Fossil SCM

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.

aku 2008-02-01 05:32 trunk
Commit b7a93530efef9a51b595ad940c1071d3c1ded2c8
+254 -1
--- src/checkin.c
+++ src/checkin.c
@@ -19,11 +19,11 @@
1919
** [email protected]
2020
** http://www.hwaci.com/drh/
2121
**
2222
*******************************************************************************
2323
**
24
-** This file contains code used to check-out versions of the project
24
+** This file contains code used to check-in versions of the project
2525
** from the local repository.
2626
*/
2727
#include "config.h"
2828
#include "checkin.h"
2929
#include <assert.h>
@@ -560,5 +560,258 @@
560560
}else{
561561
printf("Warning: commit caused a fork to occur. Please merge and push\n");
562562
printf(" your changes as soon as possible.\n");
563563
}
564564
}
565
+
566
+/*
567
+** COMMAND: test-import-manifest
568
+**
569
+** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?...
570
+**
571
+** Create a new version containing containing the specified file
572
+** revisions (if any), and child of the given PARENT version.
573
+*/
574
+void import_manifest_cmd(void){
575
+ const char* zDate; /* argument - timestamp, as seconds since epoch (int) */
576
+ const char* zComment; /* argument - manifest comment */
577
+ char* zDateFmt; /* timestamp formatted for the manifest */
578
+ int* zParents; /* arguments - array of parent references */
579
+ int zParentCount; /* number of found parent references */
580
+ Blob manifest; /* container for the manifest to be generated */
581
+ Blob mcksum; /* Self-checksum on the manifest */
582
+ Blob cksum, cksum2; /* Before and after commit checksums */
583
+ Blob cksum1b; /* Checksum recorded in the manifest */
584
+ const char* parent; /* loop variable when collecting parent references */
585
+ int i, mid; /* Another loop index, and id of new manifest */
586
+ Stmt q; /* sql statement to query table of files */
587
+
588
+#define USAGE ("DATE COMMENT ?-p|-parent PARENT_RID...? ?-f|-file (FILE_RID PATH)...?")
589
+
590
+ /*
591
+ ** Validate and process arguments, collect information.
592
+ */
593
+
594
+ db_must_be_within_tree();
595
+
596
+ /* Mandatory arguments */
597
+ if (g.argc < 4) {
598
+ usage (USAGE);
599
+ }
600
+
601
+ zDate = g.argv[2];
602
+ zComment = g.argv[3];
603
+
604
+ remove_from_argv (2,2);
605
+
606
+ /* Pull the optional parent arguments
607
+ **
608
+ ** Note: In principle it is possible that the loop below extracts
609
+ ** the wrong arguments, if we ever try to import a file whose path
610
+ ** starts with -p/-parent. In that case however the removal of two
611
+ ** arguments will leave the file bereft of an argument and the
612
+ ** recheck of the number of arguments below should catch that.
613
+ **
614
+ ** For a test command this is acceptable, it won't have lots of
615
+ ** safety nets.
616
+ */
617
+
618
+ zParentCount = 0;
619
+ zParents = (int*)malloc(sizeof(int)*(1+g.argc));
620
+ /* 1+, to be ok with the default even if no arguments around */
621
+
622
+ while ((parent = find_option("parent","p",1)) != NULL) {
623
+ /* Check and store ... */
624
+ zParents [zParentCount] = name_to_rid (parent);
625
+ zParentCount ++;
626
+ }
627
+
628
+ /*
629
+ ** Fall back to the root manifest as parent if none were specified
630
+ ** explicitly.
631
+ */
632
+
633
+ if (!zParentCount) {
634
+ zParents [zParentCount] = 1; /* HACK: rid 1 is the baseline manifest
635
+ ** which was entered when the repository
636
+ ** was created via 'new'. It always has
637
+ ** rid 1.
638
+ */
639
+ zParentCount ++;
640
+ }
641
+
642
+ /* Pull the file arguments, at least one has to be present. They are
643
+ ** the only things we can have here, now, and they are triples of
644
+ ** '-f FID PATH', so use of find_option is out, and we can check the
645
+ ** number of arguments.
646
+ **
647
+ ** Note: We store the data in a temp. table, so that we later can
648
+ ** pull it sorted, and also easily get the associated hash
649
+ ** identifiers.
650
+ **
651
+ ** Note 2: We expect at least one file, otherwise the manifest won't
652
+ ** be recognized as a baseline by the manifest parser.
653
+ */
654
+
655
+ if (((g.argc-2) % 3 != 0) || (g.argc < 5)) {
656
+ usage (USAGE);
657
+ }
658
+
659
+ db_begin_transaction();
660
+ db_multi_exec ("CREATE TEMP TABLE __im ("
661
+ "rid INTEGER PRIMARY KEY,"
662
+ "pathname TEXT NOT NULL)" );
663
+
664
+ while (g.argc > 2) {
665
+ /* Check and store ... */
666
+ if (strcmp("-f", g.argv[2]) &&
667
+ strcmp("-file",g.argv[2])) {
668
+ usage (USAGE);
669
+ }
670
+
671
+ /* DANGER The %s for the path might lead itself to an injection
672
+ ** attack. For now (i.e. testing) this is ok, but do something
673
+ ** better in the future.
674
+ */
675
+
676
+ db_multi_exec("INSERT INTO __im VALUES(%d,'%s')",
677
+ name_to_rid (g.argv[3]), g.argv[4] );
678
+ remove_from_argv (2,3);
679
+ }
680
+
681
+ verify_all_options();
682
+
683
+ /*
684
+ ** Determine the user the manifest will belong to, and check that
685
+ ** this user exists.
686
+ */
687
+
688
+ user_select();
689
+ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
690
+ fossil_fatal("no such user: %s", g.zLogin);
691
+ }
692
+
693
+ /*
694
+ ** Now generate the manifest in memory.
695
+ **
696
+ ** Start with comment and date. The latter is converted to the
697
+ ** proper format before insertion.
698
+ */
699
+
700
+ blob_zero(&manifest);
701
+
702
+ if (!strlen(zComment)) {
703
+ blob_appendf(&manifest, "C %F\n", "(no comment)");
704
+ } else {
705
+ blob_appendf(&manifest, "C %F\n", blob_str(&comment));
706
+ }
707
+
708
+ zDateFmt = db_text(0, "SELECT datetime(%Q,'unixepoch')",zDate);
709
+ zDateFmt[10] = 'T';
710
+ blob_appendf(&manifest, "D %s\n", zDateFmt);
711
+ free(zDateFmt);
712
+
713
+ /*
714
+ ** Follow with all the collected files, properly sorted. Here were
715
+ ** also compute the checksum over the files (paths, sizes,
716
+ ** contents), similar to what 'vfile_aggregate_checksum_repository'
717
+ ** does.
718
+ */
719
+
720
+ md5sum_init();
721
+ db_prepare(&q,
722
+ "SELECT pathname, uuid, __im.rid"
723
+ " FROM __im JOIN blob ON __im.rid=blob.rid"
724
+ " ORDER BY 1");
725
+
726
+ while( db_step(&q)==SQLITE_ROW ){
727
+ char zBuf[100];
728
+ Blob file;
729
+ const char *zName = db_column_text(&q, 0);
730
+ const char *zUuid = db_column_text(&q, 1);
731
+ int zRid = db_column_int (&q, 2);
732
+
733
+ /* Extend the manifest */
734
+ blob_appendf(&manifest, "F %F %s\n", zName, zUuid);
735
+
736
+ /* Update the checksum */
737
+ md5sum_step_text(zName, -1);
738
+ blob_zero(&file);
739
+ content_get(zRid, &file);
740
+ sprintf(zBuf, " %d\n", blob_size(&file));
741
+ md5sum_step_text(zBuf, -1);
742
+ md5sum_step_blob(&file);
743
+ blob_reset(&file);
744
+ }
745
+ db_finalize(&q);
746
+ md5sum_finish (&cksum);
747
+
748
+ /*
749
+ ** Follow with all the specified parents. We know that there is at
750
+ ** least one.
751
+ */
752
+
753
+ blob_appendf(&manifest, "P");
754
+ for (i=0;i<zParentCount;i++) {
755
+ char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents [i]);
756
+ blob_appendf(&manifest, " %s", zUuid);
757
+ free(zUuid);
758
+ }
759
+ blob_appendf(&manifest, "\n");
760
+
761
+ /*
762
+ ** Complete the manifest with user name and the various checksums
763
+ */
764
+
765
+ blob_appendf(&manifest, "R %b\n", &cksum);
766
+ blob_appendf(&manifest, "U %F\n", g.zLogin);
767
+ md5sum_blob(&manifest, &mcksum);
768
+ blob_appendf(&manifest, "Z %b\n", &mcksum);
769
+
770
+ /*
771
+ ** Now insert the new manifest, try to compress it relative to first
772
+ ** parent (primary).
773
+ */
774
+
775
+ /*blob_write_to_file (&manifest, "TEST_MANIFEST");*/
776
+
777
+ mid = content_put(&manifest, 0, 0);
778
+ if( mid==0 ){
779
+ fossil_panic("trouble committing manifest: %s", g.zErrMsg);
780
+ }
781
+
782
+ content_deltify(zParents[0], mid, 0);
783
+
784
+ /* Verify that the repository checksum matches the expected checksum
785
+ ** calculated before the checkin started (and stored as the R record
786
+ ** of the manifest file).
787
+ */
788
+
789
+ vfile_aggregate_checksum_manifest(mid, &cksum2, &cksum1b);
790
+ if( blob_compare(&cksum, &cksum1b) ){
791
+ fossil_panic("manifest checksum does not agree with manifest: "
792
+ "%b versus %b", &cksum, &cksum1b);
793
+ }
794
+ if( blob_compare(&cksum, &cksum2) ){
795
+ fossil_panic("tree checksum does not match manifest after commit: "
796
+ "%b versus %b", &cksum, &cksum2);
797
+ }
798
+
799
+ /*
800
+ ** At last commit all changes, after getting rid of the temp
801
+ ** holder for the files, and release allocated memory.
802
+ */
803
+
804
+ db_multi_exec("DROP TABLE __im");
805
+ db_end_transaction(0);
806
+ free(zParents);
807
+
808
+ /*
809
+ ** At the very last inform the caller about the id of the new
810
+ ** manifest.
811
+ */
812
+
813
+ printf("inserted as record %d\n", mid);
814
+ return;
815
+
816
+#undef USAGE
817
+}
565818
--- src/checkin.c
+++ src/checkin.c
@@ -19,11 +19,11 @@
19 ** [email protected]
20 ** http://www.hwaci.com/drh/
21 **
22 *******************************************************************************
23 **
24 ** This file contains code used to check-out versions of the project
25 ** from the local repository.
26 */
27 #include "config.h"
28 #include "checkin.h"
29 #include <assert.h>
@@ -560,5 +560,258 @@
560 }else{
561 printf("Warning: commit caused a fork to occur. Please merge and push\n");
562 printf(" your changes as soon as possible.\n");
563 }
564 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
565
--- src/checkin.c
+++ src/checkin.c
@@ -19,11 +19,11 @@
19 ** [email protected]
20 ** http://www.hwaci.com/drh/
21 **
22 *******************************************************************************
23 **
24 ** This file contains code used to check-in versions of the project
25 ** from the local repository.
26 */
27 #include "config.h"
28 #include "checkin.h"
29 #include <assert.h>
@@ -560,5 +560,258 @@
560 }else{
561 printf("Warning: commit caused a fork to occur. Please merge and push\n");
562 printf(" your changes as soon as possible.\n");
563 }
564 }
565
566 /*
567 ** COMMAND: test-import-manifest
568 **
569 ** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?...
570 **
571 ** Create a new version containing containing the specified file
572 ** revisions (if any), and child of the given PARENT version.
573 */
574 void import_manifest_cmd(void){
575 const char* zDate; /* argument - timestamp, as seconds since epoch (int) */
576 const char* zComment; /* argument - manifest comment */
577 char* zDateFmt; /* timestamp formatted for the manifest */
578 int* zParents; /* arguments - array of parent references */
579 int zParentCount; /* number of found parent references */
580 Blob manifest; /* container for the manifest to be generated */
581 Blob mcksum; /* Self-checksum on the manifest */
582 Blob cksum, cksum2; /* Before and after commit checksums */
583 Blob cksum1b; /* Checksum recorded in the manifest */
584 const char* parent; /* loop variable when collecting parent references */
585 int i, mid; /* Another loop index, and id of new manifest */
586 Stmt q; /* sql statement to query table of files */
587
588 #define USAGE ("DATE COMMENT ?-p|-parent PARENT_RID...? ?-f|-file (FILE_RID PATH)...?")
589
590 /*
591 ** Validate and process arguments, collect information.
592 */
593
594 db_must_be_within_tree();
595
596 /* Mandatory arguments */
597 if (g.argc < 4) {
598 usage (USAGE);
599 }
600
601 zDate = g.argv[2];
602 zComment = g.argv[3];
603
604 remove_from_argv (2,2);
605
606 /* Pull the optional parent arguments
607 **
608 ** Note: In principle it is possible that the loop below extracts
609 ** the wrong arguments, if we ever try to import a file whose path
610 ** starts with -p/-parent. In that case however the removal of two
611 ** arguments will leave the file bereft of an argument and the
612 ** recheck of the number of arguments below should catch that.
613 **
614 ** For a test command this is acceptable, it won't have lots of
615 ** safety nets.
616 */
617
618 zParentCount = 0;
619 zParents = (int*)malloc(sizeof(int)*(1+g.argc));
620 /* 1+, to be ok with the default even if no arguments around */
621
622 while ((parent = find_option("parent","p",1)) != NULL) {
623 /* Check and store ... */
624 zParents [zParentCount] = name_to_rid (parent);
625 zParentCount ++;
626 }
627
628 /*
629 ** Fall back to the root manifest as parent if none were specified
630 ** explicitly.
631 */
632
633 if (!zParentCount) {
634 zParents [zParentCount] = 1; /* HACK: rid 1 is the baseline manifest
635 ** which was entered when the repository
636 ** was created via 'new'. It always has
637 ** rid 1.
638 */
639 zParentCount ++;
640 }
641
642 /* Pull the file arguments, at least one has to be present. They are
643 ** the only things we can have here, now, and they are triples of
644 ** '-f FID PATH', so use of find_option is out, and we can check the
645 ** number of arguments.
646 **
647 ** Note: We store the data in a temp. table, so that we later can
648 ** pull it sorted, and also easily get the associated hash
649 ** identifiers.
650 **
651 ** Note 2: We expect at least one file, otherwise the manifest won't
652 ** be recognized as a baseline by the manifest parser.
653 */
654
655 if (((g.argc-2) % 3 != 0) || (g.argc < 5)) {
656 usage (USAGE);
657 }
658
659 db_begin_transaction();
660 db_multi_exec ("CREATE TEMP TABLE __im ("
661 "rid INTEGER PRIMARY KEY,"
662 "pathname TEXT NOT NULL)" );
663
664 while (g.argc > 2) {
665 /* Check and store ... */
666 if (strcmp("-f", g.argv[2]) &&
667 strcmp("-file",g.argv[2])) {
668 usage (USAGE);
669 }
670
671 /* DANGER The %s for the path might lead itself to an injection
672 ** attack. For now (i.e. testing) this is ok, but do something
673 ** better in the future.
674 */
675
676 db_multi_exec("INSERT INTO __im VALUES(%d,'%s')",
677 name_to_rid (g.argv[3]), g.argv[4] );
678 remove_from_argv (2,3);
679 }
680
681 verify_all_options();
682
683 /*
684 ** Determine the user the manifest will belong to, and check that
685 ** this user exists.
686 */
687
688 user_select();
689 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
690 fossil_fatal("no such user: %s", g.zLogin);
691 }
692
693 /*
694 ** Now generate the manifest in memory.
695 **
696 ** Start with comment and date. The latter is converted to the
697 ** proper format before insertion.
698 */
699
700 blob_zero(&manifest);
701
702 if (!strlen(zComment)) {
703 blob_appendf(&manifest, "C %F\n", "(no comment)");
704 } else {
705 blob_appendf(&manifest, "C %F\n", blob_str(&comment));
706 }
707
708 zDateFmt = db_text(0, "SELECT datetime(%Q,'unixepoch')",zDate);
709 zDateFmt[10] = 'T';
710 blob_appendf(&manifest, "D %s\n", zDateFmt);
711 free(zDateFmt);
712
713 /*
714 ** Follow with all the collected files, properly sorted. Here were
715 ** also compute the checksum over the files (paths, sizes,
716 ** contents), similar to what 'vfile_aggregate_checksum_repository'
717 ** does.
718 */
719
720 md5sum_init();
721 db_prepare(&q,
722 "SELECT pathname, uuid, __im.rid"
723 " FROM __im JOIN blob ON __im.rid=blob.rid"
724 " ORDER BY 1");
725
726 while( db_step(&q)==SQLITE_ROW ){
727 char zBuf[100];
728 Blob file;
729 const char *zName = db_column_text(&q, 0);
730 const char *zUuid = db_column_text(&q, 1);
731 int zRid = db_column_int (&q, 2);
732
733 /* Extend the manifest */
734 blob_appendf(&manifest, "F %F %s\n", zName, zUuid);
735
736 /* Update the checksum */
737 md5sum_step_text(zName, -1);
738 blob_zero(&file);
739 content_get(zRid, &file);
740 sprintf(zBuf, " %d\n", blob_size(&file));
741 md5sum_step_text(zBuf, -1);
742 md5sum_step_blob(&file);
743 blob_reset(&file);
744 }
745 db_finalize(&q);
746 md5sum_finish (&cksum);
747
748 /*
749 ** Follow with all the specified parents. We know that there is at
750 ** least one.
751 */
752
753 blob_appendf(&manifest, "P");
754 for (i=0;i<zParentCount;i++) {
755 char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents [i]);
756 blob_appendf(&manifest, " %s", zUuid);
757 free(zUuid);
758 }
759 blob_appendf(&manifest, "\n");
760
761 /*
762 ** Complete the manifest with user name and the various checksums
763 */
764
765 blob_appendf(&manifest, "R %b\n", &cksum);
766 blob_appendf(&manifest, "U %F\n", g.zLogin);
767 md5sum_blob(&manifest, &mcksum);
768 blob_appendf(&manifest, "Z %b\n", &mcksum);
769
770 /*
771 ** Now insert the new manifest, try to compress it relative to first
772 ** parent (primary).
773 */
774
775 /*blob_write_to_file (&manifest, "TEST_MANIFEST");*/
776
777 mid = content_put(&manifest, 0, 0);
778 if( mid==0 ){
779 fossil_panic("trouble committing manifest: %s", g.zErrMsg);
780 }
781
782 content_deltify(zParents[0], mid, 0);
783
784 /* Verify that the repository checksum matches the expected checksum
785 ** calculated before the checkin started (and stored as the R record
786 ** of the manifest file).
787 */
788
789 vfile_aggregate_checksum_manifest(mid, &cksum2, &cksum1b);
790 if( blob_compare(&cksum, &cksum1b) ){
791 fossil_panic("manifest checksum does not agree with manifest: "
792 "%b versus %b", &cksum, &cksum1b);
793 }
794 if( blob_compare(&cksum, &cksum2) ){
795 fossil_panic("tree checksum does not match manifest after commit: "
796 "%b versus %b", &cksum, &cksum2);
797 }
798
799 /*
800 ** At last commit all changes, after getting rid of the temp
801 ** holder for the files, and release allocated memory.
802 */
803
804 db_multi_exec("DROP TABLE __im");
805 db_end_transaction(0);
806 free(zParents);
807
808 /*
809 ** At the very last inform the caller about the id of the new
810 ** manifest.
811 */
812
813 printf("inserted as record %d\n", mid);
814 return;
815
816 #undef USAGE
817 }
818
--- tools/cvs2fossil/lib/c2f_fossil.tcl
+++ tools/cvs2fossil/lib/c2f_fossil.tcl
@@ -106,15 +106,14 @@
106106
log write 2 fossil {== $user @ [clock format $date]}
107107
log write 2 fossil {-> $parent}
108108
log write 2 fossil {%% [join [split $message \n] "\n%% "]}
109109
110110
lappend cmd Do test-import-manifest $date $message
111
- if {$parent ne ""} { lappend cmd --parents $parent }
112
- lappend cmd --files
111
+ if {$parent ne ""} { lappend cmd -p $parent }
113112
foreach {frid fpath flabel} $revisions {
114
- lappend cmd $frid $fpath
115
- log write 2 fossil {** <[format %5d $frid]> = $flabel}
113
+ lappend cmd -f $frid $fpath
114
+ log write 2 fossil {** <[format %5d $frid]> = <$flabel>}
116115
}
117116
118117
# run fossil test-command performing the import.
119118
# set uuid [eval $cmd]
120119
set uuid $label ; # FAKE an uuid for the moment
121120
--- tools/cvs2fossil/lib/c2f_fossil.tcl
+++ tools/cvs2fossil/lib/c2f_fossil.tcl
@@ -106,15 +106,14 @@
106 log write 2 fossil {== $user @ [clock format $date]}
107 log write 2 fossil {-> $parent}
108 log write 2 fossil {%% [join [split $message \n] "\n%% "]}
109
110 lappend cmd Do test-import-manifest $date $message
111 if {$parent ne ""} { lappend cmd --parents $parent }
112 lappend cmd --files
113 foreach {frid fpath flabel} $revisions {
114 lappend cmd $frid $fpath
115 log write 2 fossil {** <[format %5d $frid]> = $flabel}
116 }
117
118 # run fossil test-command performing the import.
119 # set uuid [eval $cmd]
120 set uuid $label ; # FAKE an uuid for the moment
121
--- tools/cvs2fossil/lib/c2f_fossil.tcl
+++ tools/cvs2fossil/lib/c2f_fossil.tcl
@@ -106,15 +106,14 @@
106 log write 2 fossil {== $user @ [clock format $date]}
107 log write 2 fossil {-> $parent}
108 log write 2 fossil {%% [join [split $message \n] "\n%% "]}
109
110 lappend cmd Do test-import-manifest $date $message
111 if {$parent ne ""} { lappend cmd -p $parent }
 
112 foreach {frid fpath flabel} $revisions {
113 lappend cmd -f $frid $fpath
114 log write 2 fossil {** <[format %5d $frid]> = <$flabel>}
115 }
116
117 # run fossil test-command performing the import.
118 # set uuid [eval $cmd]
119 set uuid $label ; # FAKE an uuid for the moment
120

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button