Overview
SHA1 Hash: | b7a93530efef9a51b595ad940c1071d3c1ded2c8 |
---|---|
Date: | 2008-02-01 05:32:04 |
User: | aku |
Comment: | Fixed description of file checkin.c. Implemented new command test-import-manifest. Updated fossil accessor code in the importer to the changed command line API of test-import-manifest. |
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 [fe0fcda106] to [438d21c31d].
@@ -19,11 +19,11 @@ ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** -** This file contains code used to check-out versions of the project +** This file contains code used to check-in versions of the project ** from the local repository. */ #include "config.h" #include "checkin.h" #include <assert.h> @@ -559,6 +559,259 @@ autosync(0); }else{ printf("Warning: commit caused a fork to occur. Please merge and push\n"); printf(" your changes as soon as possible.\n"); } +} + +/* +** COMMAND: test-import-manifest +** +** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?... +** +** Create a new version containing containing the specified file +** revisions (if any), and child of the given PARENT version. +*/ +void import_manifest_cmd(void){ + const char* zDate; /* argument - timestamp, as seconds since epoch (int) */ + const char* zComment; /* argument - manifest comment */ + char* zDateFmt; /* timestamp formatted for the manifest */ + int* zParents; /* arguments - array of parent references */ + int zParentCount; /* number of found parent references */ + Blob manifest; /* container for the manifest to be generated */ + Blob mcksum; /* Self-checksum on the manifest */ + Blob cksum, cksum2; /* Before and after commit checksums */ + Blob cksum1b; /* Checksum recorded in the manifest */ + const char* parent; /* loop variable when collecting parent references */ + int i, mid; /* Another loop index, and id of new manifest */ + Stmt q; /* sql statement to query table of files */ + +#define USAGE ("DATE COMMENT ?-p|-parent PARENT_RID...? ?-f|-file (FILE_RID PATH)...?") + + /* + ** Validate and process arguments, collect information. + */ + + db_must_be_within_tree(); + + /* Mandatory arguments */ + if (g.argc < 4) { + usage (USAGE); + } + + zDate = g.argv[2]; + zComment = g.argv[3]; + + remove_from_argv (2,2); + + /* Pull the optional parent arguments + ** + ** Note: In principle it is possible that the loop below extracts + ** the wrong arguments, if we ever try to import a file whose path + ** starts with -p/-parent. In that case however the removal of two + ** arguments will leave the file bereft of an argument and the + ** recheck of the number of arguments below should catch that. + ** + ** For a test command this is acceptable, it won't have lots of + ** safety nets. + */ + + zParentCount = 0; + zParents = (int*)malloc(sizeof(int)*(1+g.argc)); + /* 1+, to be ok with the default even if no arguments around */ + + while ((parent = find_option("parent","p",1)) != NULL) { + /* Check and store ... */ + zParents [zParentCount] = name_to_rid (parent); + zParentCount ++; + } + + /* + ** Fall back to the root manifest as parent if none were specified + ** explicitly. + */ + + if (!zParentCount) { + zParents [zParentCount] = 1; /* HACK: rid 1 is the baseline manifest + ** which was entered when the repository + ** was created via 'new'. It always has + ** rid 1. + */ + zParentCount ++; + } + + /* Pull the file arguments, at least one has to be present. They are + ** the only things we can have here, now, and they are triples of + ** '-f FID PATH', so use of find_option is out, and we can check the + ** number of arguments. + ** + ** Note: We store the data in a temp. table, so that we later can + ** pull it sorted, and also easily get the associated hash + ** identifiers. + ** + ** Note 2: We expect at least one file, otherwise the manifest won't + ** be recognized as a baseline by the manifest parser. + */ + + if (((g.argc-2) % 3 != 0) || (g.argc < 5)) { + usage (USAGE); + } + + db_begin_transaction(); + db_multi_exec ("CREATE TEMP TABLE __im (" + "rid INTEGER PRIMARY KEY," + "pathname TEXT NOT NULL)" ); + + while (g.argc > 2) { + /* Check and store ... */ + if (strcmp("-f", g.argv[2]) && + strcmp("-file",g.argv[2])) { + usage (USAGE); + } + + /* DANGER The %s for the path might lead itself to an injection + ** attack. For now (i.e. testing) this is ok, but do something + ** better in the future. + */ + + db_multi_exec("INSERT INTO __im VALUES(%d,'%s')", + name_to_rid (g.argv[3]), g.argv[4] ); + remove_from_argv (2,3); + } + + verify_all_options(); + + /* + ** Determine the user the manifest will belong to, and check that + ** this user exists. + */ + + user_select(); + if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ + fossil_fatal("no such user: %s", g.zLogin); + } + + /* + ** Now generate the manifest in memory. + ** + ** Start with comment and date. The latter is converted to the + ** proper format before insertion. + */ + + blob_zero(&manifest); + + if (!strlen(zComment)) { + blob_appendf(&manifest, "C %F\n", "(no comment)"); + } else { + blob_appendf(&manifest, "C %F\n", blob_str(&comment)); + } + + zDateFmt = db_text(0, "SELECT datetime(%Q,'unixepoch')",zDate); + zDateFmt[10] = 'T'; + blob_appendf(&manifest, "D %s\n", zDateFmt); + free(zDateFmt); + + /* + ** Follow with all the collected files, properly sorted. Here were + ** also compute the checksum over the files (paths, sizes, + ** contents), similar to what 'vfile_aggregate_checksum_repository' + ** does. + */ + + md5sum_init(); + db_prepare(&q, + "SELECT pathname, uuid, __im.rid" + " FROM __im JOIN blob ON __im.rid=blob.rid" + " ORDER BY 1"); + + while( db_step(&q)==SQLITE_ROW ){ + char zBuf[100]; + Blob file; + const char *zName = db_column_text(&q, 0); + const char *zUuid = db_column_text(&q, 1); + int zRid = db_column_int (&q, 2); + + /* Extend the manifest */ + blob_appendf(&manifest, "F %F %s\n", zName, zUuid); + + /* Update the checksum */ + md5sum_step_text(zName, -1); + blob_zero(&file); + content_get(zRid, &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 (&cksum); + + /* + ** Follow with all the specified parents. We know that there is at + ** least one. + */ + + blob_appendf(&manifest, "P"); + for (i=0;i<zParentCount;i++) { + char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents [i]); + blob_appendf(&manifest, " %s", zUuid); + free(zUuid); + } + blob_appendf(&manifest, "\n"); + + /* + ** Complete the manifest with user name and the various checksums + */ + + blob_appendf(&manifest, "R %b\n", &cksum); + blob_appendf(&manifest, "U %F\n", g.zLogin); + md5sum_blob(&manifest, &mcksum); + blob_appendf(&manifest, "Z %b\n", &mcksum); + + /* + ** Now insert the new manifest, try to compress it relative to first + ** parent (primary). + */ + + /*blob_write_to_file (&manifest, "TEST_MANIFEST");*/ + + mid = content_put(&manifest, 0, 0); + if( mid==0 ){ + fossil_panic("trouble committing manifest: %s", g.zErrMsg); + } + + content_deltify(zParents[0], mid, 0); + + /* 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_manifest(mid, &cksum2, &cksum1b); + if( blob_compare(&cksum, &cksum1b) ){ + fossil_panic("manifest checksum does not agree with manifest: " + "%b versus %b", &cksum, &cksum1b); + } + if( blob_compare(&cksum, &cksum2) ){ + fossil_panic("tree checksum does not match manifest after commit: " + "%b versus %b", &cksum, &cksum2); + } + + /* + ** At last commit all changes, after getting rid of the temp + ** holder for the files, and release allocated memory. + */ + + db_multi_exec("DROP TABLE __im"); + db_end_transaction(0); + free(zParents); + + /* + ** At the very last inform the caller about the id of the new + ** manifest. + */ + + printf("inserted as record %d\n", mid); + return; + +#undef USAGE }
Modified tools/cvs2fossil/lib/c2f_fossil.tcl from [7fa49e081f] to [31a0efbd8f].
@@ -106,15 +106,14 @@ log write 2 fossil {== $user @ [clock format $date]} log write 2 fossil {-> $parent} log write 2 fossil {%% [join [split $message \n] "\n%% "]} lappend cmd Do test-import-manifest $date $message - if {$parent ne ""} { lappend cmd --parents $parent } - lappend cmd --files + if {$parent ne ""} { lappend cmd -p $parent } foreach {frid fpath flabel} $revisions { - lappend cmd $frid $fpath - log write 2 fossil {** <[format %5d $frid]> = $flabel} + lappend cmd -f $frid $fpath + log write 2 fossil {** <[format %5d $frid]> = <$flabel>} } # run fossil test-command performing the import. # set uuid [eval $cmd] set uuid $label ; # FAKE an uuid for the moment