Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Rename "fossil mirror" to "fossil git export". Deprecate the "fossil export" command. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | mirror-cmd |
Files: | files | file ages | folders |
SHA3-256: |
2faec6b7481520a0b57ea315e6a80462 |
User & Date: | drh 2019-03-15 16:38:05.120 |
Context
2019-03-15
| ||
20:01 | Add the "FossilOrigin-Name:" footer on all exported comments. ... (check-in: 051cd382 user: drh tags: mirror-cmd) | |
16:38 | Rename "fossil mirror" to "fossil git export". Deprecate the "fossil export" command. ... (check-in: 2faec6b7 user: drh tags: mirror-cmd) | |
16:11 | Export "manifest", "manifest.uuid", and "manifest.tags" files if that is what the repository needs. ... (check-in: eafe5ce6 user: drh tags: mirror-cmd) | |
Changes
Changes to src/export.c.
︙ | ︙ | |||
445 446 447 448 449 450 451 | do{ export_mark(f, rid, 'c'); }while( (rid = bag_next(vers, rid))!=0 ); } } } | | | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | do{ export_mark(f, rid, 'c'); }while( (rid = bag_next(vers, rid))!=0 ); } } } /* This is the original header command (and hence documentation) for ** the "fossil export" command: ** ** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY? ** ** Write an export of all check-ins to standard output. The export is ** written in the git-fast-export file format assuming the --git option is ** provided. The git-fast-export format is currently the only VCS ** interchange format supported, though other formats may be added in ** the future. |
︙ | ︙ | |||
476 477 478 479 480 481 482 483 484 485 486 487 488 489 | ** --export-marks FILE export rids of exported data to FILE ** --import-marks FILE read rids of data to ignore from FILE ** --rename-trunk NAME use NAME as name of exported trunk branch ** --repository|-R REPOSITORY export the given REPOSITORY ** ** See also: import */ void export_cmd(void){ Stmt q, q2, q3; Bag blobs, vers; unsigned int unused_mark = 1; const char *markfile_in; const char *markfile_out; | > > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | ** --export-marks FILE export rids of exported data to FILE ** --import-marks FILE read rids of data to ignore from FILE ** --rename-trunk NAME use NAME as name of exported trunk branch ** --repository|-R REPOSITORY export the given REPOSITORY ** ** See also: import */ /* ** COMMAND: export* ** ** This command is deprecated. Use "fossil git export" instead. */ void export_cmd(void){ Stmt q, q2, q3; Bag blobs, vers; unsigned int unused_mark = 1; const char *markfile_in; const char *markfile_out; |
︙ | ︙ | |||
831 832 833 834 835 836 837 | int n; db_find_and_open_repository(0, 0); n = topological_sort_checkins(1); fossil_print("%d reorderings required\n", n); } /*************************************************************************** | | | | | | 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 | int n; db_find_and_open_repository(0, 0); n = topological_sort_checkins(1); fossil_print("%d reorderings required\n", n); } /*************************************************************************** ** Implementation of the "fossil git" command follows. We hope that the ** new code that follows will largely replace the legacy "fossil export" ** and "fossil import" code above. */ /* ** Convert characters of z[] that are not allowed to be in branch or ** tag names into "_". */ static void gitmirror_sanitize_name(char *z){ static unsigned char aSafe[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 2x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ |
︙ | ︙ | |||
873 874 875 876 877 878 879 | /* ** Quote a filename as a C-style string using \\ and \" if necessary. ** If quoting is not necessary, just return a copy of the input string. ** ** The return value is a held in memory obtained from fossil_malloc() ** and must be freed by the caller. */ | | | 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 | /* ** Quote a filename as a C-style string using \\ and \" if necessary. ** If quoting is not necessary, just return a copy of the input string. ** ** The return value is a held in memory obtained from fossil_malloc() ** and must be freed by the caller. */ static char *gitmirror_quote_filename_if_needed(const char *zIn){ int i, j; char c; int nSpecial = 0; char *zOut; for(i=0; (c = zIn[i])!=0; i++){ if( c=='\\' || c=='"' || c=='\n' ){ nSpecial++; |
︙ | ︙ | |||
913 914 915 916 917 918 919 | ** Transfer a tag over to the mirror. "rid" is the BLOB.RID value for ** the record that describes the tag. ** ** The Git tag mechanism is very limited compared to Fossil. Many Fossil ** tags cannot be exported to Git. If this tag cannot be exported, then ** silently ignore it. */ | | | | 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | ** Transfer a tag over to the mirror. "rid" is the BLOB.RID value for ** the record that describes the tag. ** ** The Git tag mechanism is very limited compared to Fossil. Many Fossil ** tags cannot be exported to Git. If this tag cannot be exported, then ** silently ignore it. */ static void gitmirror_send_tag(FILE *xCmd, int rid){ return; } /* ** Locate the mark for a UUID. ** ** If the mark does not exist and if the bCreate flag is false, then ** return 0. If the mark does not exist and the bCreate flag is true, ** then create the mark. */ static int gitmirror_find_mark(const char *zUuid, int bCreate){ int iMark; static Stmt sFind, sIns; db_static_prepare(&sFind, "SELECT id FROM mirror.mmark WHERE uuid=:uuid" ); db_bind_text(&sFind, ":uuid", zUuid); if( db_step(&sFind)==SQLITE_ROW ){ |
︙ | ︙ | |||
954 955 956 957 958 959 960 | /* This is the SHA3-256 hash of an empty file */ static const char zEmptySha3[] = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; /* ** Export a single file named by zUuid. */ | | | | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | /* This is the SHA3-256 hash of an empty file */ static const char zEmptySha3[] = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; /* ** Export a single file named by zUuid. */ static void gitmirror_send_file(FILE *xCmd, const char *zUuid){ int iMark; int rid; int rc; Blob data; rid = fast_uuid_to_rid(zUuid); if( rid<0 ){ zUuid = zEmptySha3; }else{ rc = content_get(rid, &data); if( rc==0 ){ blob_init(&data, 0, 0); zUuid = zEmptySha3; } } iMark = gitmirror_find_mark(zUuid, 1); fprintf(xCmd, "blob\nmark :%d\ndata %d\n", iMark, blob_size(&data)); fwrite(blob_buffer(&data), 1, blob_size(&data), xCmd); fprintf(xCmd, "\n"); blob_reset(&data); } /* ** Transfer a check-in over to the mirror. "rid" is the BLOB.RID for ** the check-in to export. ** ** If any ancestor of the check-in has not yet been exported, then ** invoke this routine recursively to export the ancestor first. ** This can only happen on a timewarp, so deep nesting is unlikely. ** ** Before sending the check-in, first make sure all associated files ** have already been exported, and send "blob" records for any that ** have not been. Update the MIRROR.MMARK table so that it holds the ** marks for the exported files. */ static void gitmirror_send_checkin( FILE *xCmd, /* Write fast-import text on this pipe */ int rid, /* BLOB.RID for the check-in to export */ const char *zUuid, /* BLOB.UUID for the check-in to export */ int *pnLimit, /* Stop when the counter reaches zero */ int fManifest /* MFESTFLG_* values */ ){ Manifest *pMan; /* The check-in to be output */ |
︙ | ︙ | |||
1015 1016 1017 1018 1019 1020 1021 | ** without creating a mark for this check-in. */ return; } /* Check to see if any parent logins have not yet been processed, and ** if so, create them */ for(i=0; i<pMan->nParent; i++){ | | | | | | | | 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 | ** without creating a mark for this check-in. */ return; } /* Check to see if any parent logins have not yet been processed, and ** if so, create them */ for(i=0; i<pMan->nParent; i++){ int iMark = gitmirror_find_mark(pMan->azParent[i], 0); if( iMark<=0 ){ int prid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pMan->azParent[i]); gitmirror_send_checkin(xCmd, prid, pMan->azParent[i], pnLimit, fManifest); if( *pnLimit<=0 ){ manifest_destroy(pMan); return; } } } /* Make sure all necessary files have been exported */ db_prepare(&q, "SELECT uuid FROM files_of_checkin(%Q)" " WHERE uuid NOT IN (SELECT uuid FROM mirror.mmark)", zUuid ); while( db_step(&q)==SQLITE_ROW ){ const char *zFUuid = db_column_text(&q, 0); gitmirror_send_file(xCmd, zFUuid); } db_finalize(&q); /* Figure out which branch this check-in is a member of */ zBranch = db_text(0, "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=%d", TAG_BRANCH, rid ); if( fossil_strcmp(zBranch,"trunk")==0 ){ fossil_free(zBranch); zBranch = mprintf("master"); }else if( zBranch==0 ){ zBranch = mprintf("unknown"); }else{ gitmirror_sanitize_name(zBranch); } /* Export the check-in */ fprintf(xCmd, "commit refs/heads/%s\n", zBranch); fossil_free(zBranch); iMark = gitmirror_find_mark(zUuid, 1); fprintf(xCmd, "mark :%d\n", iMark); fprintf(xCmd, "committer %s <%s@noemail.net> %lld +0000\n", pMan->zUser, pMan->zUser, (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) ); zCom = pMan->zComment; if( zCom==0 ) zCom = "(no comment)"; fprintf(xCmd, "data %d\n%s\n", (int)strlen(zCom), zCom); iParent = -1; /* Which ancestor is the primary parent */ for(i=0; i<pMan->nParent; i++){ int iOther = gitmirror_find_mark(pMan->azParent[i], 0); if( iOther==0 ) continue; if( iParent<0 ){ iParent = i; fprintf(xCmd, "from :%d\n", iOther); }else{ fprintf(xCmd, "merge :%d\n", iOther); } |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 | int iMark = db_column_int(&q,2); const char *zGitMode = "100644"; char *zFNQuoted = 0; if( zMode ){ if( strchr(zMode,'x') ) zGitMode = "100755"; if( strchr(zMode,'l') ) zGitMode = "120000"; } | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | int iMark = db_column_int(&q,2); const char *zGitMode = "100644"; char *zFNQuoted = 0; if( zMode ){ if( strchr(zMode,'x') ) zGitMode = "100755"; if( strchr(zMode,'l') ) zGitMode = "120000"; } zFNQuoted = gitmirror_quote_filename_if_needed(zFilename); fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFNQuoted); fossil_free(zFNQuoted); } db_finalize(&q); /* Include Fossil-generated auxiliary files in the check-in */ if( fManifest & MFESTFLG_RAW ){ |
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | } /* The check-in is finished, so decrement the counter */ (*pnLimit)--; } /* | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < | < | | | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 | } /* The check-in is finished, so decrement the counter */ (*pnLimit)--; } /* ** Implementation of the "fossil git export" command. */ void gitmirror_export_command(void){ const char *zLimit; /* Text of the --limit flag */ int nLimit = 0x7fffffff; /* Numeric value of the --limit flag */ int nTotal = 0; /* Total number of check-ins to export */ char *zMirror; /* Name of the mirror */ char *z; /* Generic string */ char *zCmd; /* git command to run as a subprocess */ const char *zDebug = 0; /* Value of the --debug flag */ double rEnd; /* time of most recent export */ int rc; /* Result code */ int fManifest; /* Current "manifest" setting */ FILE *xCmd; /* Pipe to the "git fast-import" command */ FILE *pIn, *pOut; /* Git mark files */ Stmt q; /* Queries */ char zLine[200]; /* One line of a mark file */ zDebug = find_option("debug",0,1); db_find_and_open_repository(0, 0); zLimit = find_option("limit", 0, 1); if( zLimit ){ nLimit = (unsigned int)atoi(zLimit); if( nLimit<=0 ) fossil_fatal("--limit must be positive"); } verify_all_options(); if( g.argc!=4 ){ usage("export MIRROR"); } zMirror = g.argv[3]; /* Make sure the GIT repository directory exists */ rc = file_mkdir(zMirror, ExtFILE, 0); if( rc ) fossil_fatal("cannot create directory \"%s\"", zMirror); /* Make sure GIT has been initialized */ z = mprintf("%s/.git", zMirror); |
︙ | ︙ | |||
1319 1320 1321 1322 1323 1324 1325 | while( nLimit && db_step(&q)==SQLITE_ROW ){ double rMTime = db_column_double(&q, 2); const char *zType = db_column_text(&q, 1); int rid = db_column_int(&q, 0); const char *zUuid = db_column_text(&q, 3); if( rMTime>rEnd ) rEnd = rMTime; if( zType[0]=='t' ){ | | | | 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | while( nLimit && db_step(&q)==SQLITE_ROW ){ double rMTime = db_column_double(&q, 2); const char *zType = db_column_text(&q, 1); int rid = db_column_int(&q, 0); const char *zUuid = db_column_text(&q, 3); if( rMTime>rEnd ) rEnd = rMTime; if( zType[0]=='t' ){ gitmirror_send_tag(xCmd, rid); }else{ gitmirror_send_checkin(xCmd, rid, zUuid, &nLimit, fManifest); printf("\r%d/%d ", nTotal-nLimit, nTotal); fflush(stdout); } } db_finalize(&q); db_prepare(&q, "REPLACE INTO mirror.mconfig(key,value) VALUES('start',:x)"); db_bind_double(&q, ":x", rEnd); |
︙ | ︙ | |||
1360 1361 1362 1363 1364 1365 1366 | file_delete(".mirror_state/out"); }else{ fossil_fatal("git fast-import didn't generate a marks file!"); } /* Optionally do a "git push" */ } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 | file_delete(".mirror_state/out"); }else{ fossil_fatal("git fast-import didn't generate a marks file!"); } /* Optionally do a "git push" */ } /* ** COMMAND: git ** ** Usage: %fossil git SUBCOMMAND ** ** Do incremental import or export operations between Fossil and Git. ** Subcommands: ** ** fossil git export MIRROR [OPTIONS] ** ** Write content from the Fossil repository into the Git repository ** in directory MIRROR. The Git repository is created if it does not ** already exist. If the Git repository does already exist, then ** new content added to fossil since the previous export is appended. ** ** Repeat this command whenever new checkins are added to the Fossil ** repository in order to reflect those changes into the mirror. ** ** The MIRROR directory will contain a subdirectory named ** ".mirror_state" that contains information that Fossil needs to ** do incremental exports. Do not attempt to manage or edit the files ** in that directory since doing so can disrupt future incremental ** exports. ** ** Options: ** --debug FILE Write fast-export text to FILE rather than ** piping it into "git fast-import". ** --limit N Add no more than N new check-ins to MIRROR. ** Useful for debugging ** ** fossil git import MIRROR ** ** TBD... */ void gitmirror_command(void){ char *zCmd; int nCmd; if( g.argc<3 ){ usage("export ARGS..."); } zCmd = g.argv[2]; nCmd = (int)strlen(zCmd); if( nCmd>2 && strncmp(zCmd,"export",nCmd)==0 ){ gitmirror_export_command(); }else if( nCmd>2 && strncmp(zCmd,"import",nCmd)==0 ){ fossil_fatal("not yet implemented - check back later"); }else { fossil_fatal("unknown subcommand \"%s\": should be one of " "\"export\", \"import\"", zCmd); } } |