Fossil SCM

Add the "fossil test-missing" command. Make test-missing and test-orphans available to "fossil all".

drh 2012-10-31 14:15 trunk
Commit eb949991434d3e1a33abd8d15df867c548454ae3
2 files changed +5 +138
--- src/allrepo.c
+++ src/allrepo.c
@@ -148,10 +148,15 @@
148148
collect_argument(&extra, "stat");
149149
}else if( strncmp(zCmd, "sync", n)==0 ){
150150
zCmd = "sync -autourl -R";
151151
}else if( strncmp(zCmd, "test-integrity", n)==0 ){
152152
zCmd = "test-integrity";
153
+ }else if( strncmp(zCmd, "test-orphans", n)==0 ){
154
+ zCmd = "test-orphans -R";
155
+ }else if( strncmp(zCmd, "test-missing", n)==0 ){
156
+ zCmd = "test-missing -q -R";
157
+ collect_argument(&extra, "notshunned");
153158
}else if( strncmp(zCmd, "changes", n)==0 ){
154159
zCmd = "changes --quiet --header --chdir";
155160
useCheckouts = 1;
156161
stopOnError = 0;
157162
quiet = 1;
158163
--- src/allrepo.c
+++ src/allrepo.c
@@ -148,10 +148,15 @@
148 collect_argument(&extra, "stat");
149 }else if( strncmp(zCmd, "sync", n)==0 ){
150 zCmd = "sync -autourl -R";
151 }else if( strncmp(zCmd, "test-integrity", n)==0 ){
152 zCmd = "test-integrity";
 
 
 
 
 
153 }else if( strncmp(zCmd, "changes", n)==0 ){
154 zCmd = "changes --quiet --header --chdir";
155 useCheckouts = 1;
156 stopOnError = 0;
157 quiet = 1;
158
--- src/allrepo.c
+++ src/allrepo.c
@@ -148,10 +148,15 @@
148 collect_argument(&extra, "stat");
149 }else if( strncmp(zCmd, "sync", n)==0 ){
150 zCmd = "sync -autourl -R";
151 }else if( strncmp(zCmd, "test-integrity", n)==0 ){
152 zCmd = "test-integrity";
153 }else if( strncmp(zCmd, "test-orphans", n)==0 ){
154 zCmd = "test-orphans -R";
155 }else if( strncmp(zCmd, "test-missing", n)==0 ){
156 zCmd = "test-missing -q -R";
157 collect_argument(&extra, "notshunned");
158 }else if( strncmp(zCmd, "changes", n)==0 ){
159 zCmd = "changes --quiet --header --chdir";
160 useCheckouts = 1;
161 stopOnError = 0;
162 quiet = 1;
163
+138
--- src/content.c
+++ src/content.c
@@ -926,5 +926,143 @@
926926
cnt++;
927927
}
928928
db_finalize(&q);
929929
fossil_print("%d orphans\n", cnt);
930930
}
931
+
932
+/* Allowed flags for check_exists */
933
+#define MISSING_SHUNNED 0x0001 /* Do not report shunned artifacts */
934
+
935
+/* This is a helper routine for test-artifacts.
936
+**
937
+** Check to see that artifact zUuid exists in the repository. If it does,
938
+** return 0. If it does not, generate an error message and return 1.
939
+*/
940
+static int check_exists(
941
+ const char *zUuid, /* The artifact we are checking for */
942
+ unsigned flags, /* Flags */
943
+ Manifest *p, /* The control artifact that references zUuid */
944
+ const char *zRole, /* Role of zUuid in p */
945
+ const char *zDetail /* Additional information, such as a filename */
946
+){
947
+ static Stmt q;
948
+ int rc = 0;
949
+
950
+ db_static_prepare(&q, "SELECT size FROM blob WHERE uuid=:uuid");
951
+ if( zUuid==0 || zUuid[0]==0 ) return 0;
952
+ db_bind_text(&q, ":uuid", zUuid);
953
+ if( db_step(&q)==SQLITE_ROW ){
954
+ int size = db_column_int(&q, 0);
955
+ if( size<0 ) rc = 2;
956
+ }else{
957
+ rc = 1;
958
+ }
959
+ db_reset(&q);
960
+ if( rc ){
961
+ const char *zCFType = "control artifact";
962
+ char *zSrc;
963
+ char *zDate;
964
+ char *zErrType = "MISSING";
965
+ if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
966
+ if( flags & MISSING_SHUNNED ) return 0;
967
+ zErrType = "SHUNNED";
968
+ }
969
+ switch( p->type ){
970
+ case CFTYPE_MANIFEST: zCFType = "check-in"; break;
971
+ case CFTYPE_CLUSTER: zCFType = "cluster"; break;
972
+ case CFTYPE_CONTROL: zCFType = "tag"; break;
973
+ case CFTYPE_WIKI: zCFType = "wiki"; break;
974
+ case CFTYPE_TICKET: zCFType = "ticket"; break;
975
+ case CFTYPE_ATTACHMENT: zCFType = "attachment"; break;
976
+ case CFTYPE_EVENT: zCFType = "event"; break;
977
+ }
978
+ zSrc = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", p->rid);
979
+ if( p->rDate>0.0 ){
980
+ zDate = db_text(0, "SELECT datetime(%.17g)", p->rDate);
981
+ }else{
982
+ zDate = db_text(0,
983
+ "SELECT datetime(rcvfrom.mtime)"
984
+ " FROM blob, rcvfrom"
985
+ " WHERE blob.rcvid=rcvfrom.rcvid"
986
+ " AND blob.rid=%d", p->rid);
987
+ }
988
+ fossil_print("%s: %s\n %s %s %S (%d) %s\n",
989
+ zErrType, zUuid, zRole, zCFType, zSrc, p->rid, zDate);
990
+ if( zDetail && zDetail[0] ){
991
+ fossil_print(" %s\n", zDetail);
992
+ }
993
+ fossil_free(zSrc);
994
+ fossil_free(zDate);
995
+ rc = 1;
996
+ }
997
+ return rc;
998
+}
999
+
1000
+/*
1001
+** COMMAND: test-missing
1002
+**
1003
+** Usage: %fossil test-missing
1004
+**
1005
+** Look at every artifact in the repository and verify that
1006
+** all references are satisfied. Report any referenced artifacts
1007
+** that are missing or shunned.
1008
+**
1009
+** Options:
1010
+**
1011
+** --notshunned Do not report shunned artifacts
1012
+** --quiet Only show output if there are errors
1013
+*/
1014
+void test_missing(void){
1015
+ Stmt q;
1016
+ Blob content;
1017
+ int nErr = 0;
1018
+ int nArtifact = 0;
1019
+ int i;
1020
+ Manifest *p;
1021
+ unsigned flags = 0;
1022
+ int quietFlag;
1023
+
1024
+ if( find_option("notshunned", 0, 0)!=0 ) flags |= MISSING_SHUNNED;
1025
+ quietFlag = find_option("quiet","q",0)!=0;
1026
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1027
+ db_prepare(&q,
1028
+ "SELECT mid FROM mlink UNION "
1029
+ "SELECT srcid FROM tagxref WHERE srcid>0 UNION "
1030
+ "SELECT rid FROM tagxref UNION "
1031
+ "SELECT rid FROM attachment JOIN blob ON src=uuid UNION "
1032
+ "SELECT objid FROM event");
1033
+ while( db_step(&q)==SQLITE_ROW ){
1034
+ int rid = db_column_int(&q, 0);
1035
+ content_get(rid, &content);
1036
+ p = manifest_parse(&content, rid, 0);
1037
+ if( p ){
1038
+ nArtifact++;
1039
+ nErr += check_exists(p->zBaseline, flags, p, "baseline of", 0);
1040
+ nErr += check_exists(p->zAttachSrc, flags, p, "file of", 0);
1041
+ for(i=0; i<p->nFile; i++){
1042
+ nErr += check_exists(p->aFile[i].zUuid, flags, p, "file of",
1043
+ p->aFile[i].zName);
1044
+ }
1045
+ for(i=0; i<p->nParent; i++){
1046
+ nErr += check_exists(p->azParent[i], flags, p, "parent of", 0);
1047
+ }
1048
+ for(i=0; i<p->nCherrypick; i++){
1049
+ nErr += check_exists(p->aCherrypick[i].zCPTarget+1, flags, p,
1050
+ "cherry-pick target of", 0);
1051
+ nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p,
1052
+ "cherry-pick baseline of", 0);
1053
+ }
1054
+ for(i=0; i<p->nCChild; i++){
1055
+ nErr += check_exists(p->azCChild[i], flags, p, "in", 0);
1056
+ }
1057
+ for(i=0; i<p->nTag; i++){
1058
+ nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0);
1059
+ }
1060
+ manifest_destroy(p);
1061
+ }
1062
+ }
1063
+ db_finalize(&q);
1064
+ if( nErr>0 || quietFlag==0 ){
1065
+ fossil_print("%d missing or shunned references in %d control artifacts\n",
1066
+ nErr, nArtifact);
1067
+ }
1068
+}
9311069
--- src/content.c
+++ src/content.c
@@ -926,5 +926,143 @@
926 cnt++;
927 }
928 db_finalize(&q);
929 fossil_print("%d orphans\n", cnt);
930 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
--- src/content.c
+++ src/content.c
@@ -926,5 +926,143 @@
926 cnt++;
927 }
928 db_finalize(&q);
929 fossil_print("%d orphans\n", cnt);
930 }
931
932 /* Allowed flags for check_exists */
933 #define MISSING_SHUNNED 0x0001 /* Do not report shunned artifacts */
934
935 /* This is a helper routine for test-artifacts.
936 **
937 ** Check to see that artifact zUuid exists in the repository. If it does,
938 ** return 0. If it does not, generate an error message and return 1.
939 */
940 static int check_exists(
941 const char *zUuid, /* The artifact we are checking for */
942 unsigned flags, /* Flags */
943 Manifest *p, /* The control artifact that references zUuid */
944 const char *zRole, /* Role of zUuid in p */
945 const char *zDetail /* Additional information, such as a filename */
946 ){
947 static Stmt q;
948 int rc = 0;
949
950 db_static_prepare(&q, "SELECT size FROM blob WHERE uuid=:uuid");
951 if( zUuid==0 || zUuid[0]==0 ) return 0;
952 db_bind_text(&q, ":uuid", zUuid);
953 if( db_step(&q)==SQLITE_ROW ){
954 int size = db_column_int(&q, 0);
955 if( size<0 ) rc = 2;
956 }else{
957 rc = 1;
958 }
959 db_reset(&q);
960 if( rc ){
961 const char *zCFType = "control artifact";
962 char *zSrc;
963 char *zDate;
964 char *zErrType = "MISSING";
965 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
966 if( flags & MISSING_SHUNNED ) return 0;
967 zErrType = "SHUNNED";
968 }
969 switch( p->type ){
970 case CFTYPE_MANIFEST: zCFType = "check-in"; break;
971 case CFTYPE_CLUSTER: zCFType = "cluster"; break;
972 case CFTYPE_CONTROL: zCFType = "tag"; break;
973 case CFTYPE_WIKI: zCFType = "wiki"; break;
974 case CFTYPE_TICKET: zCFType = "ticket"; break;
975 case CFTYPE_ATTACHMENT: zCFType = "attachment"; break;
976 case CFTYPE_EVENT: zCFType = "event"; break;
977 }
978 zSrc = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", p->rid);
979 if( p->rDate>0.0 ){
980 zDate = db_text(0, "SELECT datetime(%.17g)", p->rDate);
981 }else{
982 zDate = db_text(0,
983 "SELECT datetime(rcvfrom.mtime)"
984 " FROM blob, rcvfrom"
985 " WHERE blob.rcvid=rcvfrom.rcvid"
986 " AND blob.rid=%d", p->rid);
987 }
988 fossil_print("%s: %s\n %s %s %S (%d) %s\n",
989 zErrType, zUuid, zRole, zCFType, zSrc, p->rid, zDate);
990 if( zDetail && zDetail[0] ){
991 fossil_print(" %s\n", zDetail);
992 }
993 fossil_free(zSrc);
994 fossil_free(zDate);
995 rc = 1;
996 }
997 return rc;
998 }
999
1000 /*
1001 ** COMMAND: test-missing
1002 **
1003 ** Usage: %fossil test-missing
1004 **
1005 ** Look at every artifact in the repository and verify that
1006 ** all references are satisfied. Report any referenced artifacts
1007 ** that are missing or shunned.
1008 **
1009 ** Options:
1010 **
1011 ** --notshunned Do not report shunned artifacts
1012 ** --quiet Only show output if there are errors
1013 */
1014 void test_missing(void){
1015 Stmt q;
1016 Blob content;
1017 int nErr = 0;
1018 int nArtifact = 0;
1019 int i;
1020 Manifest *p;
1021 unsigned flags = 0;
1022 int quietFlag;
1023
1024 if( find_option("notshunned", 0, 0)!=0 ) flags |= MISSING_SHUNNED;
1025 quietFlag = find_option("quiet","q",0)!=0;
1026 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1027 db_prepare(&q,
1028 "SELECT mid FROM mlink UNION "
1029 "SELECT srcid FROM tagxref WHERE srcid>0 UNION "
1030 "SELECT rid FROM tagxref UNION "
1031 "SELECT rid FROM attachment JOIN blob ON src=uuid UNION "
1032 "SELECT objid FROM event");
1033 while( db_step(&q)==SQLITE_ROW ){
1034 int rid = db_column_int(&q, 0);
1035 content_get(rid, &content);
1036 p = manifest_parse(&content, rid, 0);
1037 if( p ){
1038 nArtifact++;
1039 nErr += check_exists(p->zBaseline, flags, p, "baseline of", 0);
1040 nErr += check_exists(p->zAttachSrc, flags, p, "file of", 0);
1041 for(i=0; i<p->nFile; i++){
1042 nErr += check_exists(p->aFile[i].zUuid, flags, p, "file of",
1043 p->aFile[i].zName);
1044 }
1045 for(i=0; i<p->nParent; i++){
1046 nErr += check_exists(p->azParent[i], flags, p, "parent of", 0);
1047 }
1048 for(i=0; i<p->nCherrypick; i++){
1049 nErr += check_exists(p->aCherrypick[i].zCPTarget+1, flags, p,
1050 "cherry-pick target of", 0);
1051 nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p,
1052 "cherry-pick baseline of", 0);
1053 }
1054 for(i=0; i<p->nCChild; i++){
1055 nErr += check_exists(p->azCChild[i], flags, p, "in", 0);
1056 }
1057 for(i=0; i<p->nTag; i++){
1058 nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0);
1059 }
1060 manifest_destroy(p);
1061 }
1062 }
1063 db_finalize(&q);
1064 if( nErr>0 || quietFlag==0 ){
1065 fossil_print("%d missing or shunned references in %d control artifacts\n",
1066 nErr, nArtifact);
1067 }
1068 }
1069

Keyboard Shortcuts

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