Overview
SHA1 Hash: | 22552fb803cfa78054677bef53d250e532e00832 |
---|---|
Date: | 2007-08-03 15:31:33 |
User: | dan |
Comment: | Extend the commit command so that specific files can be committed. There are still some problems with doing this after a merge. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/checkin.c from [e13578a174] to [a1a87577e4].
@@ -35,12 +35,14 @@ ** We assume that vfile_check_signature has been run. */ static void status_report(Blob *report, const char *zPrefix){ Stmt q; int nPrefix = strlen(zPrefix); - db_prepare(&q, "SELECT pathname, deleted, chnged, rid FROM vfile" - " WHERE chnged OR deleted OR rid=0 ORDER BY 1"); + db_prepare(&q, + "SELECT pathname, deleted, chnged, rid FROM vfile " + "WHERE file_is_selected(id) AND (chnged OR deleted OR rid=0) ORDER BY 1" + ); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); int isDeleted = db_column_int(&q, 1); int isChnged = db_column_int(&q,2); int isNew = db_column_int(&q,3)==0; @@ -211,14 +213,55 @@ while( i>0 && isspace(zComment[i-1]) ){ i--; } blob_resize(pComment, i); } /* +** Populate the Global.aCommitFile[] based on the command line arguments +** to a [commit] command. Global.aCommitFile is an array of integers +** sized at (N+1), where N is the number of arguments passed to [commit]. +** The contents are the [id] values from the vfile table corresponding +** to the filenames passed as arguments. +** +** The last element of aCommitFile[] is always 0 - indicating the end +** of the array. +** +** If there were no arguments passed to [commit], aCommitFile is not +** allocated and remains NULL. Other parts of the code interpret this +** to mean "all files". +*/ +void select_commit_files(void){ + if( g.argc>2 ){ + int ii; + Blob b; + memset(&b, 0, sizeof(Blob)); + g.aCommitFile = malloc(sizeof(int)*(g.argc-1)); + + for(ii=2; ii<g.argc; ii++){ + int iId; + if( !file_tree_name(g.argv[ii], &b) ){ + fossil_fatal("file is not in tree: %s", g.argv[ii]); + } + iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b)); + if( iId<0 ){ + fossil_fatal("fossil knows nothing about: %s", g.argv[ii]); + } + g.aCommitFile[ii-2] = iId; + } + g.aCommitFile[ii-2] = 0; + } +} + +/* ** COMMAND: commit ** ** Create a new version containing all of the changes in the current -** checkout. +** checkout. A commit is a three step process: +** +** 1) Add the new content to the blob table, +** 2) Create and add the new manifest to the blob table, +** 3) Update the vfile table, +** 4) Run checks to make sure everything is still internally consistent. */ void commit_cmd(void){ int rc; int vid, nrid, nvid; Blob comment; @@ -230,25 +273,58 @@ Blob mcksum; /* Self-checksum on the manifest */ Blob cksum1, cksum2; /* Before and after commit checksums */ Blob cksum1b; /* Checksum recorded in the manifest */ db_must_be_within_tree(); + + /* There are two ways this command may be executed. If there are + ** no arguments following the word "commit", then all modified files + ** in the checked out directory are committed. If one or more arguments + ** follows "commit", then only those files are committed. + ** + ** After the following function call has returned, the Global.aCommitFile[] + ** array is allocated to contain the "id" field from the vfile table + ** for each file to be committed. Or, if aCommitFile is NULL, all files + ** should be committed. + */ + select_commit_files(); + user_select(); db_begin_transaction(); rc = unsaved_changes(); if( rc==0 ){ fossil_panic("nothing has changed"); } + + /* If one or more files that were named on the command line have not + ** been modified, bail out now. + */ + if( g.aCommitFile ){ + Blob unmodified; + memset(&unmodified, 0, sizeof(Blob)); + blob_init(&unmodified, 0, 0); + db_blob(&unmodified, + "SELECT pathname FROM vfile WHERE chnged = 0 AND file_is_selected(id)" + ); + if( strlen(blob_str(&unmodified)) ){ + fossil_panic("file %s has not changed", blob_str(&unmodified)); + } + } + vid = db_lget_int("checkout", 0); vfile_aggregate_checksum_disk(vid, &cksum1); prepare_commit_comment(&comment); + /* Step 1: Insert records for all modified files into the blob + ** table. If there were arguments passed to this command, only + ** the identified fils are inserted (if they have been modified). + */ db_prepare(&q, - "SELECT id, %Q || pathname, mrid FROM vfile" - " WHERE chnged==1 AND NOT deleted", g.zLocalRoot - ); - db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id"); + "SELECT id, %Q || pathname, mrid FROM vfile " + "WHERE chnged==1 AND NOT deleted AND file_is_selected(id)" + , g.zLocalRoot + ); while( db_step(&q)==SQLITE_ROW ){ int id, rid; const char *zFullname; Blob content; @@ -282,10 +358,12 @@ blob_appendf(&manifest, "F %F %s\n", zName, zUuid); } db_finalize(&q); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); blob_appendf(&manifest, "P %s", zUuid); + + db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id"); db_bind_int(&q2, ":id", 0); while( db_step(&q2)==SQLITE_ROW ){ int mid = db_column_int(&q2, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid); if( zUuid ){ @@ -292,10 +370,11 @@ blob_appendf(&manifest, " %s", zUuid); free(zUuid); } } db_reset(&q2); + blob_appendf(&manifest, "\n"); blob_appendf(&manifest, "R %b\n", &cksum1); blob_appendf(&manifest, "U %F\n", g.zLogin); md5sum_blob(&manifest, &mcksum); blob_appendf(&manifest, "Z %b\n", &mcksum); @@ -320,33 +399,44 @@ manifest_crosslink(nvid, &manifest); content_deltify(vid, nvid, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); printf("New_Version: %s\n", zUuid); - /* Update VFILE */ - db_multi_exec("DELETE FROM vfile WHERE vid!=%d OR deleted", vid); - db_multi_exec("DELETE FROM vmerge"); - db_multi_exec("UPDATE vfile SET vid=%d, rid=mrid, chnged=0, deleted=0", nvid); + /* Update the vfile and vmerge tables */ + db_multi_exec( + "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND file_is_selected(id);" + "DELETE FROM vmerge WHERE file_is_selected(id) OR id=0;" + "UPDATE vfile SET vid=%d;" + "UPDATE vfile SET rid=mrid, chnged=0, deleted=0 WHERE file_is_selected(id);" + , vid, nvid + ); db_lset_int("checkout", nvid); - /* Verify that the tree checksum is unchanged */ + /* Verify that the repository checksum matches the expected checksum + ** calculated before the checkin started (and stored as the R record + ** of the manifest file). + */ vfile_aggregate_checksum_repository(nvid, &cksum2); if( blob_compare(&cksum1, &cksum2) ){ fossil_panic("tree checksum does not match repository after commit"); } + + /* Verify that the manifest checksum matches the expected checksum */ vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b); if( blob_compare(&cksum1, &cksum1b) ){ fossil_panic("manifest checksum does not agree with manifest: " "%b versus %b", &cksum1, &cksum1b); } if( blob_compare(&cksum1, &cksum2) ){ fossil_panic("tree checksum does not match manifest after commit: " "%b versus %b", &cksum1, &cksum2); } + + /* Verify that the commit did not modify any disk images. */ vfile_aggregate_checksum_disk(nvid, &cksum2); if( blob_compare(&cksum1, &cksum2) ){ fossil_panic("tree checksums before and after commit do not match"); } /* Commit */ db_end_transaction(0); }
Modified src/db.c from [904ab46ad3] to [acf733f759].
@@ -724,17 +724,51 @@ static void db_sql_trace(void *notUsed, const char *zSql){ printf("%s\n", zSql); } /* +** This is used by the [commit] command. +** +** Return true if either: +** +** a) Global.aCommitFile is NULL, or +** b) Global.aCommitFile contains the integer passed as an argument. +** +** Otherwise return false. +*/ +static void file_is_selected( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + assert(argc==1); + if( g.aCommitFile ){ + int iId = sqlite3_value_int(argv[0]); + int ii; + for(ii=0; g.aCommitFile[ii]; ii++){ + if( iId==g.aCommitFile[ii] ){ + sqlite3_result_int(context, 1); + return; + } + } + sqlite3_result_int(context, 0); + }else{ + sqlite3_result_int(context, 1); + } +} + +/* ** This function registers auxiliary functions when the SQLite ** database connection is first established. */ LOCAL void db_connection_init(void){ static int once = 1; if( once ){ sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0); + sqlite3_create_function( + g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0 + ); if( g.fSqlTrace ){ sqlite3_trace(g.db, db_sql_trace, 0); } once = 0; }
Modified src/main.c from [e3d8b5d0b9] to [efc0bca8ad].
@@ -64,10 +64,12 @@ const char *zContentType; /* The content type of the input HTTP request */ int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ Blob cgiIn; /* Input to an xfer www method */ int cgiPanic; /* Write error messages to CGI */ + + int *aCommitFile; int urlIsFile; /* True if a "file:" url */ char *urlName; /* Hostname for http: or filename for file: */ int urlPort; /* TCP port number for http: */ char *urlPath; /* Pathname for http: */
Modified src/vfile.c from [8f052c3289] to [520337f87b].
@@ -253,43 +253,66 @@ /* ** Compute an aggregate MD5 checksum over the disk image of every ** file in vid. The file names are part of the checksum. ** +** This function operates differently if the Global.aCommitFile +** variable is not NULL. In that case, the disk image is used for +** each file in aCommitFile[] and the repository image (see +** vfile_aggregate_checksum_repository() is used for all others). +** ** Return the resulting checksum in blob pOut. */ void vfile_aggregate_checksum_disk(int vid, Blob *pOut){ FILE *in; Stmt q; char zBuf[4096]; db_must_be_within_tree(); - db_prepare(&q, "SELECT %Q || pathname, pathname FROM vfile" - " WHERE NOT deleted AND vid=%d" - " ORDER BY pathname", - g.zLocalRoot, vid); + db_prepare(&q, + "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile" + " WHERE NOT deleted AND vid=%d" + " ORDER BY pathname", + g.zLocalRoot, vid + ); md5sum_init(); while( db_step(&q)==SQLITE_ROW ){ const char *zFullpath = db_column_text(&q, 0); const char *zName = db_column_text(&q, 1); + int isSelected = db_column_int(&q, 2); + md5sum_step_text(zName, -1); - in = fopen(zFullpath,"rb"); - if( in==0 ){ - md5sum_step_text(" 0\n", -1); - continue; - } - fseek(in, 0L, SEEK_END); - sprintf(zBuf, " %ld\n", ftell(in)); - fseek(in, 0L, SEEK_SET); - md5sum_step_text(zBuf, -1); - for(;;){ - int n; - n = fread(zBuf, 1, sizeof(zBuf), in); - if( n<=0 ) break; - md5sum_step_text(zBuf, n); - } - fclose(in); + + if( isSelected ){ + in = fopen(zFullpath,"rb"); + if( in==0 ){ + md5sum_step_text(" 0\n", -1); + continue; + } + fseek(in, 0L, SEEK_END); + sprintf(zBuf, " %ld\n", ftell(in)); + fseek(in, 0L, SEEK_SET); + md5sum_step_text(zBuf, -1); + for(;;){ + int n; + n = fread(zBuf, 1, sizeof(zBuf), in); + if( n<=0 ) break; + md5sum_step_text(zBuf, n); + } + fclose(in); + }else{ + int rid = db_column_int(&q, 3); + char zBuf[100]; + Blob file; + + blob_zero(&file); + content_get(rid, &file); + sprintf(zBuf, " %d\n", blob_size(&file)); + md5sum_step_text(zBuf, -1); + md5sum_step_blob(&file); + blob_reset(&file); + } } db_finalize(&q); md5sum_finish(pOut); }