Fossil SCM
Add -rename-trunk, -rename-branch, -rename-tag, -rename-rev, -rev-tags, and -no-rev-tags options to import command
Commit
d7b8b3e18328605ed0ce084b4a1eb344217306f6
Parent
45daaced43d792a…
1 file changed
+106
-32
+106
-32
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -34,10 +34,20 @@ | ||
| 34 | 34 | char isExe; /* True if executable */ |
| 35 | 35 | char isLink; /* True if symlink */ |
| 36 | 36 | }; |
| 37 | 37 | #endif |
| 38 | 38 | |
| 39 | +/* | |
| 40 | +** State information common to all import types. | |
| 41 | +*/ | |
| 42 | +static struct { | |
| 43 | + const char *zTrunkName; /* Name of trunk branch */ | |
| 44 | + const char *zBranchPre; /* Prepended to non-trunk branch names */ | |
| 45 | + const char *zBranchSuf; /* Appended to non-trunk branch names */ | |
| 46 | + const char *zTagPre; /* Prepended to non-trunk tag names */ | |
| 47 | + const char *zTagSuf; /* Appended to non-trunk tag names */ | |
| 48 | +} gimport; | |
| 39 | 49 | |
| 40 | 50 | /* |
| 41 | 51 | ** State information about an on-going fast-import parse. |
| 42 | 52 | */ |
| 43 | 53 | static struct { |
| @@ -198,11 +208,12 @@ | ||
| 198 | 208 | static void finish_tag(void){ |
| 199 | 209 | Blob record, cksum; |
| 200 | 210 | if( gg.zDate && gg.zTag && gg.zFrom && gg.zUser ){ |
| 201 | 211 | blob_zero(&record); |
| 202 | 212 | blob_appendf(&record, "D %s\n", gg.zDate); |
| 203 | - blob_appendf(&record, "T +%F %s\n", gg.zTag, gg.zFrom); | |
| 213 | + blob_appendf(&record, "T +%F%F%F %s\n", gimport.zTagPre, gg.zTag, | |
| 214 | + gimport.zTagSuf, gg.zFrom); | |
| 204 | 215 | blob_appendf(&record, "U %F\n", gg.zUser); |
| 205 | 216 | md5sum_blob(&record, &cksum); |
| 206 | 217 | blob_appendf(&record, "Z %b\n", &cksum); |
| 207 | 218 | fast_insert_content(&record, 0, 0, 1); |
| 208 | 219 | blob_reset(&cksum); |
| @@ -275,18 +286,21 @@ | ||
| 275 | 286 | |
| 276 | 287 | /* Add the required "T" cards to the manifest. Make sure they are added |
| 277 | 288 | ** in sorted order and without any duplicates. Otherwise, fossil will not |
| 278 | 289 | ** recognize the document as a valid manifest. */ |
| 279 | 290 | if( !gg.tagCommit && fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){ |
| 280 | - aTCard[nTCard++] = mprintf("T *branch * %F\n", gg.zBranch); | |
| 281 | - aTCard[nTCard++] = mprintf("T *sym-%F *\n", gg.zBranch); | |
| 291 | + aTCard[nTCard++] = mprintf("T *branch * %F%F%F\n", gimport.zBranchPre, | |
| 292 | + gg.zBranch, gimport.zBranchSuf); | |
| 293 | + aTCard[nTCard++] = mprintf("T *sym-%F%F%F *\n", gimport.zBranchPre, | |
| 294 | + gg.zBranch, gimport.zBranchSuf); | |
| 282 | 295 | if( zFromBranch ){ |
| 283 | - aTCard[nTCard++] = mprintf("T -sym-%F *\n", zFromBranch); | |
| 296 | + aTCard[nTCard++] = mprintf("T -sym-%F%F%F *\n", gimport.zBranchPre, | |
| 297 | + zFromBranch, gimport.zBranchSuf); | |
| 284 | 298 | } |
| 285 | 299 | } |
| 286 | 300 | if( gg.zFrom==0 ){ |
| 287 | - aTCard[nTCard++] = mprintf("T *sym-trunk *\n"); | |
| 301 | + aTCard[nTCard++] = mprintf("T *sym-%F *\n", gimport.zTrunkName); | |
| 288 | 302 | } |
| 289 | 303 | qsort(aTCard, nTCard, sizeof(char *), string_cmp); |
| 290 | 304 | for(i=0; i<nTCard; i++){ |
| 291 | 305 | if( i==0 || fossil_strcmp(aTCard[i-1], aTCard[i]) ){ |
| 292 | 306 | blob_appendf(&record, "%s", aTCard[i]); |
| @@ -313,11 +327,12 @@ | ||
| 313 | 327 | ** This behavior seems like a bug in git-fast-export, but it is easier |
| 314 | 328 | ** to work around the problem than to fix git-fast-export. |
| 315 | 329 | */ |
| 316 | 330 | if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){ |
| 317 | 331 | blob_appendf(&record, "D %s\n", gg.zDate); |
| 318 | - blob_appendf(&record, "T +sym-%F %s\n", gg.zBranch, gg.zPrevCheckin); | |
| 332 | + blob_appendf(&record, "T +sym-%F%F%F %s\n", gimport.zBranchPre, gg.zBranch, | |
| 333 | + gimport.zBranchSuf, gg.zPrevCheckin); | |
| 319 | 334 | blob_appendf(&record, "U %F\n", gg.zUser); |
| 320 | 335 | md5sum_blob(&record, &cksum); |
| 321 | 336 | blob_appendf(&record, "Z %b\n", &cksum); |
| 322 | 337 | db_multi_exec( |
| 323 | 338 | "INSERT OR REPLACE INTO xtag(tname, tcontent)" |
| @@ -749,11 +764,13 @@ | ||
| 749 | 764 | const char *zBranches; /* Name of branches folder in repo root */ |
| 750 | 765 | int lenBranches; /* String length of zBranches */ |
| 751 | 766 | const char *zTags; /* Name of tags folder in repo root */ |
| 752 | 767 | int lenTags; /* String length of zTags */ |
| 753 | 768 | Bag newBranches; /* Branches that were created in this revision */ |
| 754 | - int incrFlag; /* Add svn-rev-nn tags on every checkin */ | |
| 769 | + int revFlag; /* Add svn-rev-nn tags on every checkin */ | |
| 770 | + const char *zRevPre; /* Prepended to revision tag names */ | |
| 771 | + const char *zRevSuf; /* Appended to revision tag names */ | |
| 755 | 772 | } gsvn; |
| 756 | 773 | typedef struct { |
| 757 | 774 | char *zKey; |
| 758 | 775 | char *zVal; |
| 759 | 776 | } KeyVal; |
| @@ -1018,47 +1035,57 @@ | ||
| 1018 | 1035 | char *zParentBranch = |
| 1019 | 1036 | db_text(0, "SELECT tname FROM xbranches WHERE tid=%d", |
| 1020 | 1037 | parentBranch |
| 1021 | 1038 | ); |
| 1022 | 1039 | blob_appendf(&manifest, "P %s\n", zParentUuid); |
| 1023 | - blob_appendf(&manifest, "T *branch * %F\n", zBranch); | |
| 1024 | - blob_appendf(&manifest, "T *sym-%F *\n", zBranch); | |
| 1025 | - if( gsvn.incrFlag ){ | |
| 1026 | - blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 1040 | + blob_appendf(&manifest, "T *branch * %F%F%F\n", gimport.zBranchPre, | |
| 1041 | + zBranch, gimport.zBranchSuf); | |
| 1042 | + blob_appendf(&manifest, "T *sym-%F%F%F *\n", gimport.zBranchPre, | |
| 1043 | + zBranch, gimport.zBranchSuf); | |
| 1044 | + if( gsvn.revFlag ){ | |
| 1045 | + blob_appendf(&manifest, "T +sym-%Fr%d%F *\n", gimport.zTagPre, | |
| 1046 | + gsvn.rev, gimport.zTagSuf); | |
| 1027 | 1047 | } |
| 1028 | - blob_appendf(&manifest, "T -sym-%F *\n", zParentBranch); | |
| 1048 | + blob_appendf(&manifest, "T -sym-%F%F%F *\n", gimport.zBranchPre, | |
| 1049 | + zParentBranch, gimport.zBranchSuf); | |
| 1029 | 1050 | fossil_free(zParentBranch); |
| 1030 | 1051 | }else{ |
| 1031 | 1052 | char *zMergeUuid = rid_to_uuid(mergeRid); |
| 1032 | 1053 | blob_appendf(&manifest, "P %s %s\n", zParentUuid, zMergeUuid); |
| 1033 | - if( gsvn.incrFlag ){ | |
| 1034 | - blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 1054 | + if( gsvn.revFlag ){ | |
| 1055 | + blob_appendf(&manifest, "T +sym-%F%d%F *\n", gsvn.zRevPre, | |
| 1056 | + gsvn.rev, gsvn.zRevSuf); | |
| 1035 | 1057 | } |
| 1036 | 1058 | fossil_free(zMergeUuid); |
| 1037 | 1059 | } |
| 1038 | 1060 | fossil_free(zParentUuid); |
| 1039 | 1061 | }else{ |
| 1040 | - blob_appendf(&manifest, "T *branch * %F\n", zBranch); | |
| 1041 | - blob_appendf(&manifest, "T *sym-%F *\n", zBranch); | |
| 1042 | - if( gsvn.incrFlag ){ | |
| 1043 | - blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 1062 | + blob_appendf(&manifest, "T *branch * %F%F%F\n", | |
| 1063 | + gimport.zBranchPre, zBranch, gimport.zBranchSuf); | |
| 1064 | + blob_appendf(&manifest, "T *sym-%F%F%F *\n", gimport.zBranchPre, | |
| 1065 | + zBranch, gimport.zBranchSuf); | |
| 1066 | + if( gsvn.revFlag ){ | |
| 1067 | + blob_appendf(&manifest, "T +sym-%F%d%F *\n", gsvn.zRevPre, gsvn.rev, | |
| 1068 | + gsvn.zRevSuf); | |
| 1044 | 1069 | } |
| 1045 | 1070 | } |
| 1046 | 1071 | }else if( branchType==SVN_TAG ){ |
| 1047 | 1072 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1048 | 1073 | blob_reset(&manifest); |
| 1049 | 1074 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1050 | - blob_appendf(&manifest, "T +sym-%F %s\n", zBranch, zParentUuid); | |
| 1075 | + blob_appendf(&manifest, "T +sym-%F%F%F %s\n", gimport.zTagPre, zBranch, | |
| 1076 | + gimport.zTagSuf, zParentUuid); | |
| 1051 | 1077 | fossil_free(zParentUuid); |
| 1052 | 1078 | } |
| 1053 | 1079 | }else{ |
| 1054 | 1080 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1055 | 1081 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1056 | 1082 | if( branchType!=SVN_TAG ){ |
| 1057 | 1083 | blob_appendf(&manifest, "T +closed %s\n", zParentUuid); |
| 1058 | 1084 | }else{ |
| 1059 | - blob_appendf(&manifest, "T -sym-%F %s\n", zBranch, zParentUuid); | |
| 1085 | + blob_appendf(&manifest, "T -sym-%F%F%F %s\n", gimport.zBranchPre, | |
| 1086 | + zBranch, gimport.zBranchSuf, zParentUuid); | |
| 1060 | 1087 | } |
| 1061 | 1088 | fossil_free(zParentUuid); |
| 1062 | 1089 | } |
| 1063 | 1090 | if( gsvn.zUser ){ |
| 1064 | 1091 | blob_appendf(&manifest, "U %F\n", gsvn.zUser); |
| @@ -1495,31 +1522,43 @@ | ||
| 1495 | 1522 | ** |
| 1496 | 1523 | ** The following formats are currently understood by this command |
| 1497 | 1524 | ** |
| 1498 | 1525 | ** --git Import from the git-fast-export file format (default) |
| 1499 | 1526 | ** |
| 1500 | -** --svn Import from the svnadmin-dump file format. The default | |
| 1527 | +** --svn Import from the svnadmin-dump file format. The default | |
| 1501 | 1528 | ** behaviour (unless overridden by --flat) is to treat 3 |
| 1502 | 1529 | ** folders in the SVN root as special, following the |
| 1503 | -** common layout of SVN repositories. These are (by | |
| 1504 | -** default) trunk/, branches/ and tags/ | |
| 1530 | +** common layout of SVN repositories. These are (by | |
| 1531 | +** default) trunk/, branches/ and tags/. The SVN --deltas | |
| 1532 | +** format is supported but not required. | |
| 1505 | 1533 | ** Options: |
| 1506 | 1534 | ** --trunk FOLDER Name of trunk folder |
| 1507 | 1535 | ** --branches FOLDER Name of branches folder |
| 1508 | 1536 | ** --tags FOLDER Name of tags folder |
| 1509 | 1537 | ** --base PATH Path to project root in repository |
| 1510 | 1538 | ** --flat The whole dump is a single branch |
| 1539 | +** --rev-tags Tag each revision, implied by -i | |
| 1540 | +** --no-rev-tags Disables tagging effect of -i | |
| 1541 | +** --rename-rev PAT Rev tag names, default "svn-rev-%" | |
| 1511 | 1542 | ** |
| 1512 | 1543 | ** Common Options: |
| 1513 | -** -i|--incremental allow importing into an existing repository | |
| 1514 | -** -f|--force overwrite repository if already exists | |
| 1515 | -** -q|--quiet omit progress output | |
| 1516 | -** --no-rebuild skip the "rebuilding metadata" step | |
| 1517 | -** --no-vacuum skip the final VACUUM of the database file | |
| 1544 | +** -i|--incremental allow importing into an existing repository | |
| 1545 | +** -f|--force overwrite repository if already exists | |
| 1546 | +** -q|--quiet omit progress output | |
| 1547 | +** --no-rebuild skip the "rebuilding metadata" step | |
| 1548 | +** --no-vacuum skip the final VACUUM of the database file | |
| 1549 | +** --rename-trunk NAME use NAME as name of imported trunk branch | |
| 1550 | +** --rename-branch PAT rename all branch names using PAT pattern | |
| 1551 | +** --rename-tag PAT rename all tag names using PAT pattern | |
| 1518 | 1552 | ** |
| 1519 | 1553 | ** The --incremental option allows an existing repository to be extended |
| 1520 | -** with new content. | |
| 1554 | +** with new content. The --rename-* options may be useful to avoid name | |
| 1555 | +** conflicts when using the --incremental option. | |
| 1556 | +** | |
| 1557 | +** The argument to --rename-* contains one "%" character to be replaced | |
| 1558 | +** with the original name. For example, "--rename-tag svn-%-tag" renames | |
| 1559 | +** the tag called "release" to "svn-release-tag". | |
| 1521 | 1560 | ** |
| 1522 | 1561 | ** See also: export |
| 1523 | 1562 | */ |
| 1524 | 1563 | void import_cmd(void){ |
| 1525 | 1564 | char *zPassword; |
| @@ -1534,21 +1573,56 @@ | ||
| 1534 | 1573 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1535 | 1574 | |
| 1536 | 1575 | /* Options for --svn only */ |
| 1537 | 1576 | const char *zBase=""; |
| 1538 | 1577 | int flatFlag=0; |
| 1578 | + | |
| 1579 | + /* Interpret --rename-* options. Use a table to avoid code duplication. */ | |
| 1580 | + const struct { | |
| 1581 | + const char *zOpt, **varPre, *zDefaultPre, **varSuf, *zDefaultSuf; | |
| 1582 | + int format; /* 1=git, 2=svn, 3=any */ | |
| 1583 | + } renOpts[] = { | |
| 1584 | + {"rename-branch", &gimport.zBranchPre, "", &gimport.zBranchSuf, "", 3}, | |
| 1585 | + {"rename-tag" , &gimport.zTagPre , "", &gimport.zTagSuf , "", 3}, | |
| 1586 | + {"rename-rev" , &gsvn.zRevPre, "svn-rev-", &gsvn.zRevSuf , "", 2}, | |
| 1587 | + }, *renOpt = renOpts; | |
| 1588 | + int i; | |
| 1589 | + for( i = 0; i < sizeof(renOpts) / sizeof(*renOpts); ++i, ++renOpt ){ | |
| 1590 | + if( 1 << svnFlag & renOpt->format ){ | |
| 1591 | + const char *zArgument = find_option(renOpt->zOpt, 0, 1); | |
| 1592 | + if( zArgument ){ | |
| 1593 | + const char *sep = strchr(zArgument, '%'); | |
| 1594 | + if( !sep ){ | |
| 1595 | + fossil_fatal("missing '%%' in argument to --%s", renOpt->zOpt); | |
| 1596 | + }else if( strchr(sep + 1, '%') ){ | |
| 1597 | + fossil_fatal("multiple '%%' in argument to --%s", renOpt->zOpt); | |
| 1598 | + } | |
| 1599 | + *renOpt->varPre = fossil_malloc(sep - zArgument + 1); | |
| 1600 | + memcpy((char *)*renOpt->varPre, zArgument, sep - zArgument); | |
| 1601 | + ((char *)*renOpt->varPre)[sep - zArgument] = 0; | |
| 1602 | + *renOpt->varSuf = sep + 1; | |
| 1603 | + }else{ | |
| 1604 | + *renOpt->varPre = renOpt->zDefaultPre; | |
| 1605 | + *renOpt->varSuf = renOpt->zDefaultSuf; | |
| 1606 | + } | |
| 1607 | + } | |
| 1608 | + } | |
| 1609 | + if( !(gimport.zTrunkName = find_option("rename-trunk", 0, 1)) ){ | |
| 1610 | + gimport.zTrunkName = "trunk"; | |
| 1611 | + } | |
| 1539 | 1612 | |
| 1540 | 1613 | if( svnFlag ){ |
| 1541 | - /* Get --svn related options here, so verify_all_options() fail when svn | |
| 1542 | - * only option are specify with --git | |
| 1614 | + /* Get --svn related options here, so verify_all_options() fails when | |
| 1615 | + * svn-only options are specified with --git | |
| 1543 | 1616 | */ |
| 1544 | 1617 | zBase = find_option("base", 0, 1); |
| 1545 | 1618 | flatFlag = find_option("flat", 0, 0)!=0; |
| 1546 | 1619 | gsvn.zTrunk = find_option("trunk", 0, 1); |
| 1547 | 1620 | gsvn.zBranches = find_option("branches", 0, 1); |
| 1548 | 1621 | gsvn.zTags = find_option("tags", 0, 1); |
| 1549 | - gsvn.incrFlag = incrFlag; | |
| 1622 | + gsvn.revFlag = find_option("rev-tags", 0, 0) | |
| 1623 | + || (incrFlag && !find_option("no-rev-tags", 0, 0)); | |
| 1550 | 1624 | }else{ |
| 1551 | 1625 | find_option("git",0,0); /* Skip the --git option for now */ |
| 1552 | 1626 | } |
| 1553 | 1627 | verify_all_options(); |
| 1554 | 1628 | |
| 1555 | 1629 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -34,10 +34,20 @@ | |
| 34 | char isExe; /* True if executable */ |
| 35 | char isLink; /* True if symlink */ |
| 36 | }; |
| 37 | #endif |
| 38 | |
| 39 | |
| 40 | /* |
| 41 | ** State information about an on-going fast-import parse. |
| 42 | */ |
| 43 | static struct { |
| @@ -198,11 +208,12 @@ | |
| 198 | static void finish_tag(void){ |
| 199 | Blob record, cksum; |
| 200 | if( gg.zDate && gg.zTag && gg.zFrom && gg.zUser ){ |
| 201 | blob_zero(&record); |
| 202 | blob_appendf(&record, "D %s\n", gg.zDate); |
| 203 | blob_appendf(&record, "T +%F %s\n", gg.zTag, gg.zFrom); |
| 204 | blob_appendf(&record, "U %F\n", gg.zUser); |
| 205 | md5sum_blob(&record, &cksum); |
| 206 | blob_appendf(&record, "Z %b\n", &cksum); |
| 207 | fast_insert_content(&record, 0, 0, 1); |
| 208 | blob_reset(&cksum); |
| @@ -275,18 +286,21 @@ | |
| 275 | |
| 276 | /* Add the required "T" cards to the manifest. Make sure they are added |
| 277 | ** in sorted order and without any duplicates. Otherwise, fossil will not |
| 278 | ** recognize the document as a valid manifest. */ |
| 279 | if( !gg.tagCommit && fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){ |
| 280 | aTCard[nTCard++] = mprintf("T *branch * %F\n", gg.zBranch); |
| 281 | aTCard[nTCard++] = mprintf("T *sym-%F *\n", gg.zBranch); |
| 282 | if( zFromBranch ){ |
| 283 | aTCard[nTCard++] = mprintf("T -sym-%F *\n", zFromBranch); |
| 284 | } |
| 285 | } |
| 286 | if( gg.zFrom==0 ){ |
| 287 | aTCard[nTCard++] = mprintf("T *sym-trunk *\n"); |
| 288 | } |
| 289 | qsort(aTCard, nTCard, sizeof(char *), string_cmp); |
| 290 | for(i=0; i<nTCard; i++){ |
| 291 | if( i==0 || fossil_strcmp(aTCard[i-1], aTCard[i]) ){ |
| 292 | blob_appendf(&record, "%s", aTCard[i]); |
| @@ -313,11 +327,12 @@ | |
| 313 | ** This behavior seems like a bug in git-fast-export, but it is easier |
| 314 | ** to work around the problem than to fix git-fast-export. |
| 315 | */ |
| 316 | if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){ |
| 317 | blob_appendf(&record, "D %s\n", gg.zDate); |
| 318 | blob_appendf(&record, "T +sym-%F %s\n", gg.zBranch, gg.zPrevCheckin); |
| 319 | blob_appendf(&record, "U %F\n", gg.zUser); |
| 320 | md5sum_blob(&record, &cksum); |
| 321 | blob_appendf(&record, "Z %b\n", &cksum); |
| 322 | db_multi_exec( |
| 323 | "INSERT OR REPLACE INTO xtag(tname, tcontent)" |
| @@ -749,11 +764,13 @@ | |
| 749 | const char *zBranches; /* Name of branches folder in repo root */ |
| 750 | int lenBranches; /* String length of zBranches */ |
| 751 | const char *zTags; /* Name of tags folder in repo root */ |
| 752 | int lenTags; /* String length of zTags */ |
| 753 | Bag newBranches; /* Branches that were created in this revision */ |
| 754 | int incrFlag; /* Add svn-rev-nn tags on every checkin */ |
| 755 | } gsvn; |
| 756 | typedef struct { |
| 757 | char *zKey; |
| 758 | char *zVal; |
| 759 | } KeyVal; |
| @@ -1018,47 +1035,57 @@ | |
| 1018 | char *zParentBranch = |
| 1019 | db_text(0, "SELECT tname FROM xbranches WHERE tid=%d", |
| 1020 | parentBranch |
| 1021 | ); |
| 1022 | blob_appendf(&manifest, "P %s\n", zParentUuid); |
| 1023 | blob_appendf(&manifest, "T *branch * %F\n", zBranch); |
| 1024 | blob_appendf(&manifest, "T *sym-%F *\n", zBranch); |
| 1025 | if( gsvn.incrFlag ){ |
| 1026 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 1027 | } |
| 1028 | blob_appendf(&manifest, "T -sym-%F *\n", zParentBranch); |
| 1029 | fossil_free(zParentBranch); |
| 1030 | }else{ |
| 1031 | char *zMergeUuid = rid_to_uuid(mergeRid); |
| 1032 | blob_appendf(&manifest, "P %s %s\n", zParentUuid, zMergeUuid); |
| 1033 | if( gsvn.incrFlag ){ |
| 1034 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 1035 | } |
| 1036 | fossil_free(zMergeUuid); |
| 1037 | } |
| 1038 | fossil_free(zParentUuid); |
| 1039 | }else{ |
| 1040 | blob_appendf(&manifest, "T *branch * %F\n", zBranch); |
| 1041 | blob_appendf(&manifest, "T *sym-%F *\n", zBranch); |
| 1042 | if( gsvn.incrFlag ){ |
| 1043 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 1044 | } |
| 1045 | } |
| 1046 | }else if( branchType==SVN_TAG ){ |
| 1047 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1048 | blob_reset(&manifest); |
| 1049 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1050 | blob_appendf(&manifest, "T +sym-%F %s\n", zBranch, zParentUuid); |
| 1051 | fossil_free(zParentUuid); |
| 1052 | } |
| 1053 | }else{ |
| 1054 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1055 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1056 | if( branchType!=SVN_TAG ){ |
| 1057 | blob_appendf(&manifest, "T +closed %s\n", zParentUuid); |
| 1058 | }else{ |
| 1059 | blob_appendf(&manifest, "T -sym-%F %s\n", zBranch, zParentUuid); |
| 1060 | } |
| 1061 | fossil_free(zParentUuid); |
| 1062 | } |
| 1063 | if( gsvn.zUser ){ |
| 1064 | blob_appendf(&manifest, "U %F\n", gsvn.zUser); |
| @@ -1495,31 +1522,43 @@ | |
| 1495 | ** |
| 1496 | ** The following formats are currently understood by this command |
| 1497 | ** |
| 1498 | ** --git Import from the git-fast-export file format (default) |
| 1499 | ** |
| 1500 | ** --svn Import from the svnadmin-dump file format. The default |
| 1501 | ** behaviour (unless overridden by --flat) is to treat 3 |
| 1502 | ** folders in the SVN root as special, following the |
| 1503 | ** common layout of SVN repositories. These are (by |
| 1504 | ** default) trunk/, branches/ and tags/ |
| 1505 | ** Options: |
| 1506 | ** --trunk FOLDER Name of trunk folder |
| 1507 | ** --branches FOLDER Name of branches folder |
| 1508 | ** --tags FOLDER Name of tags folder |
| 1509 | ** --base PATH Path to project root in repository |
| 1510 | ** --flat The whole dump is a single branch |
| 1511 | ** |
| 1512 | ** Common Options: |
| 1513 | ** -i|--incremental allow importing into an existing repository |
| 1514 | ** -f|--force overwrite repository if already exists |
| 1515 | ** -q|--quiet omit progress output |
| 1516 | ** --no-rebuild skip the "rebuilding metadata" step |
| 1517 | ** --no-vacuum skip the final VACUUM of the database file |
| 1518 | ** |
| 1519 | ** The --incremental option allows an existing repository to be extended |
| 1520 | ** with new content. |
| 1521 | ** |
| 1522 | ** See also: export |
| 1523 | */ |
| 1524 | void import_cmd(void){ |
| 1525 | char *zPassword; |
| @@ -1534,21 +1573,56 @@ | |
| 1534 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1535 | |
| 1536 | /* Options for --svn only */ |
| 1537 | const char *zBase=""; |
| 1538 | int flatFlag=0; |
| 1539 | |
| 1540 | if( svnFlag ){ |
| 1541 | /* Get --svn related options here, so verify_all_options() fail when svn |
| 1542 | * only option are specify with --git |
| 1543 | */ |
| 1544 | zBase = find_option("base", 0, 1); |
| 1545 | flatFlag = find_option("flat", 0, 0)!=0; |
| 1546 | gsvn.zTrunk = find_option("trunk", 0, 1); |
| 1547 | gsvn.zBranches = find_option("branches", 0, 1); |
| 1548 | gsvn.zTags = find_option("tags", 0, 1); |
| 1549 | gsvn.incrFlag = incrFlag; |
| 1550 | }else{ |
| 1551 | find_option("git",0,0); /* Skip the --git option for now */ |
| 1552 | } |
| 1553 | verify_all_options(); |
| 1554 | |
| 1555 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -34,10 +34,20 @@ | |
| 34 | char isExe; /* True if executable */ |
| 35 | char isLink; /* True if symlink */ |
| 36 | }; |
| 37 | #endif |
| 38 | |
| 39 | /* |
| 40 | ** State information common to all import types. |
| 41 | */ |
| 42 | static struct { |
| 43 | const char *zTrunkName; /* Name of trunk branch */ |
| 44 | const char *zBranchPre; /* Prepended to non-trunk branch names */ |
| 45 | const char *zBranchSuf; /* Appended to non-trunk branch names */ |
| 46 | const char *zTagPre; /* Prepended to non-trunk tag names */ |
| 47 | const char *zTagSuf; /* Appended to non-trunk tag names */ |
| 48 | } gimport; |
| 49 | |
| 50 | /* |
| 51 | ** State information about an on-going fast-import parse. |
| 52 | */ |
| 53 | static struct { |
| @@ -198,11 +208,12 @@ | |
| 208 | static void finish_tag(void){ |
| 209 | Blob record, cksum; |
| 210 | if( gg.zDate && gg.zTag && gg.zFrom && gg.zUser ){ |
| 211 | blob_zero(&record); |
| 212 | blob_appendf(&record, "D %s\n", gg.zDate); |
| 213 | blob_appendf(&record, "T +%F%F%F %s\n", gimport.zTagPre, gg.zTag, |
| 214 | gimport.zTagSuf, gg.zFrom); |
| 215 | blob_appendf(&record, "U %F\n", gg.zUser); |
| 216 | md5sum_blob(&record, &cksum); |
| 217 | blob_appendf(&record, "Z %b\n", &cksum); |
| 218 | fast_insert_content(&record, 0, 0, 1); |
| 219 | blob_reset(&cksum); |
| @@ -275,18 +286,21 @@ | |
| 286 | |
| 287 | /* Add the required "T" cards to the manifest. Make sure they are added |
| 288 | ** in sorted order and without any duplicates. Otherwise, fossil will not |
| 289 | ** recognize the document as a valid manifest. */ |
| 290 | if( !gg.tagCommit && fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){ |
| 291 | aTCard[nTCard++] = mprintf("T *branch * %F%F%F\n", gimport.zBranchPre, |
| 292 | gg.zBranch, gimport.zBranchSuf); |
| 293 | aTCard[nTCard++] = mprintf("T *sym-%F%F%F *\n", gimport.zBranchPre, |
| 294 | gg.zBranch, gimport.zBranchSuf); |
| 295 | if( zFromBranch ){ |
| 296 | aTCard[nTCard++] = mprintf("T -sym-%F%F%F *\n", gimport.zBranchPre, |
| 297 | zFromBranch, gimport.zBranchSuf); |
| 298 | } |
| 299 | } |
| 300 | if( gg.zFrom==0 ){ |
| 301 | aTCard[nTCard++] = mprintf("T *sym-%F *\n", gimport.zTrunkName); |
| 302 | } |
| 303 | qsort(aTCard, nTCard, sizeof(char *), string_cmp); |
| 304 | for(i=0; i<nTCard; i++){ |
| 305 | if( i==0 || fossil_strcmp(aTCard[i-1], aTCard[i]) ){ |
| 306 | blob_appendf(&record, "%s", aTCard[i]); |
| @@ -313,11 +327,12 @@ | |
| 327 | ** This behavior seems like a bug in git-fast-export, but it is easier |
| 328 | ** to work around the problem than to fix git-fast-export. |
| 329 | */ |
| 330 | if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){ |
| 331 | blob_appendf(&record, "D %s\n", gg.zDate); |
| 332 | blob_appendf(&record, "T +sym-%F%F%F %s\n", gimport.zBranchPre, gg.zBranch, |
| 333 | gimport.zBranchSuf, gg.zPrevCheckin); |
| 334 | blob_appendf(&record, "U %F\n", gg.zUser); |
| 335 | md5sum_blob(&record, &cksum); |
| 336 | blob_appendf(&record, "Z %b\n", &cksum); |
| 337 | db_multi_exec( |
| 338 | "INSERT OR REPLACE INTO xtag(tname, tcontent)" |
| @@ -749,11 +764,13 @@ | |
| 764 | const char *zBranches; /* Name of branches folder in repo root */ |
| 765 | int lenBranches; /* String length of zBranches */ |
| 766 | const char *zTags; /* Name of tags folder in repo root */ |
| 767 | int lenTags; /* String length of zTags */ |
| 768 | Bag newBranches; /* Branches that were created in this revision */ |
| 769 | int revFlag; /* Add svn-rev-nn tags on every checkin */ |
| 770 | const char *zRevPre; /* Prepended to revision tag names */ |
| 771 | const char *zRevSuf; /* Appended to revision tag names */ |
| 772 | } gsvn; |
| 773 | typedef struct { |
| 774 | char *zKey; |
| 775 | char *zVal; |
| 776 | } KeyVal; |
| @@ -1018,47 +1035,57 @@ | |
| 1035 | char *zParentBranch = |
| 1036 | db_text(0, "SELECT tname FROM xbranches WHERE tid=%d", |
| 1037 | parentBranch |
| 1038 | ); |
| 1039 | blob_appendf(&manifest, "P %s\n", zParentUuid); |
| 1040 | blob_appendf(&manifest, "T *branch * %F%F%F\n", gimport.zBranchPre, |
| 1041 | zBranch, gimport.zBranchSuf); |
| 1042 | blob_appendf(&manifest, "T *sym-%F%F%F *\n", gimport.zBranchPre, |
| 1043 | zBranch, gimport.zBranchSuf); |
| 1044 | if( gsvn.revFlag ){ |
| 1045 | blob_appendf(&manifest, "T +sym-%Fr%d%F *\n", gimport.zTagPre, |
| 1046 | gsvn.rev, gimport.zTagSuf); |
| 1047 | } |
| 1048 | blob_appendf(&manifest, "T -sym-%F%F%F *\n", gimport.zBranchPre, |
| 1049 | zParentBranch, gimport.zBranchSuf); |
| 1050 | fossil_free(zParentBranch); |
| 1051 | }else{ |
| 1052 | char *zMergeUuid = rid_to_uuid(mergeRid); |
| 1053 | blob_appendf(&manifest, "P %s %s\n", zParentUuid, zMergeUuid); |
| 1054 | if( gsvn.revFlag ){ |
| 1055 | blob_appendf(&manifest, "T +sym-%F%d%F *\n", gsvn.zRevPre, |
| 1056 | gsvn.rev, gsvn.zRevSuf); |
| 1057 | } |
| 1058 | fossil_free(zMergeUuid); |
| 1059 | } |
| 1060 | fossil_free(zParentUuid); |
| 1061 | }else{ |
| 1062 | blob_appendf(&manifest, "T *branch * %F%F%F\n", |
| 1063 | gimport.zBranchPre, zBranch, gimport.zBranchSuf); |
| 1064 | blob_appendf(&manifest, "T *sym-%F%F%F *\n", gimport.zBranchPre, |
| 1065 | zBranch, gimport.zBranchSuf); |
| 1066 | if( gsvn.revFlag ){ |
| 1067 | blob_appendf(&manifest, "T +sym-%F%d%F *\n", gsvn.zRevPre, gsvn.rev, |
| 1068 | gsvn.zRevSuf); |
| 1069 | } |
| 1070 | } |
| 1071 | }else if( branchType==SVN_TAG ){ |
| 1072 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1073 | blob_reset(&manifest); |
| 1074 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1075 | blob_appendf(&manifest, "T +sym-%F%F%F %s\n", gimport.zTagPre, zBranch, |
| 1076 | gimport.zTagSuf, zParentUuid); |
| 1077 | fossil_free(zParentUuid); |
| 1078 | } |
| 1079 | }else{ |
| 1080 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1081 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1082 | if( branchType!=SVN_TAG ){ |
| 1083 | blob_appendf(&manifest, "T +closed %s\n", zParentUuid); |
| 1084 | }else{ |
| 1085 | blob_appendf(&manifest, "T -sym-%F%F%F %s\n", gimport.zBranchPre, |
| 1086 | zBranch, gimport.zBranchSuf, zParentUuid); |
| 1087 | } |
| 1088 | fossil_free(zParentUuid); |
| 1089 | } |
| 1090 | if( gsvn.zUser ){ |
| 1091 | blob_appendf(&manifest, "U %F\n", gsvn.zUser); |
| @@ -1495,31 +1522,43 @@ | |
| 1522 | ** |
| 1523 | ** The following formats are currently understood by this command |
| 1524 | ** |
| 1525 | ** --git Import from the git-fast-export file format (default) |
| 1526 | ** |
| 1527 | ** --svn Import from the svnadmin-dump file format. The default |
| 1528 | ** behaviour (unless overridden by --flat) is to treat 3 |
| 1529 | ** folders in the SVN root as special, following the |
| 1530 | ** common layout of SVN repositories. These are (by |
| 1531 | ** default) trunk/, branches/ and tags/. The SVN --deltas |
| 1532 | ** format is supported but not required. |
| 1533 | ** Options: |
| 1534 | ** --trunk FOLDER Name of trunk folder |
| 1535 | ** --branches FOLDER Name of branches folder |
| 1536 | ** --tags FOLDER Name of tags folder |
| 1537 | ** --base PATH Path to project root in repository |
| 1538 | ** --flat The whole dump is a single branch |
| 1539 | ** --rev-tags Tag each revision, implied by -i |
| 1540 | ** --no-rev-tags Disables tagging effect of -i |
| 1541 | ** --rename-rev PAT Rev tag names, default "svn-rev-%" |
| 1542 | ** |
| 1543 | ** Common Options: |
| 1544 | ** -i|--incremental allow importing into an existing repository |
| 1545 | ** -f|--force overwrite repository if already exists |
| 1546 | ** -q|--quiet omit progress output |
| 1547 | ** --no-rebuild skip the "rebuilding metadata" step |
| 1548 | ** --no-vacuum skip the final VACUUM of the database file |
| 1549 | ** --rename-trunk NAME use NAME as name of imported trunk branch |
| 1550 | ** --rename-branch PAT rename all branch names using PAT pattern |
| 1551 | ** --rename-tag PAT rename all tag names using PAT pattern |
| 1552 | ** |
| 1553 | ** The --incremental option allows an existing repository to be extended |
| 1554 | ** with new content. The --rename-* options may be useful to avoid name |
| 1555 | ** conflicts when using the --incremental option. |
| 1556 | ** |
| 1557 | ** The argument to --rename-* contains one "%" character to be replaced |
| 1558 | ** with the original name. For example, "--rename-tag svn-%-tag" renames |
| 1559 | ** the tag called "release" to "svn-release-tag". |
| 1560 | ** |
| 1561 | ** See also: export |
| 1562 | */ |
| 1563 | void import_cmd(void){ |
| 1564 | char *zPassword; |
| @@ -1534,21 +1573,56 @@ | |
| 1573 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1574 | |
| 1575 | /* Options for --svn only */ |
| 1576 | const char *zBase=""; |
| 1577 | int flatFlag=0; |
| 1578 | |
| 1579 | /* Interpret --rename-* options. Use a table to avoid code duplication. */ |
| 1580 | const struct { |
| 1581 | const char *zOpt, **varPre, *zDefaultPre, **varSuf, *zDefaultSuf; |
| 1582 | int format; /* 1=git, 2=svn, 3=any */ |
| 1583 | } renOpts[] = { |
| 1584 | {"rename-branch", &gimport.zBranchPre, "", &gimport.zBranchSuf, "", 3}, |
| 1585 | {"rename-tag" , &gimport.zTagPre , "", &gimport.zTagSuf , "", 3}, |
| 1586 | {"rename-rev" , &gsvn.zRevPre, "svn-rev-", &gsvn.zRevSuf , "", 2}, |
| 1587 | }, *renOpt = renOpts; |
| 1588 | int i; |
| 1589 | for( i = 0; i < sizeof(renOpts) / sizeof(*renOpts); ++i, ++renOpt ){ |
| 1590 | if( 1 << svnFlag & renOpt->format ){ |
| 1591 | const char *zArgument = find_option(renOpt->zOpt, 0, 1); |
| 1592 | if( zArgument ){ |
| 1593 | const char *sep = strchr(zArgument, '%'); |
| 1594 | if( !sep ){ |
| 1595 | fossil_fatal("missing '%%' in argument to --%s", renOpt->zOpt); |
| 1596 | }else if( strchr(sep + 1, '%') ){ |
| 1597 | fossil_fatal("multiple '%%' in argument to --%s", renOpt->zOpt); |
| 1598 | } |
| 1599 | *renOpt->varPre = fossil_malloc(sep - zArgument + 1); |
| 1600 | memcpy((char *)*renOpt->varPre, zArgument, sep - zArgument); |
| 1601 | ((char *)*renOpt->varPre)[sep - zArgument] = 0; |
| 1602 | *renOpt->varSuf = sep + 1; |
| 1603 | }else{ |
| 1604 | *renOpt->varPre = renOpt->zDefaultPre; |
| 1605 | *renOpt->varSuf = renOpt->zDefaultSuf; |
| 1606 | } |
| 1607 | } |
| 1608 | } |
| 1609 | if( !(gimport.zTrunkName = find_option("rename-trunk", 0, 1)) ){ |
| 1610 | gimport.zTrunkName = "trunk"; |
| 1611 | } |
| 1612 | |
| 1613 | if( svnFlag ){ |
| 1614 | /* Get --svn related options here, so verify_all_options() fails when |
| 1615 | * svn-only options are specified with --git |
| 1616 | */ |
| 1617 | zBase = find_option("base", 0, 1); |
| 1618 | flatFlag = find_option("flat", 0, 0)!=0; |
| 1619 | gsvn.zTrunk = find_option("trunk", 0, 1); |
| 1620 | gsvn.zBranches = find_option("branches", 0, 1); |
| 1621 | gsvn.zTags = find_option("tags", 0, 1); |
| 1622 | gsvn.revFlag = find_option("rev-tags", 0, 0) |
| 1623 | || (incrFlag && !find_option("no-rev-tags", 0, 0)); |
| 1624 | }else{ |
| 1625 | find_option("git",0,0); /* Skip the --git option for now */ |
| 1626 | } |
| 1627 | verify_all_options(); |
| 1628 | |
| 1629 |