Fossil SCM
Do not use the --input-marks option with "git fast-import". Instead, remember older Git-names and insert them directly into the fast-import stream.
Commit
8e6f3ced08278afbd646a74e91eaea3ff37695eb588c22b64dbe00662da9edcf
Parent
d1b88ad570162e0…
1 file changed
+46
-41
+46
-41
| --- src/export.c | ||
| +++ src/export.c | ||
| @@ -936,37 +936,42 @@ | ||
| 936 | 936 | zOut[j] = 0; |
| 937 | 937 | return zOut; |
| 938 | 938 | } |
| 939 | 939 | |
| 940 | 940 | /* |
| 941 | -** Locate the mark for a UUID. | |
| 941 | +** Find the Git-name corresponding to the Fossil-name zUuid. | |
| 942 | 942 | ** |
| 943 | 943 | ** If the mark does not exist and if the bCreate flag is false, then |
| 944 | -** return 0. If the mark does not exist and the bCreate flag is true, | |
| 944 | +** return NULL. If the mark does not exist and the bCreate flag is true, | |
| 945 | 945 | ** then create the mark. |
| 946 | +** | |
| 947 | +** The string returned is obtained from fossil_malloc() and should | |
| 948 | +** be freed by the caller. | |
| 946 | 949 | */ |
| 947 | -static int gitmirror_find_mark(const char *zUuid, int bCreate){ | |
| 948 | - int iMark; | |
| 950 | +static char *gitmirror_find_mark(const char *zUuid, int bCreate){ | |
| 949 | 951 | static Stmt sFind, sIns; |
| 950 | 952 | db_static_prepare(&sFind, |
| 951 | - "SELECT id FROM mirror.mmark WHERE uuid=:uuid" | |
| 953 | + "SELECT coalesce(githash,printf(':%%d',id))" | |
| 954 | + " FROM mirror.mmark WHERE uuid=:uuid" | |
| 952 | 955 | ); |
| 953 | 956 | db_bind_text(&sFind, ":uuid", zUuid); |
| 954 | 957 | if( db_step(&sFind)==SQLITE_ROW ){ |
| 955 | - iMark = db_column_int(&sFind, 0); | |
| 958 | + char *zMark = fossil_strdup(db_column_text(&sFind, 0)); | |
| 956 | 959 | db_reset(&sFind); |
| 957 | - return iMark; | |
| 960 | + return zMark; | |
| 958 | 961 | } |
| 959 | 962 | db_reset(&sFind); |
| 960 | - if( !bCreate ) return 0; | |
| 963 | + if( !bCreate ){ | |
| 964 | + return 0; | |
| 965 | + } | |
| 961 | 966 | db_static_prepare(&sIns, |
| 962 | 967 | "INSERT INTO mirror.mmark(uuid) VALUES(:uuid)" |
| 963 | 968 | ); |
| 964 | 969 | db_bind_text(&sIns, ":uuid", zUuid); |
| 965 | 970 | db_step(&sIns); |
| 966 | 971 | db_reset(&sIns); |
| 967 | - return db_last_insert_rowid(); | |
| 972 | + return mprintf(":%d", db_last_insert_rowid()); | |
| 968 | 973 | } |
| 969 | 974 | |
| 970 | 975 | /* This is the SHA3-256 hash of an empty file */ |
| 971 | 976 | static const char zEmptySha3[] = |
| 972 | 977 | "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; |
| @@ -980,11 +985,11 @@ | ||
| 980 | 985 | ** But files that are missing from the repository but have not been officially |
| 981 | 986 | ** shunned cause an error return. Except, if bPhantomOk is true, then missing |
| 982 | 987 | ** files are replaced by an empty file. |
| 983 | 988 | */ |
| 984 | 989 | static int gitmirror_send_file(FILE *xCmd, const char *zUuid, int bPhantomOk){ |
| 985 | - int iMark; | |
| 990 | + char *zMark; | |
| 986 | 991 | int rid; |
| 987 | 992 | int rc; |
| 988 | 993 | Blob data; |
| 989 | 994 | rid = fast_uuid_to_rid(zUuid); |
| 990 | 995 | if( rid<0 ){ |
| @@ -1004,14 +1009,17 @@ | ||
| 1004 | 1009 | }else{ |
| 1005 | 1010 | return 1; |
| 1006 | 1011 | } |
| 1007 | 1012 | } |
| 1008 | 1013 | } |
| 1009 | - iMark = gitmirror_find_mark(zUuid, 1); | |
| 1010 | - fprintf(xCmd, "blob\nmark :%d\ndata %d\n", iMark, blob_size(&data)); | |
| 1011 | - fwrite(blob_buffer(&data), 1, blob_size(&data), xCmd); | |
| 1012 | - fprintf(xCmd, "\n"); | |
| 1014 | + zMark = gitmirror_find_mark(zUuid, 1); | |
| 1015 | + if( zMark[0]==':' ){ | |
| 1016 | + fprintf(xCmd, "blob\nmark %s\ndata %d\n", zMark, blob_size(&data)); | |
| 1017 | + fwrite(blob_buffer(&data), 1, blob_size(&data), xCmd); | |
| 1018 | + fprintf(xCmd, "\n"); | |
| 1019 | + } | |
| 1020 | + fossil_free(zMark); | |
| 1013 | 1021 | blob_reset(&data); |
| 1014 | 1022 | return 0; |
| 1015 | 1023 | } |
| 1016 | 1024 | |
| 1017 | 1025 | /* |
| @@ -1039,11 +1047,11 @@ | ||
| 1039 | 1047 | Manifest *pMan; /* The check-in to be output */ |
| 1040 | 1048 | int i; /* Loop counter */ |
| 1041 | 1049 | int iParent; /* Which immediate ancestor is primary. -1 for none */ |
| 1042 | 1050 | Stmt q; /* An SQL query */ |
| 1043 | 1051 | char *zBranch; /* The branch of the check-in */ |
| 1044 | - int iMark; /* The mark for the check-in */ | |
| 1052 | + char *zMark; /* The Git-name of the check-in */ | |
| 1045 | 1053 | Blob sql; /* String of SQL for part of the query */ |
| 1046 | 1054 | Blob comment; /* The comment text for the check-in */ |
| 1047 | 1055 | int nErr = 0; /* Number of errors */ |
| 1048 | 1056 | int bPhantomOk; /* True if phantom files should be ignored */ |
| 1049 | 1057 | |
| @@ -1056,21 +1064,22 @@ | ||
| 1056 | 1064 | } |
| 1057 | 1065 | |
| 1058 | 1066 | /* Check to see if any parent logins have not yet been processed, and |
| 1059 | 1067 | ** if so, create them */ |
| 1060 | 1068 | for(i=0; i<pMan->nParent; i++){ |
| 1061 | - int iMark = gitmirror_find_mark(pMan->azParent[i], 0); | |
| 1062 | - if( iMark<=0 ){ | |
| 1069 | + char *zPMark = gitmirror_find_mark(pMan->azParent[i], 0); | |
| 1070 | + if( zPMark==0 ){ | |
| 1063 | 1071 | int prid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", |
| 1064 | 1072 | pMan->azParent[i]); |
| 1065 | 1073 | int rc = gitmirror_send_checkin(xCmd, prid, pMan->azParent[i], |
| 1066 | 1074 | pnLimit, fManifest); |
| 1067 | 1075 | if( rc || *pnLimit<=0 ){ |
| 1068 | 1076 | manifest_destroy(pMan); |
| 1069 | 1077 | return 1; |
| 1070 | 1078 | } |
| 1071 | 1079 | } |
| 1080 | + fossil_free(zPMark); | |
| 1072 | 1081 | } |
| 1073 | 1082 | |
| 1074 | 1083 | /* Ignore phantom files on check-ins that are over one year old */ |
| 1075 | 1084 | bPhantomOk = db_int(0, "SELECT %.6f<julianday('now','-1 year')", |
| 1076 | 1085 | pMan->rDate); |
| @@ -1113,12 +1122,13 @@ | ||
| 1113 | 1122 | } |
| 1114 | 1123 | |
| 1115 | 1124 | /* Export the check-in */ |
| 1116 | 1125 | fprintf(xCmd, "commit refs/heads/%s\n", zBranch); |
| 1117 | 1126 | fossil_free(zBranch); |
| 1118 | - iMark = gitmirror_find_mark(zUuid, 1); | |
| 1119 | - fprintf(xCmd, "mark :%d\n", iMark); | |
| 1127 | + zMark = gitmirror_find_mark(zUuid,1); | |
| 1128 | + fprintf(xCmd, "mark %s\n", zMark); | |
| 1129 | + fossil_free(zMark); | |
| 1120 | 1130 | fprintf(xCmd, "committer %s <%[email protected]> %lld +0000\n", |
| 1121 | 1131 | pMan->zUser, pMan->zUser, |
| 1122 | 1132 | (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) |
| 1123 | 1133 | ); |
| 1124 | 1134 | blob_init(&comment, pMan->zComment, -1); |
| @@ -1128,18 +1138,19 @@ | ||
| 1128 | 1138 | blob_appendf(&comment, "\n\nFossilOrigin-Name: %s", zUuid); |
| 1129 | 1139 | fprintf(xCmd, "data %d\n%s\n", blob_size(&comment), blob_str(&comment)); |
| 1130 | 1140 | blob_reset(&comment); |
| 1131 | 1141 | iParent = -1; /* Which ancestor is the primary parent */ |
| 1132 | 1142 | for(i=0; i<pMan->nParent; i++){ |
| 1133 | - int iOther = gitmirror_find_mark(pMan->azParent[i], 0); | |
| 1134 | - if( iOther==0 ) continue; | |
| 1143 | + char *zOther = gitmirror_find_mark(pMan->azParent[i], 0); | |
| 1144 | + if( zOther==0 ) continue; | |
| 1135 | 1145 | if( iParent<0 ){ |
| 1136 | 1146 | iParent = i; |
| 1137 | - fprintf(xCmd, "from :%d\n", iOther); | |
| 1147 | + fprintf(xCmd, "from %s\n", zOther); | |
| 1138 | 1148 | }else{ |
| 1139 | - fprintf(xCmd, "merge :%d\n", iOther); | |
| 1149 | + fprintf(xCmd, "merge %s\n", zOther); | |
| 1140 | 1150 | } |
| 1151 | + fossil_free(zOther); | |
| 1141 | 1152 | } |
| 1142 | 1153 | if( iParent>=0 ){ |
| 1143 | 1154 | db_prepare(&q, |
| 1144 | 1155 | "SELECT filename FROM files_of_checkin(%Q)" |
| 1145 | 1156 | " EXCEPT SELECT filename FROM files_of_checkin(%Q)", |
| @@ -1159,27 +1170,29 @@ | ||
| 1159 | 1170 | blob_append_sql(&sql, |
| 1160 | 1171 | " EXCEPT SELECT filename, uuid, perm FROM files_of_checkin(%Q)", |
| 1161 | 1172 | pMan->azParent[0]); |
| 1162 | 1173 | } |
| 1163 | 1174 | db_prepare(&q, |
| 1164 | - "SELECT x.filename, x.perm, mmark.id FROM (%s) AS x, mirror.mmark" | |
| 1175 | + "SELECT x.filename, x.perm," | |
| 1176 | + " coalesce(mmark.githash,printf(':%%d',mmark.id))" | |
| 1177 | + " FROM (%s) AS x, mirror.mmark" | |
| 1165 | 1178 | " WHERE mmark.uuid=x.uuid", |
| 1166 | 1179 | blob_sql_text(&sql) |
| 1167 | 1180 | ); |
| 1168 | 1181 | blob_reset(&sql); |
| 1169 | 1182 | while( db_step(&q)==SQLITE_ROW ){ |
| 1170 | 1183 | const char *zFilename = db_column_text(&q,0); |
| 1171 | 1184 | const char *zMode = db_column_text(&q,1); |
| 1172 | - int iMark = db_column_int(&q,2); | |
| 1185 | + const char *zMark = db_column_text(&q,2); | |
| 1173 | 1186 | const char *zGitMode = "100644"; |
| 1174 | 1187 | char *zFNQuoted = 0; |
| 1175 | 1188 | if( zMode ){ |
| 1176 | 1189 | if( strchr(zMode,'x') ) zGitMode = "100755"; |
| 1177 | 1190 | if( strchr(zMode,'l') ) zGitMode = "120000"; |
| 1178 | 1191 | } |
| 1179 | 1192 | zFNQuoted = gitmirror_quote_filename_if_needed(zFilename); |
| 1180 | - fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFNQuoted); | |
| 1193 | + fprintf(xCmd,"M %s %s %s\n", zGitMode, zMark, zFNQuoted); | |
| 1181 | 1194 | fossil_free(zFNQuoted); |
| 1182 | 1195 | } |
| 1183 | 1196 | db_finalize(&q); |
| 1184 | 1197 | |
| 1185 | 1198 | /* Include Fossil-generated auxiliary files in the check-in */ |
| @@ -1224,11 +1237,11 @@ | ||
| 1224 | 1237 | double rEnd; /* time of most recent export */ |
| 1225 | 1238 | int rc; /* Result code */ |
| 1226 | 1239 | int bForce; /* Do the export and sync even if no changes*/ |
| 1227 | 1240 | int fManifest; /* Current "manifest" setting */ |
| 1228 | 1241 | FILE *xCmd; /* Pipe to the "git fast-import" command */ |
| 1229 | - FILE *pIn, *pOut; /* Git mark files */ | |
| 1242 | + FILE *pMarks; /* Git mark files */ | |
| 1230 | 1243 | Stmt q; /* Queries */ |
| 1231 | 1244 | char zLine[200]; /* One line of a mark file */ |
| 1232 | 1245 | |
| 1233 | 1246 | zDebug = find_option("debug",0,1); |
| 1234 | 1247 | db_find_and_open_repository(0, 0); |
| @@ -1334,12 +1347,11 @@ | ||
| 1334 | 1347 | xCmd = fopen(zDebug, "wb"); |
| 1335 | 1348 | if( xCmd==0 ) fossil_fatal("cannot open file \"%s\" for writing", zDebug); |
| 1336 | 1349 | } |
| 1337 | 1350 | }else{ |
| 1338 | 1351 | zCmd = mprintf("git fast-import" |
| 1339 | - " --import-marks-if-exists=.mirror_state/in" | |
| 1340 | - " --export-marks=.mirror_state/out" | |
| 1352 | + " --export-marks=.mirror_state/marks.txt" | |
| 1341 | 1353 | " --quiet --done"); |
| 1342 | 1354 | gitmirror_message(VERB_NORMAL, "%s\n", zCmd); |
| 1343 | 1355 | xCmd = popen(zCmd, "w"); |
| 1344 | 1356 | if( zCmd==0 ){ |
| 1345 | 1357 | fossil_fatal("cannot start the \"git fast-import\" command"); |
| @@ -1388,18 +1400,14 @@ | ||
| 1388 | 1400 | nTotal-nLimit, zMirror); |
| 1389 | 1401 | |
| 1390 | 1402 | /* Read the export-marks file. Transfer the new marks over into |
| 1391 | 1403 | ** the import-marks file. |
| 1392 | 1404 | */ |
| 1393 | - pOut = fopen(".mirror_state/out", "rb"); | |
| 1394 | - if( pOut ){ | |
| 1395 | - pIn = fopen(".mirror_state/in", "ab"); | |
| 1396 | - if( pIn==0 ){ | |
| 1397 | - fossil_fatal("cannot open %s/.mirror_state/in for appending", zMirror); | |
| 1398 | - } | |
| 1405 | + pMarks = fopen(".mirror_state/marks.txt", "rb"); | |
| 1406 | + if( pMarks ){ | |
| 1399 | 1407 | db_prepare(&q, "UPDATE mirror.mmark SET githash=:githash WHERE id=:id"); |
| 1400 | - while( fgets(zLine, sizeof(zLine), pOut) ){ | |
| 1408 | + while( fgets(zLine, sizeof(zLine), pMarks) ){ | |
| 1401 | 1409 | int j, k; |
| 1402 | 1410 | if( zLine[0]!=':' ) continue; |
| 1403 | 1411 | db_bind_int(&q, ":id", atoi(zLine+1)); |
| 1404 | 1412 | for(j=1; zLine[j] && zLine[j]!=' '; j++){} |
| 1405 | 1413 | if( zLine[j]!=' ' ) continue; |
| @@ -1408,17 +1416,14 @@ | ||
| 1408 | 1416 | for(k=j; fossil_isalnum(zLine[k]); k++){} |
| 1409 | 1417 | zLine[k] = 0; |
| 1410 | 1418 | db_bind_text(&q, ":githash", &zLine[j]); |
| 1411 | 1419 | db_step(&q); |
| 1412 | 1420 | db_reset(&q); |
| 1413 | - zLine[k] = '\n'; | |
| 1414 | - fputs(zLine, pIn); | |
| 1415 | 1421 | } |
| 1416 | 1422 | db_finalize(&q); |
| 1417 | - fclose(pOut); | |
| 1418 | - fclose(pIn); | |
| 1419 | - file_delete(".mirror_state/out"); | |
| 1423 | + fclose(pMarks); | |
| 1424 | + file_delete(".mirror_state/marks.txt"); | |
| 1420 | 1425 | }else{ |
| 1421 | 1426 | fossil_fatal("git fast-import didn't generate a marks file!"); |
| 1422 | 1427 | } |
| 1423 | 1428 | db_multi_exec( |
| 1424 | 1429 | "CREATE INDEX IF NOT EXISTS mirror.mmarkx1 ON mmark(githash);" |
| 1425 | 1430 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -936,37 +936,42 @@ | |
| 936 | zOut[j] = 0; |
| 937 | return zOut; |
| 938 | } |
| 939 | |
| 940 | /* |
| 941 | ** Locate the mark for a UUID. |
| 942 | ** |
| 943 | ** If the mark does not exist and if the bCreate flag is false, then |
| 944 | ** return 0. If the mark does not exist and the bCreate flag is true, |
| 945 | ** then create the mark. |
| 946 | */ |
| 947 | static int gitmirror_find_mark(const char *zUuid, int bCreate){ |
| 948 | int iMark; |
| 949 | static Stmt sFind, sIns; |
| 950 | db_static_prepare(&sFind, |
| 951 | "SELECT id FROM mirror.mmark WHERE uuid=:uuid" |
| 952 | ); |
| 953 | db_bind_text(&sFind, ":uuid", zUuid); |
| 954 | if( db_step(&sFind)==SQLITE_ROW ){ |
| 955 | iMark = db_column_int(&sFind, 0); |
| 956 | db_reset(&sFind); |
| 957 | return iMark; |
| 958 | } |
| 959 | db_reset(&sFind); |
| 960 | if( !bCreate ) return 0; |
| 961 | db_static_prepare(&sIns, |
| 962 | "INSERT INTO mirror.mmark(uuid) VALUES(:uuid)" |
| 963 | ); |
| 964 | db_bind_text(&sIns, ":uuid", zUuid); |
| 965 | db_step(&sIns); |
| 966 | db_reset(&sIns); |
| 967 | return db_last_insert_rowid(); |
| 968 | } |
| 969 | |
| 970 | /* This is the SHA3-256 hash of an empty file */ |
| 971 | static const char zEmptySha3[] = |
| 972 | "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; |
| @@ -980,11 +985,11 @@ | |
| 980 | ** But files that are missing from the repository but have not been officially |
| 981 | ** shunned cause an error return. Except, if bPhantomOk is true, then missing |
| 982 | ** files are replaced by an empty file. |
| 983 | */ |
| 984 | static int gitmirror_send_file(FILE *xCmd, const char *zUuid, int bPhantomOk){ |
| 985 | int iMark; |
| 986 | int rid; |
| 987 | int rc; |
| 988 | Blob data; |
| 989 | rid = fast_uuid_to_rid(zUuid); |
| 990 | if( rid<0 ){ |
| @@ -1004,14 +1009,17 @@ | |
| 1004 | }else{ |
| 1005 | return 1; |
| 1006 | } |
| 1007 | } |
| 1008 | } |
| 1009 | iMark = gitmirror_find_mark(zUuid, 1); |
| 1010 | fprintf(xCmd, "blob\nmark :%d\ndata %d\n", iMark, blob_size(&data)); |
| 1011 | fwrite(blob_buffer(&data), 1, blob_size(&data), xCmd); |
| 1012 | fprintf(xCmd, "\n"); |
| 1013 | blob_reset(&data); |
| 1014 | return 0; |
| 1015 | } |
| 1016 | |
| 1017 | /* |
| @@ -1039,11 +1047,11 @@ | |
| 1039 | Manifest *pMan; /* The check-in to be output */ |
| 1040 | int i; /* Loop counter */ |
| 1041 | int iParent; /* Which immediate ancestor is primary. -1 for none */ |
| 1042 | Stmt q; /* An SQL query */ |
| 1043 | char *zBranch; /* The branch of the check-in */ |
| 1044 | int iMark; /* The mark for the check-in */ |
| 1045 | Blob sql; /* String of SQL for part of the query */ |
| 1046 | Blob comment; /* The comment text for the check-in */ |
| 1047 | int nErr = 0; /* Number of errors */ |
| 1048 | int bPhantomOk; /* True if phantom files should be ignored */ |
| 1049 | |
| @@ -1056,21 +1064,22 @@ | |
| 1056 | } |
| 1057 | |
| 1058 | /* Check to see if any parent logins have not yet been processed, and |
| 1059 | ** if so, create them */ |
| 1060 | for(i=0; i<pMan->nParent; i++){ |
| 1061 | int iMark = gitmirror_find_mark(pMan->azParent[i], 0); |
| 1062 | if( iMark<=0 ){ |
| 1063 | int prid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", |
| 1064 | pMan->azParent[i]); |
| 1065 | int rc = gitmirror_send_checkin(xCmd, prid, pMan->azParent[i], |
| 1066 | pnLimit, fManifest); |
| 1067 | if( rc || *pnLimit<=0 ){ |
| 1068 | manifest_destroy(pMan); |
| 1069 | return 1; |
| 1070 | } |
| 1071 | } |
| 1072 | } |
| 1073 | |
| 1074 | /* Ignore phantom files on check-ins that are over one year old */ |
| 1075 | bPhantomOk = db_int(0, "SELECT %.6f<julianday('now','-1 year')", |
| 1076 | pMan->rDate); |
| @@ -1113,12 +1122,13 @@ | |
| 1113 | } |
| 1114 | |
| 1115 | /* Export the check-in */ |
| 1116 | fprintf(xCmd, "commit refs/heads/%s\n", zBranch); |
| 1117 | fossil_free(zBranch); |
| 1118 | iMark = gitmirror_find_mark(zUuid, 1); |
| 1119 | fprintf(xCmd, "mark :%d\n", iMark); |
| 1120 | fprintf(xCmd, "committer %s <%[email protected]> %lld +0000\n", |
| 1121 | pMan->zUser, pMan->zUser, |
| 1122 | (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) |
| 1123 | ); |
| 1124 | blob_init(&comment, pMan->zComment, -1); |
| @@ -1128,18 +1138,19 @@ | |
| 1128 | blob_appendf(&comment, "\n\nFossilOrigin-Name: %s", zUuid); |
| 1129 | fprintf(xCmd, "data %d\n%s\n", blob_size(&comment), blob_str(&comment)); |
| 1130 | blob_reset(&comment); |
| 1131 | iParent = -1; /* Which ancestor is the primary parent */ |
| 1132 | for(i=0; i<pMan->nParent; i++){ |
| 1133 | int iOther = gitmirror_find_mark(pMan->azParent[i], 0); |
| 1134 | if( iOther==0 ) continue; |
| 1135 | if( iParent<0 ){ |
| 1136 | iParent = i; |
| 1137 | fprintf(xCmd, "from :%d\n", iOther); |
| 1138 | }else{ |
| 1139 | fprintf(xCmd, "merge :%d\n", iOther); |
| 1140 | } |
| 1141 | } |
| 1142 | if( iParent>=0 ){ |
| 1143 | db_prepare(&q, |
| 1144 | "SELECT filename FROM files_of_checkin(%Q)" |
| 1145 | " EXCEPT SELECT filename FROM files_of_checkin(%Q)", |
| @@ -1159,27 +1170,29 @@ | |
| 1159 | blob_append_sql(&sql, |
| 1160 | " EXCEPT SELECT filename, uuid, perm FROM files_of_checkin(%Q)", |
| 1161 | pMan->azParent[0]); |
| 1162 | } |
| 1163 | db_prepare(&q, |
| 1164 | "SELECT x.filename, x.perm, mmark.id FROM (%s) AS x, mirror.mmark" |
| 1165 | " WHERE mmark.uuid=x.uuid", |
| 1166 | blob_sql_text(&sql) |
| 1167 | ); |
| 1168 | blob_reset(&sql); |
| 1169 | while( db_step(&q)==SQLITE_ROW ){ |
| 1170 | const char *zFilename = db_column_text(&q,0); |
| 1171 | const char *zMode = db_column_text(&q,1); |
| 1172 | int iMark = db_column_int(&q,2); |
| 1173 | const char *zGitMode = "100644"; |
| 1174 | char *zFNQuoted = 0; |
| 1175 | if( zMode ){ |
| 1176 | if( strchr(zMode,'x') ) zGitMode = "100755"; |
| 1177 | if( strchr(zMode,'l') ) zGitMode = "120000"; |
| 1178 | } |
| 1179 | zFNQuoted = gitmirror_quote_filename_if_needed(zFilename); |
| 1180 | fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFNQuoted); |
| 1181 | fossil_free(zFNQuoted); |
| 1182 | } |
| 1183 | db_finalize(&q); |
| 1184 | |
| 1185 | /* Include Fossil-generated auxiliary files in the check-in */ |
| @@ -1224,11 +1237,11 @@ | |
| 1224 | double rEnd; /* time of most recent export */ |
| 1225 | int rc; /* Result code */ |
| 1226 | int bForce; /* Do the export and sync even if no changes*/ |
| 1227 | int fManifest; /* Current "manifest" setting */ |
| 1228 | FILE *xCmd; /* Pipe to the "git fast-import" command */ |
| 1229 | FILE *pIn, *pOut; /* Git mark files */ |
| 1230 | Stmt q; /* Queries */ |
| 1231 | char zLine[200]; /* One line of a mark file */ |
| 1232 | |
| 1233 | zDebug = find_option("debug",0,1); |
| 1234 | db_find_and_open_repository(0, 0); |
| @@ -1334,12 +1347,11 @@ | |
| 1334 | xCmd = fopen(zDebug, "wb"); |
| 1335 | if( xCmd==0 ) fossil_fatal("cannot open file \"%s\" for writing", zDebug); |
| 1336 | } |
| 1337 | }else{ |
| 1338 | zCmd = mprintf("git fast-import" |
| 1339 | " --import-marks-if-exists=.mirror_state/in" |
| 1340 | " --export-marks=.mirror_state/out" |
| 1341 | " --quiet --done"); |
| 1342 | gitmirror_message(VERB_NORMAL, "%s\n", zCmd); |
| 1343 | xCmd = popen(zCmd, "w"); |
| 1344 | if( zCmd==0 ){ |
| 1345 | fossil_fatal("cannot start the \"git fast-import\" command"); |
| @@ -1388,18 +1400,14 @@ | |
| 1388 | nTotal-nLimit, zMirror); |
| 1389 | |
| 1390 | /* Read the export-marks file. Transfer the new marks over into |
| 1391 | ** the import-marks file. |
| 1392 | */ |
| 1393 | pOut = fopen(".mirror_state/out", "rb"); |
| 1394 | if( pOut ){ |
| 1395 | pIn = fopen(".mirror_state/in", "ab"); |
| 1396 | if( pIn==0 ){ |
| 1397 | fossil_fatal("cannot open %s/.mirror_state/in for appending", zMirror); |
| 1398 | } |
| 1399 | db_prepare(&q, "UPDATE mirror.mmark SET githash=:githash WHERE id=:id"); |
| 1400 | while( fgets(zLine, sizeof(zLine), pOut) ){ |
| 1401 | int j, k; |
| 1402 | if( zLine[0]!=':' ) continue; |
| 1403 | db_bind_int(&q, ":id", atoi(zLine+1)); |
| 1404 | for(j=1; zLine[j] && zLine[j]!=' '; j++){} |
| 1405 | if( zLine[j]!=' ' ) continue; |
| @@ -1408,17 +1416,14 @@ | |
| 1408 | for(k=j; fossil_isalnum(zLine[k]); k++){} |
| 1409 | zLine[k] = 0; |
| 1410 | db_bind_text(&q, ":githash", &zLine[j]); |
| 1411 | db_step(&q); |
| 1412 | db_reset(&q); |
| 1413 | zLine[k] = '\n'; |
| 1414 | fputs(zLine, pIn); |
| 1415 | } |
| 1416 | db_finalize(&q); |
| 1417 | fclose(pOut); |
| 1418 | fclose(pIn); |
| 1419 | file_delete(".mirror_state/out"); |
| 1420 | }else{ |
| 1421 | fossil_fatal("git fast-import didn't generate a marks file!"); |
| 1422 | } |
| 1423 | db_multi_exec( |
| 1424 | "CREATE INDEX IF NOT EXISTS mirror.mmarkx1 ON mmark(githash);" |
| 1425 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -936,37 +936,42 @@ | |
| 936 | zOut[j] = 0; |
| 937 | return zOut; |
| 938 | } |
| 939 | |
| 940 | /* |
| 941 | ** Find the Git-name corresponding to the Fossil-name zUuid. |
| 942 | ** |
| 943 | ** If the mark does not exist and if the bCreate flag is false, then |
| 944 | ** return NULL. If the mark does not exist and the bCreate flag is true, |
| 945 | ** then create the mark. |
| 946 | ** |
| 947 | ** The string returned is obtained from fossil_malloc() and should |
| 948 | ** be freed by the caller. |
| 949 | */ |
| 950 | static char *gitmirror_find_mark(const char *zUuid, int bCreate){ |
| 951 | static Stmt sFind, sIns; |
| 952 | db_static_prepare(&sFind, |
| 953 | "SELECT coalesce(githash,printf(':%%d',id))" |
| 954 | " FROM mirror.mmark WHERE uuid=:uuid" |
| 955 | ); |
| 956 | db_bind_text(&sFind, ":uuid", zUuid); |
| 957 | if( db_step(&sFind)==SQLITE_ROW ){ |
| 958 | char *zMark = fossil_strdup(db_column_text(&sFind, 0)); |
| 959 | db_reset(&sFind); |
| 960 | return zMark; |
| 961 | } |
| 962 | db_reset(&sFind); |
| 963 | if( !bCreate ){ |
| 964 | return 0; |
| 965 | } |
| 966 | db_static_prepare(&sIns, |
| 967 | "INSERT INTO mirror.mmark(uuid) VALUES(:uuid)" |
| 968 | ); |
| 969 | db_bind_text(&sIns, ":uuid", zUuid); |
| 970 | db_step(&sIns); |
| 971 | db_reset(&sIns); |
| 972 | return mprintf(":%d", db_last_insert_rowid()); |
| 973 | } |
| 974 | |
| 975 | /* This is the SHA3-256 hash of an empty file */ |
| 976 | static const char zEmptySha3[] = |
| 977 | "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; |
| @@ -980,11 +985,11 @@ | |
| 985 | ** But files that are missing from the repository but have not been officially |
| 986 | ** shunned cause an error return. Except, if bPhantomOk is true, then missing |
| 987 | ** files are replaced by an empty file. |
| 988 | */ |
| 989 | static int gitmirror_send_file(FILE *xCmd, const char *zUuid, int bPhantomOk){ |
| 990 | char *zMark; |
| 991 | int rid; |
| 992 | int rc; |
| 993 | Blob data; |
| 994 | rid = fast_uuid_to_rid(zUuid); |
| 995 | if( rid<0 ){ |
| @@ -1004,14 +1009,17 @@ | |
| 1009 | }else{ |
| 1010 | return 1; |
| 1011 | } |
| 1012 | } |
| 1013 | } |
| 1014 | zMark = gitmirror_find_mark(zUuid, 1); |
| 1015 | if( zMark[0]==':' ){ |
| 1016 | fprintf(xCmd, "blob\nmark %s\ndata %d\n", zMark, blob_size(&data)); |
| 1017 | fwrite(blob_buffer(&data), 1, blob_size(&data), xCmd); |
| 1018 | fprintf(xCmd, "\n"); |
| 1019 | } |
| 1020 | fossil_free(zMark); |
| 1021 | blob_reset(&data); |
| 1022 | return 0; |
| 1023 | } |
| 1024 | |
| 1025 | /* |
| @@ -1039,11 +1047,11 @@ | |
| 1047 | Manifest *pMan; /* The check-in to be output */ |
| 1048 | int i; /* Loop counter */ |
| 1049 | int iParent; /* Which immediate ancestor is primary. -1 for none */ |
| 1050 | Stmt q; /* An SQL query */ |
| 1051 | char *zBranch; /* The branch of the check-in */ |
| 1052 | char *zMark; /* The Git-name of the check-in */ |
| 1053 | Blob sql; /* String of SQL for part of the query */ |
| 1054 | Blob comment; /* The comment text for the check-in */ |
| 1055 | int nErr = 0; /* Number of errors */ |
| 1056 | int bPhantomOk; /* True if phantom files should be ignored */ |
| 1057 | |
| @@ -1056,21 +1064,22 @@ | |
| 1064 | } |
| 1065 | |
| 1066 | /* Check to see if any parent logins have not yet been processed, and |
| 1067 | ** if so, create them */ |
| 1068 | for(i=0; i<pMan->nParent; i++){ |
| 1069 | char *zPMark = gitmirror_find_mark(pMan->azParent[i], 0); |
| 1070 | if( zPMark==0 ){ |
| 1071 | int prid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", |
| 1072 | pMan->azParent[i]); |
| 1073 | int rc = gitmirror_send_checkin(xCmd, prid, pMan->azParent[i], |
| 1074 | pnLimit, fManifest); |
| 1075 | if( rc || *pnLimit<=0 ){ |
| 1076 | manifest_destroy(pMan); |
| 1077 | return 1; |
| 1078 | } |
| 1079 | } |
| 1080 | fossil_free(zPMark); |
| 1081 | } |
| 1082 | |
| 1083 | /* Ignore phantom files on check-ins that are over one year old */ |
| 1084 | bPhantomOk = db_int(0, "SELECT %.6f<julianday('now','-1 year')", |
| 1085 | pMan->rDate); |
| @@ -1113,12 +1122,13 @@ | |
| 1122 | } |
| 1123 | |
| 1124 | /* Export the check-in */ |
| 1125 | fprintf(xCmd, "commit refs/heads/%s\n", zBranch); |
| 1126 | fossil_free(zBranch); |
| 1127 | zMark = gitmirror_find_mark(zUuid,1); |
| 1128 | fprintf(xCmd, "mark %s\n", zMark); |
| 1129 | fossil_free(zMark); |
| 1130 | fprintf(xCmd, "committer %s <%[email protected]> %lld +0000\n", |
| 1131 | pMan->zUser, pMan->zUser, |
| 1132 | (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) |
| 1133 | ); |
| 1134 | blob_init(&comment, pMan->zComment, -1); |
| @@ -1128,18 +1138,19 @@ | |
| 1138 | blob_appendf(&comment, "\n\nFossilOrigin-Name: %s", zUuid); |
| 1139 | fprintf(xCmd, "data %d\n%s\n", blob_size(&comment), blob_str(&comment)); |
| 1140 | blob_reset(&comment); |
| 1141 | iParent = -1; /* Which ancestor is the primary parent */ |
| 1142 | for(i=0; i<pMan->nParent; i++){ |
| 1143 | char *zOther = gitmirror_find_mark(pMan->azParent[i], 0); |
| 1144 | if( zOther==0 ) continue; |
| 1145 | if( iParent<0 ){ |
| 1146 | iParent = i; |
| 1147 | fprintf(xCmd, "from %s\n", zOther); |
| 1148 | }else{ |
| 1149 | fprintf(xCmd, "merge %s\n", zOther); |
| 1150 | } |
| 1151 | fossil_free(zOther); |
| 1152 | } |
| 1153 | if( iParent>=0 ){ |
| 1154 | db_prepare(&q, |
| 1155 | "SELECT filename FROM files_of_checkin(%Q)" |
| 1156 | " EXCEPT SELECT filename FROM files_of_checkin(%Q)", |
| @@ -1159,27 +1170,29 @@ | |
| 1170 | blob_append_sql(&sql, |
| 1171 | " EXCEPT SELECT filename, uuid, perm FROM files_of_checkin(%Q)", |
| 1172 | pMan->azParent[0]); |
| 1173 | } |
| 1174 | db_prepare(&q, |
| 1175 | "SELECT x.filename, x.perm," |
| 1176 | " coalesce(mmark.githash,printf(':%%d',mmark.id))" |
| 1177 | " FROM (%s) AS x, mirror.mmark" |
| 1178 | " WHERE mmark.uuid=x.uuid", |
| 1179 | blob_sql_text(&sql) |
| 1180 | ); |
| 1181 | blob_reset(&sql); |
| 1182 | while( db_step(&q)==SQLITE_ROW ){ |
| 1183 | const char *zFilename = db_column_text(&q,0); |
| 1184 | const char *zMode = db_column_text(&q,1); |
| 1185 | const char *zMark = db_column_text(&q,2); |
| 1186 | const char *zGitMode = "100644"; |
| 1187 | char *zFNQuoted = 0; |
| 1188 | if( zMode ){ |
| 1189 | if( strchr(zMode,'x') ) zGitMode = "100755"; |
| 1190 | if( strchr(zMode,'l') ) zGitMode = "120000"; |
| 1191 | } |
| 1192 | zFNQuoted = gitmirror_quote_filename_if_needed(zFilename); |
| 1193 | fprintf(xCmd,"M %s %s %s\n", zGitMode, zMark, zFNQuoted); |
| 1194 | fossil_free(zFNQuoted); |
| 1195 | } |
| 1196 | db_finalize(&q); |
| 1197 | |
| 1198 | /* Include Fossil-generated auxiliary files in the check-in */ |
| @@ -1224,11 +1237,11 @@ | |
| 1237 | double rEnd; /* time of most recent export */ |
| 1238 | int rc; /* Result code */ |
| 1239 | int bForce; /* Do the export and sync even if no changes*/ |
| 1240 | int fManifest; /* Current "manifest" setting */ |
| 1241 | FILE *xCmd; /* Pipe to the "git fast-import" command */ |
| 1242 | FILE *pMarks; /* Git mark files */ |
| 1243 | Stmt q; /* Queries */ |
| 1244 | char zLine[200]; /* One line of a mark file */ |
| 1245 | |
| 1246 | zDebug = find_option("debug",0,1); |
| 1247 | db_find_and_open_repository(0, 0); |
| @@ -1334,12 +1347,11 @@ | |
| 1347 | xCmd = fopen(zDebug, "wb"); |
| 1348 | if( xCmd==0 ) fossil_fatal("cannot open file \"%s\" for writing", zDebug); |
| 1349 | } |
| 1350 | }else{ |
| 1351 | zCmd = mprintf("git fast-import" |
| 1352 | " --export-marks=.mirror_state/marks.txt" |
| 1353 | " --quiet --done"); |
| 1354 | gitmirror_message(VERB_NORMAL, "%s\n", zCmd); |
| 1355 | xCmd = popen(zCmd, "w"); |
| 1356 | if( zCmd==0 ){ |
| 1357 | fossil_fatal("cannot start the \"git fast-import\" command"); |
| @@ -1388,18 +1400,14 @@ | |
| 1400 | nTotal-nLimit, zMirror); |
| 1401 | |
| 1402 | /* Read the export-marks file. Transfer the new marks over into |
| 1403 | ** the import-marks file. |
| 1404 | */ |
| 1405 | pMarks = fopen(".mirror_state/marks.txt", "rb"); |
| 1406 | if( pMarks ){ |
| 1407 | db_prepare(&q, "UPDATE mirror.mmark SET githash=:githash WHERE id=:id"); |
| 1408 | while( fgets(zLine, sizeof(zLine), pMarks) ){ |
| 1409 | int j, k; |
| 1410 | if( zLine[0]!=':' ) continue; |
| 1411 | db_bind_int(&q, ":id", atoi(zLine+1)); |
| 1412 | for(j=1; zLine[j] && zLine[j]!=' '; j++){} |
| 1413 | if( zLine[j]!=' ' ) continue; |
| @@ -1408,17 +1416,14 @@ | |
| 1416 | for(k=j; fossil_isalnum(zLine[k]); k++){} |
| 1417 | zLine[k] = 0; |
| 1418 | db_bind_text(&q, ":githash", &zLine[j]); |
| 1419 | db_step(&q); |
| 1420 | db_reset(&q); |
| 1421 | } |
| 1422 | db_finalize(&q); |
| 1423 | fclose(pMarks); |
| 1424 | file_delete(".mirror_state/marks.txt"); |
| 1425 | }else{ |
| 1426 | fossil_fatal("git fast-import didn't generate a marks file!"); |
| 1427 | } |
| 1428 | db_multi_exec( |
| 1429 | "CREATE INDEX IF NOT EXISTS mirror.mmarkx1 ON mmark(githash);" |
| 1430 |