Fossil SCM
Options to set trunk/branches/tags folder names and project repository root (filter). Various fixes
Commit
f67cb93fa6612082c6bb4a901d38500bf2df7b8a
Parent
59cc1242b3640e4…
1 file changed
+84
-34
+84
-34
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -725,10 +725,17 @@ | ||
| 725 | 725 | char *zBranch; /* Name of a branch for a commit */ |
| 726 | 726 | char *zDate; /* Date/time stamp */ |
| 727 | 727 | char *zUser; /* User name */ |
| 728 | 728 | char *zComment; /* Comment of a commit */ |
| 729 | 729 | int flatFlag; /* True if whole repo is a single file tree */ |
| 730 | + const char *zTrunk; /* Name of trunk folder in repo root */ | |
| 731 | + int lenTrunk; /* String length of zTrunk */ | |
| 732 | + const char *zBranches; /* Name of branches folder in repo root */ | |
| 733 | + int lenBranches; /* String length of zBranches */ | |
| 734 | + const char *zTags; /* Name of tags folder in repo root */ | |
| 735 | + int lenTags; /* String length of zTags */ | |
| 736 | + Blob filter; /* Path to repo root */ | |
| 730 | 737 | } gsvn; |
| 731 | 738 | typedef struct { |
| 732 | 739 | const char *zKey; |
| 733 | 740 | const char *zVal; |
| 734 | 741 | } KeyVal; |
| @@ -896,11 +903,11 @@ | ||
| 896 | 903 | Blob manifest; |
| 897 | 904 | static Stmt insRev; |
| 898 | 905 | static Stmt qParent; |
| 899 | 906 | static Stmt qFiles; |
| 900 | 907 | static Stmt qTags; |
| 901 | - char zFilter[200]; | |
| 908 | + int nBaseFilter; | |
| 902 | 909 | int nFilter; |
| 903 | 910 | int rid; |
| 904 | 911 | const char *zParentBranch = 0; |
| 905 | 912 | Blob mcksum; |
| 906 | 913 | |
| @@ -910,13 +917,11 @@ | ||
| 910 | 917 | db_static_prepare(&qParent, "SELECT tuuid, tbranch FROM xrevisions " |
| 911 | 918 | "WHERE trev=:rev"); |
| 912 | 919 | db_static_prepare(&qFiles, "SELECT tpath, trid, tperm FROM xfiles " |
| 913 | 920 | "WHERE tpath GLOB :filter ORDER BY tpath"); |
| 914 | 921 | db_static_prepare(&qTags, "SELECT ttag FROM xtags WHERE trev=:rev"); |
| 915 | - if( db_int(0, "SELECT 1 FROM xfiles LIMIT 1")==0 ){ return; } | |
| 916 | 922 | if( !gsvn.flatFlag ){ |
| 917 | - if( gsvn.zBranch==0 || gsvn.zBranch[0]=='\0' ){ return; } | |
| 918 | 923 | if( gsvn.parent<0 ){ |
| 919 | 924 | gsvn.parent = db_int(-1, "SELECT ifnull(max(trev),-1) FROM xrevisions " |
| 920 | 925 | "WHERE tbranch=%Q", gsvn.zBranch); |
| 921 | 926 | } |
| 922 | 927 | db_bind_int(&insRev, ":rev", gsvn.rev); |
| @@ -934,27 +939,28 @@ | ||
| 934 | 939 | blob_appendf(&manifest, "C %F\n", gsvn.zComment); |
| 935 | 940 | }else{ |
| 936 | 941 | blob_append(&manifest, "C (no\\scomment)\n", 16); |
| 937 | 942 | } |
| 938 | 943 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 939 | - if( strncmp(gsvn.zBranch, "trunk", 5)==0 ){ | |
| 940 | - memcpy(zFilter, "trunk/*", 8); | |
| 941 | - nFilter = 6; | |
| 944 | + nBaseFilter = blob_size(&gsvn.filter); | |
| 945 | + if( strcmp(gsvn.zBranch, gsvn.zTrunk)==0 ){ | |
| 946 | + blob_appendf(&gsvn.filter, "%s*", gsvn.zTrunk); | |
| 942 | 947 | }else{ |
| 943 | - sqlite3_snprintf(sizeof(zFilter), zFilter, "branches/%s/*", gsvn.zBranch); | |
| 944 | - nFilter = strlen(zFilter)-1; | |
| 948 | + blob_appendf(&gsvn.filter, "%s%s/*", gsvn.zBranches, gsvn.zBranch); | |
| 945 | 949 | } |
| 946 | - db_bind_text(&qFiles, ":filter", zFilter); | |
| 950 | + db_bind_text(&qFiles, ":filter", blob_str(&gsvn.filter)); | |
| 951 | + nFilter = blob_size(&gsvn.filter); | |
| 947 | 952 | while( db_step(&qFiles)==SQLITE_ROW ){ |
| 948 | 953 | const char *zFile = db_column_text(&qFiles, 0); |
| 949 | 954 | int rid = db_column_int(&qFiles, 1); |
| 950 | 955 | const char *zPerm = db_column_text(&qFiles, 2); |
| 951 | 956 | const char *zUuid; |
| 952 | 957 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 953 | 958 | blob_appendf(&manifest, "F %F %s %s\n", zFile+nFilter, zUuid, zPerm); |
| 954 | 959 | fossil_free(zUuid); |
| 955 | 960 | } |
| 961 | + blob_resize(&gsvn.filter, nBaseFilter); | |
| 956 | 962 | if( gsvn.parent>=0 ){ |
| 957 | 963 | const char *zParentUuid; |
| 958 | 964 | db_bind_int(&qParent, ":rev", gsvn.parent); |
| 959 | 965 | db_step(&qParent); |
| 960 | 966 | zParentUuid = db_column_text(&qParent, 0); |
| @@ -1016,11 +1022,11 @@ | ||
| 1016 | 1022 | } |
| 1017 | 1023 | zDiff += 4; |
| 1018 | 1024 | blob_zero(pOut); |
| 1019 | 1025 | while( zDiff<(blob_buffer(pDiff)+blob_size(pDiff)) ){ |
| 1020 | 1026 | u64 offSrc = svn_get_varint(&zDiff); |
| 1021 | - u64 lenSrc = svn_get_varint(&zDiff); | |
| 1027 | + /*u64 lenSrc =*/ svn_get_varint(&zDiff); | |
| 1022 | 1028 | u64 lenOut = svn_get_varint(&zDiff); |
| 1023 | 1029 | u64 lenInst = svn_get_varint(&zDiff); |
| 1024 | 1030 | u64 lenData = svn_get_varint(&zDiff); |
| 1025 | 1031 | const char *zInst = zDiff; |
| 1026 | 1032 | const char *zData = zInst+lenInst; |
| @@ -1063,10 +1069,11 @@ | ||
| 1063 | 1069 | const char *zTemp; |
| 1064 | 1070 | const char *zUuid; |
| 1065 | 1071 | Stmt addHist; |
| 1066 | 1072 | Stmt insTag; |
| 1067 | 1073 | Stmt cpyPath; |
| 1074 | + int bHasFiles; | |
| 1068 | 1075 | |
| 1069 | 1076 | /* version */ |
| 1070 | 1077 | if( svn_read_rec(pIn, &rec) |
| 1071 | 1078 | && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ |
| 1072 | 1079 | ver = atoi(zTemp); |
| @@ -1099,11 +1106,11 @@ | ||
| 1099 | 1106 | ); |
| 1100 | 1107 | gsvn.rev = -1; |
| 1101 | 1108 | while( svn_read_rec(pIn, &rec) ){ |
| 1102 | 1109 | if( (zTemp = svn_find_header(rec, "Revision-number")) ){ /* revision node */ |
| 1103 | 1110 | /* finish previous revision */ |
| 1104 | - if( gsvn.rev>=0 ){ | |
| 1111 | + if( bHasFiles ){ | |
| 1105 | 1112 | svn_create_manifest(); |
| 1106 | 1113 | fossil_free(gsvn.zUser); |
| 1107 | 1114 | fossil_free(gsvn.zComment); |
| 1108 | 1115 | fossil_free(gsvn.zDate); |
| 1109 | 1116 | fossil_free(gsvn.zBranch); |
| @@ -1113,10 +1120,11 @@ | ||
| 1113 | 1120 | gsvn.zUser = mprintf("%s", svn_find_prop(rec, "svn:author")); |
| 1114 | 1121 | gsvn.zComment = mprintf("%s", svn_find_prop(rec, "svn:log")); |
| 1115 | 1122 | gsvn.zDate = date_in_standard_format(svn_find_prop(rec, "svn:date")); |
| 1116 | 1123 | gsvn.parent = -1; |
| 1117 | 1124 | gsvn.zBranch = 0; |
| 1125 | + bHasFiles = 0; | |
| 1118 | 1126 | fossil_print("\rImporting SVN revision: %d", gsvn.rev); |
| 1119 | 1127 | db_bind_int(&addHist, ":rev", gsvn.rev); |
| 1120 | 1128 | db_bind_int(&cpyPath, ":rev", gsvn.rev); |
| 1121 | 1129 | }else |
| 1122 | 1130 | if( (zTemp = svn_find_header(rec, "Node-path")) ){ /* file/dir node */ |
| @@ -1137,27 +1145,38 @@ | ||
| 1137 | 1145 | }else{ |
| 1138 | 1146 | fossil_fatal("Missing copyfrom-rev"); |
| 1139 | 1147 | } |
| 1140 | 1148 | } |
| 1141 | 1149 | if( !gsvn.flatFlag ){ |
| 1142 | - if( strncmp(zPath, "branches/", 9)==0 ){ | |
| 1143 | - int nBranch; | |
| 1144 | - zTemp = zPath+9; | |
| 1150 | + if( strncmp(zPath, gsvn.zBranches, gsvn.lenBranches)==0 ){ | |
| 1151 | + int lenBranch; | |
| 1152 | + zTemp = zPath+gsvn.lenBranches; | |
| 1145 | 1153 | while( *zTemp && *zTemp!='/' ){ zTemp++; } |
| 1146 | - nBranch = zTemp-zPath+9; | |
| 1147 | - gsvn.zBranch = fossil_malloc(nBranch+1); | |
| 1148 | - memcpy(gsvn.zBranch, zPath+9, nBranch); | |
| 1149 | - gsvn.zBranch[nBranch] = '\0'; | |
| 1150 | - }else | |
| 1151 | - if( strncmp(zPath, "trunk/", 6)==0 ){ | |
| 1152 | - gsvn.zBranch = mprintf("trunk"); | |
| 1153 | - }else | |
| 1154 | - if( strncmp(zPath, "tags/", 5)!=0 | |
| 1155 | - && strcmp(zPath, "branches")!=0 | |
| 1156 | - && strcmp(zPath, "trunk")!=0 | |
| 1157 | - && strcmp(zPath, "tags")!=0){ | |
| 1158 | - fossil_fatal("Write outside repository layout: %s", zPath); | |
| 1154 | + lenBranch = zTemp-zPath-gsvn.lenBranches; | |
| 1155 | + zTemp = zPath+gsvn.lenBranches; | |
| 1156 | + if( gsvn.zBranch!=0 ){ | |
| 1157 | + if( strncmp(zTemp, gsvn.zBranch, lenBranch)!=0 ){ | |
| 1158 | + fossil_fatal("Commit to multiple branches"); | |
| 1159 | + } | |
| 1160 | + }else{ | |
| 1161 | + gsvn.zBranch = fossil_malloc(lenBranch+1); | |
| 1162 | + memcpy(gsvn.zBranch, zTemp, lenBranch); | |
| 1163 | + gsvn.zBranch[lenBranch] = '\0'; | |
| 1164 | + bHasFiles = 1; | |
| 1165 | + } | |
| 1166 | + }else | |
| 1167 | + if( strncmp(zPath, gsvn.zTrunk, gsvn.lenTrunk)==0 ){ | |
| 1168 | + if( gsvn.zBranch!=0 ){ | |
| 1169 | + if( strncmp(gsvn.zTrunk, gsvn.zBranch, gsvn.lenTrunk-1)!=0 ){ | |
| 1170 | + fossil_fatal("Commit to multiple branches"); | |
| 1171 | + } | |
| 1172 | + }else{ | |
| 1173 | + gsvn.zBranch = fossil_malloc(gsvn.lenTrunk); | |
| 1174 | + memcpy(gsvn.zBranch, gsvn.zTrunk, gsvn.lenTrunk-1); | |
| 1175 | + gsvn.zBranch[gsvn.lenTrunk-1] = '\0'; | |
| 1176 | + bHasFiles = 1; | |
| 1177 | + } | |
| 1159 | 1178 | } |
| 1160 | 1179 | } |
| 1161 | 1180 | if( strncmp(zAction, "delete", 6)==0 |
| 1162 | 1181 | || strncmp(zAction, "replace", 7)==0 ) |
| 1163 | 1182 | { |
| @@ -1178,17 +1197,17 @@ | ||
| 1178 | 1197 | db_bind_text(&cpyPath, ":path", zPath); |
| 1179 | 1198 | db_bind_text(&cpyPath, ":srcpath", zSrcPath); |
| 1180 | 1199 | db_step(&cpyPath); |
| 1181 | 1200 | db_reset(&cpyPath); |
| 1182 | 1201 | if( !gsvn.flatFlag ){ |
| 1183 | - if( strncmp(zPath, "branches/", 9)==0 ){ | |
| 1184 | - zTemp = zPath+9+strlen(gsvn.zBranch); | |
| 1202 | + if( strncmp(zPath, gsvn.zBranches, gsvn.lenBranches)==0 ){ | |
| 1203 | + zTemp = zPath+gsvn.lenBranches+strlen(gsvn.zBranch); | |
| 1185 | 1204 | if( *zTemp==0 ){ |
| 1186 | 1205 | gsvn.parent = srcRev; |
| 1187 | 1206 | } |
| 1188 | - }else if( strncmp(zPath, "tags/", 5)==0 ){ | |
| 1189 | - zTemp = zPath+5; | |
| 1207 | + }else if( strncmp(zPath, gsvn.zTags, gsvn.lenTags)==0 ){ | |
| 1208 | + zTemp = zPath+gsvn.lenTags; | |
| 1190 | 1209 | db_bind_int(&insTag, ":rev", srcRev); |
| 1191 | 1210 | db_bind_text(&insTag, ":tag", zTemp); |
| 1192 | 1211 | db_step(&insTag); |
| 1193 | 1212 | db_reset(&insTag); |
| 1194 | 1213 | } |
| @@ -1278,14 +1297,20 @@ | ||
| 1278 | 1297 | ** |
| 1279 | 1298 | ** The following formats are currently understood by this command |
| 1280 | 1299 | ** |
| 1281 | 1300 | ** git Import from the git-fast-export file format |
| 1282 | 1301 | ** |
| 1283 | -** svn Import from the svnadmin-dump file format | |
| 1302 | +** svn Import from the svnadmin-dump file format. The default | |
| 1303 | +** behaviour is to treat 3 folders in the SVN root as special, | |
| 1304 | +** following the common layout of SVN repositories. These are | |
| 1305 | +** (by default) trunk/, branches/ and tags/ | |
| 1284 | 1306 | ** Options: |
| 1285 | -** --flat The whole dump is a single branch. The default | |
| 1286 | -** is to use the trunk/branches/tags svn layout | |
| 1307 | +** --trunk FOLDER Name of trunk folder | |
| 1308 | +** --branches FOLDER Name of branches folder | |
| 1309 | +** --tags FOLDER Name of tags folder | |
| 1310 | +** --fiter PATH Path to project root in repository | |
| 1311 | +** --flat The whole dump is a single branch | |
| 1287 | 1312 | ** |
| 1288 | 1313 | ** The --incremental option allows an existing repository to be extended |
| 1289 | 1314 | ** with new content. |
| 1290 | 1315 | ** |
| 1291 | 1316 | ** Options: |
| @@ -1295,12 +1320,16 @@ | ||
| 1295 | 1320 | */ |
| 1296 | 1321 | void import_cmd(void){ |
| 1297 | 1322 | char *zPassword; |
| 1298 | 1323 | FILE *pIn; |
| 1299 | 1324 | Stmt q; |
| 1325 | + const char *zFilter = find_option("filter", 0, 1); | |
| 1300 | 1326 | int forceFlag = find_option("force", "f", 0)!=0; |
| 1301 | 1327 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1328 | + gsvn.zTrunk = find_option("trunk", 0, 1); | |
| 1329 | + gsvn.zBranches = find_option("branches", 0, 1); | |
| 1330 | + gsvn.zTags = find_option("tags", 0, 1); | |
| 1302 | 1331 | gsvn.flatFlag = find_option("flat", 0, 0)!=0; |
| 1303 | 1332 | |
| 1304 | 1333 | verify_all_options(); |
| 1305 | 1334 | if( g.argc!=4 && g.argc!=5 ){ |
| 1306 | 1335 | usage("FORMAT REPOSITORY-NAME"); |
| @@ -1378,10 +1407,31 @@ | ||
| 1378 | 1407 | " VALUES(new.tpath, new.trid, new.tperm); END;" |
| 1379 | 1408 | "CREATE TEMP TABLE xtags(" |
| 1380 | 1409 | " trev INT, ttag TEXT" |
| 1381 | 1410 | ");" |
| 1382 | 1411 | ); |
| 1412 | + if( gsvn.zTrunk==0 ){ gsvn.zTrunk = "trunk/"; } | |
| 1413 | + if( gsvn.zBranches==0 ){ gsvn.zBranches = "branches/"; } | |
| 1414 | + if( gsvn.zTags==0 ){ gsvn.zTags = "tags/"; } | |
| 1415 | + gsvn.lenTrunk = strlen(gsvn.zTrunk); | |
| 1416 | + gsvn.lenBranches = strlen(gsvn.zBranches); | |
| 1417 | + gsvn.lenTags = strlen(gsvn.zTags); | |
| 1418 | + if( gsvn.zTrunk[gsvn.lenTrunk-1]!='/' ){ | |
| 1419 | + gsvn.zTrunk = mprintf("%s/", gsvn.zTrunk); | |
| 1420 | + gsvn.lenTrunk++; | |
| 1421 | + } | |
| 1422 | + if( gsvn.zBranches[gsvn.lenBranches-1]!='/' ){ | |
| 1423 | + gsvn.zBranches = mprintf("%s/", gsvn.zBranches); | |
| 1424 | + gsvn.lenBranches++; | |
| 1425 | + } | |
| 1426 | + if( gsvn.zTags[gsvn.lenTags-1]!='/' ){ | |
| 1427 | + gsvn.zTags = mprintf("%s/", gsvn.zTags); | |
| 1428 | + gsvn.lenTags++; | |
| 1429 | + } | |
| 1430 | + if( zFilter==0 ){ zFilter = ""; } | |
| 1431 | + blob_zero(&gsvn.filter); | |
| 1432 | + blob_set(&gsvn.filter, zFilter); | |
| 1383 | 1433 | svn_dump_import(pIn); |
| 1384 | 1434 | } |
| 1385 | 1435 | |
| 1386 | 1436 | verify_cancel(); |
| 1387 | 1437 | db_end_transaction(0); |
| 1388 | 1438 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -725,10 +725,17 @@ | |
| 725 | char *zBranch; /* Name of a branch for a commit */ |
| 726 | char *zDate; /* Date/time stamp */ |
| 727 | char *zUser; /* User name */ |
| 728 | char *zComment; /* Comment of a commit */ |
| 729 | int flatFlag; /* True if whole repo is a single file tree */ |
| 730 | } gsvn; |
| 731 | typedef struct { |
| 732 | const char *zKey; |
| 733 | const char *zVal; |
| 734 | } KeyVal; |
| @@ -896,11 +903,11 @@ | |
| 896 | Blob manifest; |
| 897 | static Stmt insRev; |
| 898 | static Stmt qParent; |
| 899 | static Stmt qFiles; |
| 900 | static Stmt qTags; |
| 901 | char zFilter[200]; |
| 902 | int nFilter; |
| 903 | int rid; |
| 904 | const char *zParentBranch = 0; |
| 905 | Blob mcksum; |
| 906 | |
| @@ -910,13 +917,11 @@ | |
| 910 | db_static_prepare(&qParent, "SELECT tuuid, tbranch FROM xrevisions " |
| 911 | "WHERE trev=:rev"); |
| 912 | db_static_prepare(&qFiles, "SELECT tpath, trid, tperm FROM xfiles " |
| 913 | "WHERE tpath GLOB :filter ORDER BY tpath"); |
| 914 | db_static_prepare(&qTags, "SELECT ttag FROM xtags WHERE trev=:rev"); |
| 915 | if( db_int(0, "SELECT 1 FROM xfiles LIMIT 1")==0 ){ return; } |
| 916 | if( !gsvn.flatFlag ){ |
| 917 | if( gsvn.zBranch==0 || gsvn.zBranch[0]=='\0' ){ return; } |
| 918 | if( gsvn.parent<0 ){ |
| 919 | gsvn.parent = db_int(-1, "SELECT ifnull(max(trev),-1) FROM xrevisions " |
| 920 | "WHERE tbranch=%Q", gsvn.zBranch); |
| 921 | } |
| 922 | db_bind_int(&insRev, ":rev", gsvn.rev); |
| @@ -934,27 +939,28 @@ | |
| 934 | blob_appendf(&manifest, "C %F\n", gsvn.zComment); |
| 935 | }else{ |
| 936 | blob_append(&manifest, "C (no\\scomment)\n", 16); |
| 937 | } |
| 938 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 939 | if( strncmp(gsvn.zBranch, "trunk", 5)==0 ){ |
| 940 | memcpy(zFilter, "trunk/*", 8); |
| 941 | nFilter = 6; |
| 942 | }else{ |
| 943 | sqlite3_snprintf(sizeof(zFilter), zFilter, "branches/%s/*", gsvn.zBranch); |
| 944 | nFilter = strlen(zFilter)-1; |
| 945 | } |
| 946 | db_bind_text(&qFiles, ":filter", zFilter); |
| 947 | while( db_step(&qFiles)==SQLITE_ROW ){ |
| 948 | const char *zFile = db_column_text(&qFiles, 0); |
| 949 | int rid = db_column_int(&qFiles, 1); |
| 950 | const char *zPerm = db_column_text(&qFiles, 2); |
| 951 | const char *zUuid; |
| 952 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 953 | blob_appendf(&manifest, "F %F %s %s\n", zFile+nFilter, zUuid, zPerm); |
| 954 | fossil_free(zUuid); |
| 955 | } |
| 956 | if( gsvn.parent>=0 ){ |
| 957 | const char *zParentUuid; |
| 958 | db_bind_int(&qParent, ":rev", gsvn.parent); |
| 959 | db_step(&qParent); |
| 960 | zParentUuid = db_column_text(&qParent, 0); |
| @@ -1016,11 +1022,11 @@ | |
| 1016 | } |
| 1017 | zDiff += 4; |
| 1018 | blob_zero(pOut); |
| 1019 | while( zDiff<(blob_buffer(pDiff)+blob_size(pDiff)) ){ |
| 1020 | u64 offSrc = svn_get_varint(&zDiff); |
| 1021 | u64 lenSrc = svn_get_varint(&zDiff); |
| 1022 | u64 lenOut = svn_get_varint(&zDiff); |
| 1023 | u64 lenInst = svn_get_varint(&zDiff); |
| 1024 | u64 lenData = svn_get_varint(&zDiff); |
| 1025 | const char *zInst = zDiff; |
| 1026 | const char *zData = zInst+lenInst; |
| @@ -1063,10 +1069,11 @@ | |
| 1063 | const char *zTemp; |
| 1064 | const char *zUuid; |
| 1065 | Stmt addHist; |
| 1066 | Stmt insTag; |
| 1067 | Stmt cpyPath; |
| 1068 | |
| 1069 | /* version */ |
| 1070 | if( svn_read_rec(pIn, &rec) |
| 1071 | && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ |
| 1072 | ver = atoi(zTemp); |
| @@ -1099,11 +1106,11 @@ | |
| 1099 | ); |
| 1100 | gsvn.rev = -1; |
| 1101 | while( svn_read_rec(pIn, &rec) ){ |
| 1102 | if( (zTemp = svn_find_header(rec, "Revision-number")) ){ /* revision node */ |
| 1103 | /* finish previous revision */ |
| 1104 | if( gsvn.rev>=0 ){ |
| 1105 | svn_create_manifest(); |
| 1106 | fossil_free(gsvn.zUser); |
| 1107 | fossil_free(gsvn.zComment); |
| 1108 | fossil_free(gsvn.zDate); |
| 1109 | fossil_free(gsvn.zBranch); |
| @@ -1113,10 +1120,11 @@ | |
| 1113 | gsvn.zUser = mprintf("%s", svn_find_prop(rec, "svn:author")); |
| 1114 | gsvn.zComment = mprintf("%s", svn_find_prop(rec, "svn:log")); |
| 1115 | gsvn.zDate = date_in_standard_format(svn_find_prop(rec, "svn:date")); |
| 1116 | gsvn.parent = -1; |
| 1117 | gsvn.zBranch = 0; |
| 1118 | fossil_print("\rImporting SVN revision: %d", gsvn.rev); |
| 1119 | db_bind_int(&addHist, ":rev", gsvn.rev); |
| 1120 | db_bind_int(&cpyPath, ":rev", gsvn.rev); |
| 1121 | }else |
| 1122 | if( (zTemp = svn_find_header(rec, "Node-path")) ){ /* file/dir node */ |
| @@ -1137,27 +1145,38 @@ | |
| 1137 | }else{ |
| 1138 | fossil_fatal("Missing copyfrom-rev"); |
| 1139 | } |
| 1140 | } |
| 1141 | if( !gsvn.flatFlag ){ |
| 1142 | if( strncmp(zPath, "branches/", 9)==0 ){ |
| 1143 | int nBranch; |
| 1144 | zTemp = zPath+9; |
| 1145 | while( *zTemp && *zTemp!='/' ){ zTemp++; } |
| 1146 | nBranch = zTemp-zPath+9; |
| 1147 | gsvn.zBranch = fossil_malloc(nBranch+1); |
| 1148 | memcpy(gsvn.zBranch, zPath+9, nBranch); |
| 1149 | gsvn.zBranch[nBranch] = '\0'; |
| 1150 | }else |
| 1151 | if( strncmp(zPath, "trunk/", 6)==0 ){ |
| 1152 | gsvn.zBranch = mprintf("trunk"); |
| 1153 | }else |
| 1154 | if( strncmp(zPath, "tags/", 5)!=0 |
| 1155 | && strcmp(zPath, "branches")!=0 |
| 1156 | && strcmp(zPath, "trunk")!=0 |
| 1157 | && strcmp(zPath, "tags")!=0){ |
| 1158 | fossil_fatal("Write outside repository layout: %s", zPath); |
| 1159 | } |
| 1160 | } |
| 1161 | if( strncmp(zAction, "delete", 6)==0 |
| 1162 | || strncmp(zAction, "replace", 7)==0 ) |
| 1163 | { |
| @@ -1178,17 +1197,17 @@ | |
| 1178 | db_bind_text(&cpyPath, ":path", zPath); |
| 1179 | db_bind_text(&cpyPath, ":srcpath", zSrcPath); |
| 1180 | db_step(&cpyPath); |
| 1181 | db_reset(&cpyPath); |
| 1182 | if( !gsvn.flatFlag ){ |
| 1183 | if( strncmp(zPath, "branches/", 9)==0 ){ |
| 1184 | zTemp = zPath+9+strlen(gsvn.zBranch); |
| 1185 | if( *zTemp==0 ){ |
| 1186 | gsvn.parent = srcRev; |
| 1187 | } |
| 1188 | }else if( strncmp(zPath, "tags/", 5)==0 ){ |
| 1189 | zTemp = zPath+5; |
| 1190 | db_bind_int(&insTag, ":rev", srcRev); |
| 1191 | db_bind_text(&insTag, ":tag", zTemp); |
| 1192 | db_step(&insTag); |
| 1193 | db_reset(&insTag); |
| 1194 | } |
| @@ -1278,14 +1297,20 @@ | |
| 1278 | ** |
| 1279 | ** The following formats are currently understood by this command |
| 1280 | ** |
| 1281 | ** git Import from the git-fast-export file format |
| 1282 | ** |
| 1283 | ** svn Import from the svnadmin-dump file format |
| 1284 | ** Options: |
| 1285 | ** --flat The whole dump is a single branch. The default |
| 1286 | ** is to use the trunk/branches/tags svn layout |
| 1287 | ** |
| 1288 | ** The --incremental option allows an existing repository to be extended |
| 1289 | ** with new content. |
| 1290 | ** |
| 1291 | ** Options: |
| @@ -1295,12 +1320,16 @@ | |
| 1295 | */ |
| 1296 | void import_cmd(void){ |
| 1297 | char *zPassword; |
| 1298 | FILE *pIn; |
| 1299 | Stmt q; |
| 1300 | int forceFlag = find_option("force", "f", 0)!=0; |
| 1301 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1302 | gsvn.flatFlag = find_option("flat", 0, 0)!=0; |
| 1303 | |
| 1304 | verify_all_options(); |
| 1305 | if( g.argc!=4 && g.argc!=5 ){ |
| 1306 | usage("FORMAT REPOSITORY-NAME"); |
| @@ -1378,10 +1407,31 @@ | |
| 1378 | " VALUES(new.tpath, new.trid, new.tperm); END;" |
| 1379 | "CREATE TEMP TABLE xtags(" |
| 1380 | " trev INT, ttag TEXT" |
| 1381 | ");" |
| 1382 | ); |
| 1383 | svn_dump_import(pIn); |
| 1384 | } |
| 1385 | |
| 1386 | verify_cancel(); |
| 1387 | db_end_transaction(0); |
| 1388 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -725,10 +725,17 @@ | |
| 725 | char *zBranch; /* Name of a branch for a commit */ |
| 726 | char *zDate; /* Date/time stamp */ |
| 727 | char *zUser; /* User name */ |
| 728 | char *zComment; /* Comment of a commit */ |
| 729 | int flatFlag; /* True if whole repo is a single file tree */ |
| 730 | const char *zTrunk; /* Name of trunk folder in repo root */ |
| 731 | int lenTrunk; /* String length of zTrunk */ |
| 732 | const char *zBranches; /* Name of branches folder in repo root */ |
| 733 | int lenBranches; /* String length of zBranches */ |
| 734 | const char *zTags; /* Name of tags folder in repo root */ |
| 735 | int lenTags; /* String length of zTags */ |
| 736 | Blob filter; /* Path to repo root */ |
| 737 | } gsvn; |
| 738 | typedef struct { |
| 739 | const char *zKey; |
| 740 | const char *zVal; |
| 741 | } KeyVal; |
| @@ -896,11 +903,11 @@ | |
| 903 | Blob manifest; |
| 904 | static Stmt insRev; |
| 905 | static Stmt qParent; |
| 906 | static Stmt qFiles; |
| 907 | static Stmt qTags; |
| 908 | int nBaseFilter; |
| 909 | int nFilter; |
| 910 | int rid; |
| 911 | const char *zParentBranch = 0; |
| 912 | Blob mcksum; |
| 913 | |
| @@ -910,13 +917,11 @@ | |
| 917 | db_static_prepare(&qParent, "SELECT tuuid, tbranch FROM xrevisions " |
| 918 | "WHERE trev=:rev"); |
| 919 | db_static_prepare(&qFiles, "SELECT tpath, trid, tperm FROM xfiles " |
| 920 | "WHERE tpath GLOB :filter ORDER BY tpath"); |
| 921 | db_static_prepare(&qTags, "SELECT ttag FROM xtags WHERE trev=:rev"); |
| 922 | if( !gsvn.flatFlag ){ |
| 923 | if( gsvn.parent<0 ){ |
| 924 | gsvn.parent = db_int(-1, "SELECT ifnull(max(trev),-1) FROM xrevisions " |
| 925 | "WHERE tbranch=%Q", gsvn.zBranch); |
| 926 | } |
| 927 | db_bind_int(&insRev, ":rev", gsvn.rev); |
| @@ -934,27 +939,28 @@ | |
| 939 | blob_appendf(&manifest, "C %F\n", gsvn.zComment); |
| 940 | }else{ |
| 941 | blob_append(&manifest, "C (no\\scomment)\n", 16); |
| 942 | } |
| 943 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 944 | nBaseFilter = blob_size(&gsvn.filter); |
| 945 | if( strcmp(gsvn.zBranch, gsvn.zTrunk)==0 ){ |
| 946 | blob_appendf(&gsvn.filter, "%s*", gsvn.zTrunk); |
| 947 | }else{ |
| 948 | blob_appendf(&gsvn.filter, "%s%s/*", gsvn.zBranches, gsvn.zBranch); |
| 949 | } |
| 950 | db_bind_text(&qFiles, ":filter", blob_str(&gsvn.filter)); |
| 951 | nFilter = blob_size(&gsvn.filter); |
| 952 | while( db_step(&qFiles)==SQLITE_ROW ){ |
| 953 | const char *zFile = db_column_text(&qFiles, 0); |
| 954 | int rid = db_column_int(&qFiles, 1); |
| 955 | const char *zPerm = db_column_text(&qFiles, 2); |
| 956 | const char *zUuid; |
| 957 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 958 | blob_appendf(&manifest, "F %F %s %s\n", zFile+nFilter, zUuid, zPerm); |
| 959 | fossil_free(zUuid); |
| 960 | } |
| 961 | blob_resize(&gsvn.filter, nBaseFilter); |
| 962 | if( gsvn.parent>=0 ){ |
| 963 | const char *zParentUuid; |
| 964 | db_bind_int(&qParent, ":rev", gsvn.parent); |
| 965 | db_step(&qParent); |
| 966 | zParentUuid = db_column_text(&qParent, 0); |
| @@ -1016,11 +1022,11 @@ | |
| 1022 | } |
| 1023 | zDiff += 4; |
| 1024 | blob_zero(pOut); |
| 1025 | while( zDiff<(blob_buffer(pDiff)+blob_size(pDiff)) ){ |
| 1026 | u64 offSrc = svn_get_varint(&zDiff); |
| 1027 | /*u64 lenSrc =*/ svn_get_varint(&zDiff); |
| 1028 | u64 lenOut = svn_get_varint(&zDiff); |
| 1029 | u64 lenInst = svn_get_varint(&zDiff); |
| 1030 | u64 lenData = svn_get_varint(&zDiff); |
| 1031 | const char *zInst = zDiff; |
| 1032 | const char *zData = zInst+lenInst; |
| @@ -1063,10 +1069,11 @@ | |
| 1069 | const char *zTemp; |
| 1070 | const char *zUuid; |
| 1071 | Stmt addHist; |
| 1072 | Stmt insTag; |
| 1073 | Stmt cpyPath; |
| 1074 | int bHasFiles; |
| 1075 | |
| 1076 | /* version */ |
| 1077 | if( svn_read_rec(pIn, &rec) |
| 1078 | && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ |
| 1079 | ver = atoi(zTemp); |
| @@ -1099,11 +1106,11 @@ | |
| 1106 | ); |
| 1107 | gsvn.rev = -1; |
| 1108 | while( svn_read_rec(pIn, &rec) ){ |
| 1109 | if( (zTemp = svn_find_header(rec, "Revision-number")) ){ /* revision node */ |
| 1110 | /* finish previous revision */ |
| 1111 | if( bHasFiles ){ |
| 1112 | svn_create_manifest(); |
| 1113 | fossil_free(gsvn.zUser); |
| 1114 | fossil_free(gsvn.zComment); |
| 1115 | fossil_free(gsvn.zDate); |
| 1116 | fossil_free(gsvn.zBranch); |
| @@ -1113,10 +1120,11 @@ | |
| 1120 | gsvn.zUser = mprintf("%s", svn_find_prop(rec, "svn:author")); |
| 1121 | gsvn.zComment = mprintf("%s", svn_find_prop(rec, "svn:log")); |
| 1122 | gsvn.zDate = date_in_standard_format(svn_find_prop(rec, "svn:date")); |
| 1123 | gsvn.parent = -1; |
| 1124 | gsvn.zBranch = 0; |
| 1125 | bHasFiles = 0; |
| 1126 | fossil_print("\rImporting SVN revision: %d", gsvn.rev); |
| 1127 | db_bind_int(&addHist, ":rev", gsvn.rev); |
| 1128 | db_bind_int(&cpyPath, ":rev", gsvn.rev); |
| 1129 | }else |
| 1130 | if( (zTemp = svn_find_header(rec, "Node-path")) ){ /* file/dir node */ |
| @@ -1137,27 +1145,38 @@ | |
| 1145 | }else{ |
| 1146 | fossil_fatal("Missing copyfrom-rev"); |
| 1147 | } |
| 1148 | } |
| 1149 | if( !gsvn.flatFlag ){ |
| 1150 | if( strncmp(zPath, gsvn.zBranches, gsvn.lenBranches)==0 ){ |
| 1151 | int lenBranch; |
| 1152 | zTemp = zPath+gsvn.lenBranches; |
| 1153 | while( *zTemp && *zTemp!='/' ){ zTemp++; } |
| 1154 | lenBranch = zTemp-zPath-gsvn.lenBranches; |
| 1155 | zTemp = zPath+gsvn.lenBranches; |
| 1156 | if( gsvn.zBranch!=0 ){ |
| 1157 | if( strncmp(zTemp, gsvn.zBranch, lenBranch)!=0 ){ |
| 1158 | fossil_fatal("Commit to multiple branches"); |
| 1159 | } |
| 1160 | }else{ |
| 1161 | gsvn.zBranch = fossil_malloc(lenBranch+1); |
| 1162 | memcpy(gsvn.zBranch, zTemp, lenBranch); |
| 1163 | gsvn.zBranch[lenBranch] = '\0'; |
| 1164 | bHasFiles = 1; |
| 1165 | } |
| 1166 | }else |
| 1167 | if( strncmp(zPath, gsvn.zTrunk, gsvn.lenTrunk)==0 ){ |
| 1168 | if( gsvn.zBranch!=0 ){ |
| 1169 | if( strncmp(gsvn.zTrunk, gsvn.zBranch, gsvn.lenTrunk-1)!=0 ){ |
| 1170 | fossil_fatal("Commit to multiple branches"); |
| 1171 | } |
| 1172 | }else{ |
| 1173 | gsvn.zBranch = fossil_malloc(gsvn.lenTrunk); |
| 1174 | memcpy(gsvn.zBranch, gsvn.zTrunk, gsvn.lenTrunk-1); |
| 1175 | gsvn.zBranch[gsvn.lenTrunk-1] = '\0'; |
| 1176 | bHasFiles = 1; |
| 1177 | } |
| 1178 | } |
| 1179 | } |
| 1180 | if( strncmp(zAction, "delete", 6)==0 |
| 1181 | || strncmp(zAction, "replace", 7)==0 ) |
| 1182 | { |
| @@ -1178,17 +1197,17 @@ | |
| 1197 | db_bind_text(&cpyPath, ":path", zPath); |
| 1198 | db_bind_text(&cpyPath, ":srcpath", zSrcPath); |
| 1199 | db_step(&cpyPath); |
| 1200 | db_reset(&cpyPath); |
| 1201 | if( !gsvn.flatFlag ){ |
| 1202 | if( strncmp(zPath, gsvn.zBranches, gsvn.lenBranches)==0 ){ |
| 1203 | zTemp = zPath+gsvn.lenBranches+strlen(gsvn.zBranch); |
| 1204 | if( *zTemp==0 ){ |
| 1205 | gsvn.parent = srcRev; |
| 1206 | } |
| 1207 | }else if( strncmp(zPath, gsvn.zTags, gsvn.lenTags)==0 ){ |
| 1208 | zTemp = zPath+gsvn.lenTags; |
| 1209 | db_bind_int(&insTag, ":rev", srcRev); |
| 1210 | db_bind_text(&insTag, ":tag", zTemp); |
| 1211 | db_step(&insTag); |
| 1212 | db_reset(&insTag); |
| 1213 | } |
| @@ -1278,14 +1297,20 @@ | |
| 1297 | ** |
| 1298 | ** The following formats are currently understood by this command |
| 1299 | ** |
| 1300 | ** git Import from the git-fast-export file format |
| 1301 | ** |
| 1302 | ** svn Import from the svnadmin-dump file format. The default |
| 1303 | ** behaviour is to treat 3 folders in the SVN root as special, |
| 1304 | ** following the common layout of SVN repositories. These are |
| 1305 | ** (by default) trunk/, branches/ and tags/ |
| 1306 | ** Options: |
| 1307 | ** --trunk FOLDER Name of trunk folder |
| 1308 | ** --branches FOLDER Name of branches folder |
| 1309 | ** --tags FOLDER Name of tags folder |
| 1310 | ** --fiter PATH Path to project root in repository |
| 1311 | ** --flat The whole dump is a single branch |
| 1312 | ** |
| 1313 | ** The --incremental option allows an existing repository to be extended |
| 1314 | ** with new content. |
| 1315 | ** |
| 1316 | ** Options: |
| @@ -1295,12 +1320,16 @@ | |
| 1320 | */ |
| 1321 | void import_cmd(void){ |
| 1322 | char *zPassword; |
| 1323 | FILE *pIn; |
| 1324 | Stmt q; |
| 1325 | const char *zFilter = find_option("filter", 0, 1); |
| 1326 | int forceFlag = find_option("force", "f", 0)!=0; |
| 1327 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1328 | gsvn.zTrunk = find_option("trunk", 0, 1); |
| 1329 | gsvn.zBranches = find_option("branches", 0, 1); |
| 1330 | gsvn.zTags = find_option("tags", 0, 1); |
| 1331 | gsvn.flatFlag = find_option("flat", 0, 0)!=0; |
| 1332 | |
| 1333 | verify_all_options(); |
| 1334 | if( g.argc!=4 && g.argc!=5 ){ |
| 1335 | usage("FORMAT REPOSITORY-NAME"); |
| @@ -1378,10 +1407,31 @@ | |
| 1407 | " VALUES(new.tpath, new.trid, new.tperm); END;" |
| 1408 | "CREATE TEMP TABLE xtags(" |
| 1409 | " trev INT, ttag TEXT" |
| 1410 | ");" |
| 1411 | ); |
| 1412 | if( gsvn.zTrunk==0 ){ gsvn.zTrunk = "trunk/"; } |
| 1413 | if( gsvn.zBranches==0 ){ gsvn.zBranches = "branches/"; } |
| 1414 | if( gsvn.zTags==0 ){ gsvn.zTags = "tags/"; } |
| 1415 | gsvn.lenTrunk = strlen(gsvn.zTrunk); |
| 1416 | gsvn.lenBranches = strlen(gsvn.zBranches); |
| 1417 | gsvn.lenTags = strlen(gsvn.zTags); |
| 1418 | if( gsvn.zTrunk[gsvn.lenTrunk-1]!='/' ){ |
| 1419 | gsvn.zTrunk = mprintf("%s/", gsvn.zTrunk); |
| 1420 | gsvn.lenTrunk++; |
| 1421 | } |
| 1422 | if( gsvn.zBranches[gsvn.lenBranches-1]!='/' ){ |
| 1423 | gsvn.zBranches = mprintf("%s/", gsvn.zBranches); |
| 1424 | gsvn.lenBranches++; |
| 1425 | } |
| 1426 | if( gsvn.zTags[gsvn.lenTags-1]!='/' ){ |
| 1427 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1428 | gsvn.lenTags++; |
| 1429 | } |
| 1430 | if( zFilter==0 ){ zFilter = ""; } |
| 1431 | blob_zero(&gsvn.filter); |
| 1432 | blob_set(&gsvn.filter, zFilter); |
| 1433 | svn_dump_import(pIn); |
| 1434 | } |
| 1435 | |
| 1436 | verify_cancel(); |
| 1437 | db_end_transaction(0); |
| 1438 |