Fossil SCM
Significant speed improvment
Commit
31b1e5a8260eecf7057e40163f6c8d259b1823ee
Parent
ea54a29848ba316…
2 files changed
+2
+228
-246
M
src/db.c
+2
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -286,10 +286,12 @@ | ||
| 286 | 286 | pStmt->pNext = db.pAllStmt; |
| 287 | 287 | pStmt->pPrev = 0; |
| 288 | 288 | if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt; |
| 289 | 289 | db.pAllStmt = pStmt; |
| 290 | 290 | va_end(ap); |
| 291 | + }else{ | |
| 292 | + db_reset(pStmt); | |
| 291 | 293 | } |
| 292 | 294 | return rc; |
| 293 | 295 | } |
| 294 | 296 | |
| 295 | 297 | /* |
| 296 | 298 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -286,10 +286,12 @@ | |
| 286 | pStmt->pNext = db.pAllStmt; |
| 287 | pStmt->pPrev = 0; |
| 288 | if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt; |
| 289 | db.pAllStmt = pStmt; |
| 290 | va_end(ap); |
| 291 | } |
| 292 | return rc; |
| 293 | } |
| 294 | |
| 295 | /* |
| 296 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -286,10 +286,12 @@ | |
| 286 | pStmt->pNext = db.pAllStmt; |
| 287 | pStmt->pPrev = 0; |
| 288 | if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt; |
| 289 | db.pAllStmt = pStmt; |
| 290 | va_end(ap); |
| 291 | }else{ |
| 292 | db_reset(pStmt); |
| 293 | } |
| 294 | return rc; |
| 295 | } |
| 296 | |
| 297 | /* |
| 298 |
+228
-246
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -717,10 +717,19 @@ | ||
| 717 | 717 | trim_newline(zLine); |
| 718 | 718 | fossil_fatal("bad fast-import line: [%s]", zLine); |
| 719 | 719 | return; |
| 720 | 720 | } |
| 721 | 721 | |
| 722 | +static struct{ | |
| 723 | + int rev; /* SVN revision number */ | |
| 724 | + int parent; /* SVN revision number of parent check-in */ | |
| 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; | |
| 722 | 731 | typedef struct { |
| 723 | 732 | const char *zKey; |
| 724 | 733 | const char *zVal; |
| 725 | 734 | } KeyVal; |
| 726 | 735 | typedef struct { |
| @@ -880,133 +889,117 @@ | ||
| 880 | 889 | rec->contentFlag = 0; |
| 881 | 890 | } |
| 882 | 891 | return 1; |
| 883 | 892 | } |
| 884 | 893 | |
| 885 | -static void svn_create_manifests(int flatFlag){ | |
| 886 | - Blob manifest; | |
| 887 | - Stmt qRev; | |
| 888 | - Stmt qParent; | |
| 889 | - Stmt qFiles; | |
| 890 | - Stmt qTags; | |
| 891 | - Stmt setUuid; | |
| 892 | - | |
| 893 | - if( !flatFlag ){ | |
| 894 | - db_multi_exec("DELETE FROM xrevisions WHERE tbranch ISNULL;" | |
| 895 | - "UPDATE xrevisions SET tparent=(" | |
| 896 | - " SELECT ifnull(max(trev),-1) FROM xrevisions t" | |
| 897 | - " WHERE t.trev<xrevisions.trev" | |
| 898 | - " AND t.tbranch=xrevisions.tbranch" | |
| 899 | - " )" | |
| 900 | - " WHERE tparent ISNULL;" | |
| 901 | - "WITH xprefix AS ( " | |
| 902 | - " SELECT trev, CASE tbranch WHEN 'trunk' THEN 'trunk/'" | |
| 903 | - " ELSE 'branches/'||tbranch||'/' END xpref" | |
| 904 | - " FROM xrevisions" | |
| 905 | - " ), " | |
| 906 | - " x AS (SELECT trev xrev, xpref, length(xpref) xlen " | |
| 907 | - " FROM xprefix) " | |
| 908 | - " UPDATE xfiles SET tpath= " | |
| 909 | - " CASE substr(tpath,1,(SELECT xlen FROM x WHERE xrev=trev))" | |
| 910 | - " WHEN (SELECT xpref FROM x WHERE xrev=trev)" | |
| 911 | - " THEN substr(tpath,(SELECT xlen FROM x WHERE xrev=trev)+1)" | |
| 912 | - " END;" | |
| 913 | - "DELETE FROM xfiles WHERE tpath ISNULL"); | |
| 914 | - }else{ | |
| 915 | - db_multi_exec("UPDATE xrevisions SET tparent=trev-1"); | |
| 916 | - } | |
| 917 | - db_prepare(&qRev, "SELECT trev, tuser, tmsg, ttime, tparent, tbranch" | |
| 918 | - " FROM xrevisions " | |
| 919 | - " ORDER BY trev"); | |
| 920 | - db_prepare(&qParent, "SELECT tuuid, tbranch FROM xrevisions WHERE trev=:rev"); | |
| 921 | - db_prepare(&qFiles, "SELECT tpath, uuid, tperm" | |
| 922 | - " FROM xfiles JOIN blob ON xfiles.trid=blob.rid" | |
| 923 | - " WHERE trev=:rev ORDER BY tpath"); | |
| 924 | - db_prepare(&qTags, "SELECT ttag FROM xtags WHERE trev=:rev"); | |
| 925 | - db_prepare(&setUuid, "UPDATE xrevisions" | |
| 926 | - " SET tuuid=(SELECT uuid FROM blob WHERE rid=:rid)" | |
| 927 | - " WHERE trev=:rev"); | |
| 928 | - blob_zero(&manifest); | |
| 929 | - while( db_step(&qRev)==SQLITE_ROW ){ | |
| 930 | - int rev = db_column_int(&qRev, 0); | |
| 931 | - const char *zUser = db_column_text(&qRev, 1); | |
| 932 | - const char *zMsg = db_column_text(&qRev, 2); | |
| 933 | - const char *zTime = db_column_text(&qRev, 3); | |
| 934 | - int parentRev = db_column_int(&qRev, 4); | |
| 935 | - const char *zBranch = db_column_text(&qRev, 5); | |
| 936 | - int rid; | |
| 937 | - const char *zParentBranch = 0; | |
| 938 | - Blob mcksum; | |
| 939 | - blob_reset(&manifest); | |
| 940 | - if( zMsg ){ | |
| 941 | - blob_appendf(&manifest, "C %F\n", zMsg); | |
| 942 | - }else{ | |
| 943 | - blob_append(&manifest, "C (no\\scomment)\n", 16); | |
| 944 | - } | |
| 945 | - blob_appendf(&manifest, "D %s\n", zTime); | |
| 946 | - db_bind_int(&qFiles, ":rev", rev); | |
| 947 | - while( db_step(&qFiles)==SQLITE_ROW ){ | |
| 948 | - const char *zFile = db_column_text(&qFiles, 0); | |
| 949 | - const char *zUuid = db_column_text(&qFiles, 1); | |
| 950 | - const char *zPerm = db_column_text(&qFiles, 2); | |
| 951 | - blob_appendf(&manifest, "F %F %s %s\n", zFile, zUuid, zPerm); | |
| 952 | - } | |
| 953 | - db_reset(&qFiles); | |
| 954 | - if( parentRev>=0 ){ | |
| 955 | - const char *zParentUuid; | |
| 956 | - db_bind_int(&qParent, ":rev", parentRev); | |
| 957 | - db_step(&qParent); | |
| 958 | - zParentUuid = db_column_text(&qParent, 0); | |
| 959 | - blob_appendf(&manifest, "P %s\n", zParentUuid); | |
| 960 | - if( !flatFlag ){ | |
| 961 | - zParentBranch = db_column_text(&qParent, 1); | |
| 962 | - if( strcmp(zBranch, zParentBranch)!=0 ){ | |
| 963 | - blob_appendf(&manifest, "T *branch * %s\n", zBranch); | |
| 964 | - blob_appendf(&manifest, "T *sym-%s *\n", zBranch); | |
| 965 | - zParentBranch = mprintf("%s", zParentBranch); | |
| 966 | - }else{ | |
| 967 | - zParentBranch = 0; | |
| 968 | - } | |
| 969 | - } | |
| 970 | - db_reset(&qParent); | |
| 971 | - }else{ | |
| 972 | - blob_appendf(&manifest, "T *branch * trunk\n"); | |
| 973 | - blob_appendf(&manifest, "T *sym-trunk *\n"); | |
| 974 | - } | |
| 975 | - db_bind_int(&qTags, ":rev", rev); | |
| 976 | - while( db_step(&qTags)==SQLITE_ROW ){ | |
| 977 | - const char *zTag = db_column_text(&qTags, 0); | |
| 978 | - blob_appendf(&manifest, "T +sym-%s *\n", zTag); | |
| 979 | - } | |
| 980 | - db_reset(&qTags); | |
| 981 | - blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", rev); | |
| 982 | - if( zParentBranch ) { | |
| 983 | - blob_appendf(&manifest, "T -sym-%s *\n", zParentBranch); | |
| 984 | - zParentBranch = 0; | |
| 985 | - } | |
| 986 | - if( zUser ){ | |
| 987 | - blob_appendf(&manifest, "U %F\n", zUser); | |
| 988 | - }else{ | |
| 989 | - const char *zUserOvrd = find_option("user-override",0,1); | |
| 990 | - blob_appendf(&manifest, "U %F\n", | |
| 991 | - zUserOvrd ? zUserOvrd : login_name()); | |
| 992 | - } | |
| 993 | - md5sum_blob(&manifest, &mcksum); | |
| 994 | - blob_appendf(&manifest, "Z %b\n", &mcksum); | |
| 995 | - blob_reset(&mcksum); | |
| 996 | - | |
| 997 | - rid = content_put(&manifest); | |
| 998 | - db_bind_int(&setUuid, ":rid", rid); | |
| 999 | - db_bind_int(&setUuid, ":rev", rev); | |
| 1000 | - db_step(&setUuid); | |
| 1001 | - db_reset(&setUuid); | |
| 1002 | - } | |
| 1003 | - db_finalize(&qRev); | |
| 1004 | - db_finalize(&qParent); | |
| 1005 | - db_finalize(&qFiles); | |
| 1006 | - db_finalize(&qTags); | |
| 1007 | - db_finalize(&setUuid); | |
| 894 | +static void svn_create_manifest( | |
| 895 | +){ | |
| 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 | + | |
| 907 | + db_static_prepare(&insRev, "REPLACE INTO xrevisions (trev, tbranch, tuuid) " | |
| 908 | + "VALUES(:rev, :branch, " | |
| 909 | + " (SELECT uuid FROM blob WHERE rid=:rid))"); | |
| 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); | |
| 923 | + db_bind_text(&insRev, ":branch", gsvn.zBranch); | |
| 924 | + db_bind_int(&insRev, ":rid", 0); | |
| 925 | + db_step(&insRev); | |
| 926 | + db_reset(&insRev); | |
| 927 | + }else{ | |
| 928 | + static int prevRev = -1; | |
| 929 | + gsvn.parent = prevRev; | |
| 930 | + prevRev = gsvn.rev; | |
| 931 | + } | |
| 932 | + blob_zero(&manifest); | |
| 933 | + if( gsvn.zComment ){ | |
| 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); | |
| 961 | + blob_appendf(&manifest, "P %s\n", zParentUuid); | |
| 962 | + if( !gsvn.flatFlag ){ | |
| 963 | + zParentBranch = db_column_text(&qParent, 1); | |
| 964 | + if( strcmp(gsvn.zBranch, zParentBranch)!=0 ){ | |
| 965 | + blob_appendf(&manifest, "T *branch * %s\n", gsvn.zBranch); | |
| 966 | + blob_appendf(&manifest, "T *sym-%s *\n", gsvn.zBranch); | |
| 967 | + zParentBranch = mprintf("%s", zParentBranch); | |
| 968 | + }else{ | |
| 969 | + zParentBranch = 0; | |
| 970 | + } | |
| 971 | + } | |
| 972 | + }else{ | |
| 973 | + blob_appendf(&manifest, "T *branch * trunk\n"); | |
| 974 | + blob_appendf(&manifest, "T *sym-trunk *\n"); | |
| 975 | + } | |
| 976 | + db_bind_int(&qTags, ":rev", gsvn.rev); | |
| 977 | + while( db_step(&qTags)==SQLITE_ROW ){ | |
| 978 | + const char *zTag = db_column_text(&qTags, 0); | |
| 979 | + blob_appendf(&manifest, "T +sym-%s *\n", zTag); | |
| 980 | + } | |
| 981 | + blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 982 | + if( zParentBranch ) { | |
| 983 | + blob_appendf(&manifest, "T -sym-%s *\n", zParentBranch); | |
| 984 | + } | |
| 985 | + if( gsvn.zUser ){ | |
| 986 | + blob_appendf(&manifest, "U %F\n", gsvn.zUser); | |
| 987 | + }else{ | |
| 988 | + const char *zUserOvrd = find_option("user-override",0,1); | |
| 989 | + blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : login_name()); | |
| 990 | + } | |
| 991 | + md5sum_blob(&manifest, &mcksum); | |
| 992 | + blob_appendf(&manifest, "Z %b\n", &mcksum); | |
| 993 | + blob_reset(&mcksum); | |
| 994 | + | |
| 995 | + rid = content_put(&manifest); | |
| 996 | + blob_reset(&manifest); | |
| 997 | + db_bind_int(&insRev, ":rev", gsvn.rev); | |
| 998 | + db_bind_text(&insRev, ":branch", gsvn.zBranch); | |
| 999 | + db_bind_int(&insRev, ":rid", rid); | |
| 1000 | + db_step(&insRev); | |
| 1008 | 1001 | } |
| 1009 | 1002 | |
| 1010 | 1003 | static u64 svn_get_varint(const char **pz){ |
| 1011 | 1004 | unsigned int v = 0; |
| 1012 | 1005 | do{ |
| @@ -1062,23 +1055,18 @@ | ||
| 1062 | 1055 | |
| 1063 | 1056 | /* |
| 1064 | 1057 | ** Read the svn-dump format from pIn and insert the corresponding |
| 1065 | 1058 | ** content into the database. |
| 1066 | 1059 | */ |
| 1067 | -static void svn_dump_import(FILE *pIn, int flatFlag){ | |
| 1060 | +static void svn_dump_import(FILE *pIn){ | |
| 1068 | 1061 | SvnRecord rec; |
| 1069 | 1062 | int ver; |
| 1070 | 1063 | const char *zTemp; |
| 1071 | 1064 | const char *zUuid; |
| 1072 | - char zBranch[200] = {0}; | |
| 1073 | - Stmt insRev; | |
| 1074 | - Stmt insFile; | |
| 1065 | + Stmt addHist; | |
| 1075 | 1066 | Stmt insTag; |
| 1076 | - Stmt delFile; | |
| 1077 | - Stmt setBranch; | |
| 1078 | - Stmt setParent; | |
| 1079 | - int rev = 0; | |
| 1067 | + Stmt cpyPath; | |
| 1080 | 1068 | |
| 1081 | 1069 | /* version */ |
| 1082 | 1070 | if( svn_read_rec(pIn, &rec) |
| 1083 | 1071 | && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ |
| 1084 | 1072 | ver = atoi(zTemp); |
| @@ -1093,71 +1081,55 @@ | ||
| 1093 | 1081 | if( !svn_read_rec(pIn, &rec) || !(zUuid = svn_find_header(rec, "UUID")) ){ |
| 1094 | 1082 | fossil_fatal("Missing UUID!"); |
| 1095 | 1083 | } |
| 1096 | 1084 | svn_free_rec(&rec); |
| 1097 | 1085 | /* content */ |
| 1098 | - db_prepare(&insRev, | |
| 1099 | - "INSERT INTO xrevisions (trev, tuser, tmsg, ttime) " | |
| 1100 | - "VALUES(:rev, :user, :msg, :time)" | |
| 1101 | - ); | |
| 1102 | - db_prepare(&insFile, | |
| 1103 | - "INSERT INTO xfiles (trev, tpath, trid, tperm) " | |
| 1104 | - "VALUES(:rev, :path, :rid, :perm)" | |
| 1086 | + db_prepare(&addHist, | |
| 1087 | + "INSERT INTO xhist (trev, tpath, trid, tperm) " | |
| 1088 | + "VALUES(:rev, :path, :rid, :perm)" | |
| 1105 | 1089 | ); |
| 1106 | 1090 | db_prepare(&insTag, "INSERT INTO xtags (trev, ttag) VALUES(:rev, :tag)"); |
| 1107 | - db_prepare(&delFile, | |
| 1108 | - "DELETE FROM xfiles " | |
| 1109 | - "WHERE trev=:rev " | |
| 1110 | - " AND (tpath=:path OR (tpath>:path||'/' AND tpath<:path||'0'))" | |
| 1111 | - ); | |
| 1112 | - db_prepare(&setBranch, | |
| 1113 | - "UPDATE xrevisions SET tbranch=:branch " | |
| 1114 | - "WHERE trev=:rev" | |
| 1115 | - ); | |
| 1116 | - db_prepare(&setParent, | |
| 1117 | - "UPDATE xrevisions SET tparent=:parent " | |
| 1118 | - "WHERE trev=:rev" | |
| 1119 | - ); | |
| 1091 | + db_prepare(&cpyPath, | |
| 1092 | + "WITH xsrc AS (SELECT * FROM (" | |
| 1093 | + " SELECT tpath, trid, tperm, max(trev) trev FROM xhist" | |
| 1094 | + " WHERE trev<=:srcrev GROUP BY tpath" | |
| 1095 | + " ) WHERE trid NOTNULL)" | |
| 1096 | + "INSERT INTO xhist (trev, tpath, trid, tperm)" | |
| 1097 | + " SELECT :rev, :path||substr(tpath, length(:srcpath)+1), trid, tperm" | |
| 1098 | + " FROM xsrc WHERE tpath>:srcpath||'/' AND tpath<:srcpath||0" | |
| 1099 | + ); | |
| 1100 | + gsvn.rev = -1; | |
| 1120 | 1101 | while( svn_read_rec(pIn, &rec) ){ |
| 1121 | - if( zTemp = svn_find_header(rec, "Revision-number") ){ | |
| 1122 | - const char *zUser = svn_find_prop(rec, "svn:author"); | |
| 1123 | - const char *zLog = svn_find_prop(rec, "svn:log"); | |
| 1124 | - const char *zDate = svn_find_prop(rec, "svn:date"); | |
| 1125 | - if( !flatFlag ){ | |
| 1126 | - if( *zBranch ){ | |
| 1127 | - db_bind_text(&setBranch, ":branch", zBranch); | |
| 1128 | - db_bind_int(&setBranch, ":rev", rev); | |
| 1129 | - db_step(&setBranch); | |
| 1130 | - db_reset(&setBranch); | |
| 1131 | - zBranch[0] = 0; | |
| 1132 | - } | |
| 1133 | - } | |
| 1134 | - zDate = date_in_standard_format(zDate); | |
| 1135 | - rev = atoi(zTemp); | |
| 1136 | - db_bind_int(&insRev, ":rev", rev); | |
| 1137 | - db_bind_text(&insRev, ":user", zUser); | |
| 1138 | - db_bind_text(&insRev, ":msg", zLog); | |
| 1139 | - db_bind_text(&insRev, ":time", zDate); | |
| 1140 | - db_step(&insRev); | |
| 1141 | - db_reset(&insRev); | |
| 1142 | - fossil_free(zDate); | |
| 1143 | - if( rev>0 ){ | |
| 1144 | - db_multi_exec("INSERT INTO xfiles (trev, tpath, trid, tperm) " | |
| 1145 | - "SELECT %d, tpath, trid, tperm FROM xfiles " | |
| 1146 | - "WHERE trev=%d", rev, rev-1); | |
| 1147 | - } | |
| 1148 | - }else | |
| 1149 | - if( zTemp = svn_find_header(rec, "Node-path") ){ | |
| 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); | |
| 1110 | + } | |
| 1111 | + /* start new revision */ | |
| 1112 | + gsvn.rev = atoi(zTemp); | |
| 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 */ | |
| 1150 | 1123 | const char *zPath = zTemp; |
| 1151 | 1124 | const char *zAction = svn_find_header(rec, "Node-action"); |
| 1152 | 1125 | const char *zKind = svn_find_header(rec, "Node-kind"); |
| 1153 | 1126 | const char *zSrcPath = svn_find_header(rec, "Node-copyfrom-path"); |
| 1154 | 1127 | const char *zPerm = svn_find_prop(rec, "svn:executable") ? "x" : 0; |
| 1155 | 1128 | int deltaFlag = 0; |
| 1156 | - int srcRev = -1; | |
| 1157 | - int rid = 0; | |
| 1158 | - if( zTemp = svn_find_header(rec, "Text-delta") ){ | |
| 1129 | + int srcRev = 0; | |
| 1130 | + if( (zTemp = svn_find_header(rec, "Text-delta")) ){ | |
| 1159 | 1131 | deltaFlag = strncmp(zTemp, "true", 4)==0; |
| 1160 | 1132 | } |
| 1161 | 1133 | if( zSrcPath ){ |
| 1162 | 1134 | zTemp = svn_find_header(rec, "Node-copyfrom-rev"); |
| 1163 | 1135 | if( zTemp ){ |
| @@ -1164,53 +1136,56 @@ | ||
| 1164 | 1136 | srcRev = atoi(zTemp); |
| 1165 | 1137 | }else{ |
| 1166 | 1138 | fossil_fatal("Missing copyfrom-rev"); |
| 1167 | 1139 | } |
| 1168 | 1140 | } |
| 1169 | - if( !flatFlag ){ | |
| 1141 | + if( !gsvn.flatFlag ){ | |
| 1170 | 1142 | if( strncmp(zPath, "branches/", 9)==0 ){ |
| 1171 | - int i; | |
| 1172 | - sqlite3_snprintf(sizeof(zBranch), zBranch, "%s", zPath+9); | |
| 1173 | - for( i=0; zBranch[i]; i++ ){ | |
| 1174 | - if( zBranch[i]=='/' ) zBranch[i]=0; | |
| 1175 | - } | |
| 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'; | |
| 1176 | 1150 | }else |
| 1177 | 1151 | if( strncmp(zPath, "trunk/", 6)==0 ){ |
| 1178 | - memcpy(zBranch, "trunk", 6); | |
| 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); | |
| 1179 | 1159 | } |
| 1180 | 1160 | } |
| 1181 | 1161 | if( strncmp(zAction, "delete", 6)==0 |
| 1182 | 1162 | || strncmp(zAction, "replace", 7)==0 ) |
| 1183 | 1163 | { |
| 1184 | - db_bind_int(&delFile, ":rev", rev); | |
| 1185 | - db_bind_text(&delFile, ":path", zPath); | |
| 1186 | - db_step(&delFile); | |
| 1187 | - db_reset(&delFile); | |
| 1164 | + db_bind_null(&addHist, ":rid"); | |
| 1165 | + db_bind_text(&addHist, ":path", zPath); | |
| 1166 | + db_bind_null(&addHist, ":perm"); | |
| 1167 | + db_step(&addHist); | |
| 1168 | + db_reset(&addHist); | |
| 1188 | 1169 | } /* no 'else' here since 'replace' does both a 'delete' and an 'add' */ |
| 1189 | 1170 | if( strncmp(zAction, "add", 3)==0 |
| 1190 | 1171 | || strncmp(zAction, "replace", 7)==0 ) |
| 1191 | 1172 | { |
| 1192 | 1173 | if( zKind==0 ){ |
| 1193 | 1174 | fossil_fatal("Missing Node-kind"); |
| 1194 | 1175 | }else if( strncmp(zKind, "dir", 3)==0 ){ |
| 1195 | 1176 | if( zSrcPath ){ |
| 1196 | - db_multi_exec( | |
| 1197 | - "INSERT INTO xfiles (trev, tpath, trid, tperm) " | |
| 1198 | - " SELECT %d, %Q||substr(tpath, length(%Q)+1), trid, tperm " | |
| 1199 | - " FROM xfiles " | |
| 1200 | - " WHERE trev=%d AND tpath GLOB '%q/*'", | |
| 1201 | - rev, zPath, zSrcPath, srcRev, zSrcPath | |
| 1202 | - ); | |
| 1203 | - if( !flatFlag ){ | |
| 1177 | + db_bind_int(&cpyPath, ":srcrev", srcRev); | |
| 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 ){ | |
| 1204 | 1183 | if( strncmp(zPath, "branches/", 9)==0 ){ |
| 1205 | - zTemp = zPath+9; | |
| 1206 | - while( *zTemp && *zTemp!='/' ){ zTemp++; } | |
| 1184 | + zTemp = zPath+9+strlen(gsvn.zBranch); | |
| 1207 | 1185 | if( *zTemp==0 ){ |
| 1208 | - db_bind_int(&setParent, ":parent", srcRev); | |
| 1209 | - db_bind_int(&setParent, ":rev", rev); | |
| 1210 | - db_step(&setParent); | |
| 1211 | - db_reset(&setParent); | |
| 1186 | + gsvn.parent = srcRev; | |
| 1212 | 1187 | } |
| 1213 | 1188 | }else if( strncmp(zPath, "tags/", 5)==0 ){ |
| 1214 | 1189 | zTemp = zPath+5; |
| 1215 | 1190 | db_bind_int(&insTag, ":rev", srcRev); |
| 1216 | 1191 | db_bind_text(&insTag, ":tag", zTemp); |
| @@ -1218,14 +1193,17 @@ | ||
| 1218 | 1193 | db_reset(&insTag); |
| 1219 | 1194 | } |
| 1220 | 1195 | } |
| 1221 | 1196 | } |
| 1222 | 1197 | }else{ |
| 1198 | + int rid = 0; | |
| 1223 | 1199 | if( zSrcPath ){ |
| 1224 | - rid = db_int(0, | |
| 1225 | - "SELECT trid FROM xfiles WHERE trev=%d AND tpath=%Q", | |
| 1226 | - srcRev, zSrcPath); | |
| 1200 | + rid = db_int(0, "SELECT trid, max(trev) FROM xhist" | |
| 1201 | + " WHERE trev<=%d AND tpath=%Q", srcRev, zSrcPath); | |
| 1202 | + if( rid==0 ){ | |
| 1203 | + fossil_fatal("Reference to non-existent path/revision"); | |
| 1204 | + } | |
| 1227 | 1205 | } |
| 1228 | 1206 | if( deltaFlag ){ |
| 1229 | 1207 | Blob deltaSrc; |
| 1230 | 1208 | Blob target; |
| 1231 | 1209 | if( rid!=0 ){ |
| @@ -1236,64 +1214,58 @@ | ||
| 1236 | 1214 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1237 | 1215 | rid = content_put(&target); |
| 1238 | 1216 | }else if( rec.contentFlag ){ |
| 1239 | 1217 | rid = content_put(&rec.content); |
| 1240 | 1218 | } |
| 1241 | - db_bind_int(&insFile, ":rev", rev); | |
| 1242 | - db_bind_int(&insFile, ":rid", rid); | |
| 1243 | - db_bind_text(&insFile, ":path", zPath); | |
| 1244 | - db_bind_text(&insFile, ":perm", zPerm); | |
| 1245 | - db_step(&insFile); | |
| 1246 | - db_reset(&insFile); | |
| 1219 | + db_bind_int(&addHist, ":rid", rid); | |
| 1220 | + db_bind_text(&addHist, ":path", zPath); | |
| 1221 | + db_bind_text(&addHist, ":perm", zPerm); | |
| 1222 | + db_step(&addHist); | |
| 1223 | + db_reset(&addHist); | |
| 1247 | 1224 | } |
| 1248 | 1225 | }else |
| 1249 | 1226 | if( strncmp(zAction, "change", 6)==0 ){ |
| 1227 | + int rid = 0; | |
| 1250 | 1228 | if( zKind==0 ){ |
| 1251 | 1229 | fossil_fatal("Missing Node-kind"); |
| 1252 | 1230 | } |
| 1253 | 1231 | if( strncmp(zKind, "dir", 3)==0 ) continue; |
| 1254 | 1232 | if( deltaFlag ){ |
| 1255 | 1233 | Blob deltaSrc; |
| 1256 | 1234 | Blob target; |
| 1257 | - rid = db_int(0, "SELECT trid FROM xfiles WHERE tpath=%Q AND trev=%d", | |
| 1258 | - zPath, rev-1); | |
| 1235 | + rid = db_int(0, "SELECT trid, max(trev) FROM xhist" | |
| 1236 | + " WHERE trev<=%d AND tpath=%Q", gsvn.rev-1, zPath); | |
| 1259 | 1237 | content_get(rid, &deltaSrc); |
| 1260 | 1238 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1261 | 1239 | rid = content_put(&target); |
| 1262 | 1240 | }else{ |
| 1263 | 1241 | rid = content_put(&rec.content); |
| 1264 | 1242 | } |
| 1265 | - db_bind_int(&insFile, ":rev", rev); | |
| 1266 | - db_bind_int(&insFile, ":rid", rid); | |
| 1267 | - db_bind_text(&insFile, ":path", zPath); | |
| 1268 | - db_bind_text(&insFile, ":perm", zPerm); | |
| 1269 | - db_step(&insFile); | |
| 1270 | - db_reset(&insFile); | |
| 1243 | + db_bind_int(&addHist, ":rid", rid); | |
| 1244 | + db_bind_text(&addHist, ":path", zPath); | |
| 1245 | + db_bind_text(&addHist, ":perm", zPerm); | |
| 1246 | + db_step(&addHist); | |
| 1247 | + db_reset(&addHist); | |
| 1271 | 1248 | }else |
| 1272 | - if( strncmp(zAction, "delete", 6)==0){ /* already did this above */ | |
| 1273 | - }else{ | |
| 1249 | + if( strncmp(zAction, "delete", 6)!=0 ){ /* already did this above */ | |
| 1274 | 1250 | fossil_fatal("Unknown Node-action"); |
| 1275 | 1251 | } |
| 1276 | 1252 | }else{ |
| 1277 | 1253 | fossil_fatal("Unknown record type"); |
| 1278 | 1254 | } |
| 1279 | 1255 | svn_free_rec(&rec); |
| 1280 | 1256 | } |
| 1281 | - if( !flatFlag ){ | |
| 1282 | - if( *zBranch ){ | |
| 1283 | - db_bind_text(&setBranch, ":branch", zBranch); | |
| 1284 | - db_bind_int(&setBranch, ":rev", rev); | |
| 1285 | - db_step(&setBranch); | |
| 1286 | - } | |
| 1287 | - } | |
| 1288 | - db_finalize(&insRev); | |
| 1289 | - db_finalize(&insFile); | |
| 1257 | + if( gsvn.rev>0 ){ | |
| 1258 | + svn_create_manifest(); | |
| 1259 | + } | |
| 1260 | + fossil_free(gsvn.zUser); | |
| 1261 | + fossil_free(gsvn.zComment); | |
| 1262 | + fossil_free(gsvn.zDate); | |
| 1263 | + db_finalize(&addHist); | |
| 1290 | 1264 | db_finalize(&insTag); |
| 1291 | - db_finalize(&delFile); | |
| 1292 | - db_finalize(&setBranch); | |
| 1293 | - db_finalize(&setParent); | |
| 1294 | - svn_create_manifests(flatFlag); | |
| 1265 | + db_finalize(&cpyPath); | |
| 1266 | + fossil_print(" Done!\n"); | |
| 1295 | 1267 | } |
| 1296 | 1268 | |
| 1297 | 1269 | /* |
| 1298 | 1270 | ** COMMAND: import |
| 1299 | 1271 | ** |
| @@ -1325,11 +1297,11 @@ | ||
| 1325 | 1297 | char *zPassword; |
| 1326 | 1298 | FILE *pIn; |
| 1327 | 1299 | Stmt q; |
| 1328 | 1300 | int forceFlag = find_option("force", "f", 0)!=0; |
| 1329 | 1301 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1330 | - int flatFlag = find_option("flat", 0, 0)!=0; | |
| 1302 | + gsvn.flatFlag = find_option("flat", 0, 0)!=0; | |
| 1331 | 1303 | |
| 1332 | 1304 | verify_all_options(); |
| 1333 | 1305 | if( g.argc!=4 && g.argc!=5 ){ |
| 1334 | 1306 | usage("FORMAT REPOSITORY-NAME"); |
| 1335 | 1307 | } |
| @@ -1386,24 +1358,34 @@ | ||
| 1386 | 1358 | db_finalize(&q); |
| 1387 | 1359 | }else |
| 1388 | 1360 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1389 | 1361 | db_multi_exec( |
| 1390 | 1362 | "CREATE TEMP TABLE xrevisions(" |
| 1391 | - " trev INTEGER PRIMARY KEY, tuser TEXT, tmsg TEXT, ttime DATETIME," | |
| 1392 | - " tparent INT, tbranch TEXT, tuuid TEXT" | |
| 1363 | + " trev INTEGER PRIMARY KEY, tbranch TEXT, tuuid TEXT" | |
| 1364 | + ");" | |
| 1365 | + "CREATE TEMP TABLE xhist(" | |
| 1366 | + " trev INT, tpath TEXT NOT NULL, trid TEXT, tperm TEXT," | |
| 1367 | + " UNIQUE (trev, tpath) ON CONFLICT REPLACE" | |
| 1393 | 1368 | ");" |
| 1394 | 1369 | "CREATE TEMP TABLE xfiles(" |
| 1395 | - " trev INT, tpath TEXT, trid TEXT, tperm TEXT," | |
| 1396 | - " UNIQUE (trev, tpath) ON CONFLICT REPLACE" | |
| 1370 | + " tpath TEXT NOT NULL, trid TEXT, tperm TEXT," | |
| 1371 | + " UNIQUE (tpath) ON CONFLICT REPLACE" | |
| 1397 | 1372 | ");" |
| 1373 | + "CREATE TEMP TRIGGER xfilesdeltrig AFTER INSERT ON xhist FOR EACH ROW" | |
| 1374 | + " WHEN new.trid ISNULL" | |
| 1375 | + " BEGIN DELETE FROM xfiles WHERE xfiles.tpath=new.tpath; END;" | |
| 1376 | + "CREATE TEMP TRIGGER xfilesaddtrig AFTER INSERT ON xhist FOR EACH ROW" | |
| 1377 | + " WHEN new.trid NOTNULL BEGIN INSERT INTO xfiles(tpath,trid,tperm)" | |
| 1378 | + " VALUES(new.tpath, new.trid, new.tperm); END;" | |
| 1398 | 1379 | "CREATE TEMP TABLE xtags(" |
| 1399 | 1380 | " trev INT, ttag TEXT" |
| 1400 | 1381 | ");" |
| 1401 | 1382 | ); |
| 1402 | - svn_dump_import(pIn, flatFlag); | |
| 1383 | + svn_dump_import(pIn); | |
| 1403 | 1384 | } |
| 1404 | 1385 | |
| 1386 | + verify_cancel(); | |
| 1405 | 1387 | db_end_transaction(0); |
| 1406 | 1388 | db_begin_transaction(); |
| 1407 | 1389 | fossil_print("Rebuilding repository meta-data...\n"); |
| 1408 | 1390 | rebuild_db(0, 1, !incrFlag); |
| 1409 | 1391 | verify_cancel(); |
| 1410 | 1392 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -717,10 +717,19 @@ | |
| 717 | trim_newline(zLine); |
| 718 | fossil_fatal("bad fast-import line: [%s]", zLine); |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | typedef struct { |
| 723 | const char *zKey; |
| 724 | const char *zVal; |
| 725 | } KeyVal; |
| 726 | typedef struct { |
| @@ -880,133 +889,117 @@ | |
| 880 | rec->contentFlag = 0; |
| 881 | } |
| 882 | return 1; |
| 883 | } |
| 884 | |
| 885 | static void svn_create_manifests(int flatFlag){ |
| 886 | Blob manifest; |
| 887 | Stmt qRev; |
| 888 | Stmt qParent; |
| 889 | Stmt qFiles; |
| 890 | Stmt qTags; |
| 891 | Stmt setUuid; |
| 892 | |
| 893 | if( !flatFlag ){ |
| 894 | db_multi_exec("DELETE FROM xrevisions WHERE tbranch ISNULL;" |
| 895 | "UPDATE xrevisions SET tparent=(" |
| 896 | " SELECT ifnull(max(trev),-1) FROM xrevisions t" |
| 897 | " WHERE t.trev<xrevisions.trev" |
| 898 | " AND t.tbranch=xrevisions.tbranch" |
| 899 | " )" |
| 900 | " WHERE tparent ISNULL;" |
| 901 | "WITH xprefix AS ( " |
| 902 | " SELECT trev, CASE tbranch WHEN 'trunk' THEN 'trunk/'" |
| 903 | " ELSE 'branches/'||tbranch||'/' END xpref" |
| 904 | " FROM xrevisions" |
| 905 | " ), " |
| 906 | " x AS (SELECT trev xrev, xpref, length(xpref) xlen " |
| 907 | " FROM xprefix) " |
| 908 | " UPDATE xfiles SET tpath= " |
| 909 | " CASE substr(tpath,1,(SELECT xlen FROM x WHERE xrev=trev))" |
| 910 | " WHEN (SELECT xpref FROM x WHERE xrev=trev)" |
| 911 | " THEN substr(tpath,(SELECT xlen FROM x WHERE xrev=trev)+1)" |
| 912 | " END;" |
| 913 | "DELETE FROM xfiles WHERE tpath ISNULL"); |
| 914 | }else{ |
| 915 | db_multi_exec("UPDATE xrevisions SET tparent=trev-1"); |
| 916 | } |
| 917 | db_prepare(&qRev, "SELECT trev, tuser, tmsg, ttime, tparent, tbranch" |
| 918 | " FROM xrevisions " |
| 919 | " ORDER BY trev"); |
| 920 | db_prepare(&qParent, "SELECT tuuid, tbranch FROM xrevisions WHERE trev=:rev"); |
| 921 | db_prepare(&qFiles, "SELECT tpath, uuid, tperm" |
| 922 | " FROM xfiles JOIN blob ON xfiles.trid=blob.rid" |
| 923 | " WHERE trev=:rev ORDER BY tpath"); |
| 924 | db_prepare(&qTags, "SELECT ttag FROM xtags WHERE trev=:rev"); |
| 925 | db_prepare(&setUuid, "UPDATE xrevisions" |
| 926 | " SET tuuid=(SELECT uuid FROM blob WHERE rid=:rid)" |
| 927 | " WHERE trev=:rev"); |
| 928 | blob_zero(&manifest); |
| 929 | while( db_step(&qRev)==SQLITE_ROW ){ |
| 930 | int rev = db_column_int(&qRev, 0); |
| 931 | const char *zUser = db_column_text(&qRev, 1); |
| 932 | const char *zMsg = db_column_text(&qRev, 2); |
| 933 | const char *zTime = db_column_text(&qRev, 3); |
| 934 | int parentRev = db_column_int(&qRev, 4); |
| 935 | const char *zBranch = db_column_text(&qRev, 5); |
| 936 | int rid; |
| 937 | const char *zParentBranch = 0; |
| 938 | Blob mcksum; |
| 939 | blob_reset(&manifest); |
| 940 | if( zMsg ){ |
| 941 | blob_appendf(&manifest, "C %F\n", zMsg); |
| 942 | }else{ |
| 943 | blob_append(&manifest, "C (no\\scomment)\n", 16); |
| 944 | } |
| 945 | blob_appendf(&manifest, "D %s\n", zTime); |
| 946 | db_bind_int(&qFiles, ":rev", rev); |
| 947 | while( db_step(&qFiles)==SQLITE_ROW ){ |
| 948 | const char *zFile = db_column_text(&qFiles, 0); |
| 949 | const char *zUuid = db_column_text(&qFiles, 1); |
| 950 | const char *zPerm = db_column_text(&qFiles, 2); |
| 951 | blob_appendf(&manifest, "F %F %s %s\n", zFile, zUuid, zPerm); |
| 952 | } |
| 953 | db_reset(&qFiles); |
| 954 | if( parentRev>=0 ){ |
| 955 | const char *zParentUuid; |
| 956 | db_bind_int(&qParent, ":rev", parentRev); |
| 957 | db_step(&qParent); |
| 958 | zParentUuid = db_column_text(&qParent, 0); |
| 959 | blob_appendf(&manifest, "P %s\n", zParentUuid); |
| 960 | if( !flatFlag ){ |
| 961 | zParentBranch = db_column_text(&qParent, 1); |
| 962 | if( strcmp(zBranch, zParentBranch)!=0 ){ |
| 963 | blob_appendf(&manifest, "T *branch * %s\n", zBranch); |
| 964 | blob_appendf(&manifest, "T *sym-%s *\n", zBranch); |
| 965 | zParentBranch = mprintf("%s", zParentBranch); |
| 966 | }else{ |
| 967 | zParentBranch = 0; |
| 968 | } |
| 969 | } |
| 970 | db_reset(&qParent); |
| 971 | }else{ |
| 972 | blob_appendf(&manifest, "T *branch * trunk\n"); |
| 973 | blob_appendf(&manifest, "T *sym-trunk *\n"); |
| 974 | } |
| 975 | db_bind_int(&qTags, ":rev", rev); |
| 976 | while( db_step(&qTags)==SQLITE_ROW ){ |
| 977 | const char *zTag = db_column_text(&qTags, 0); |
| 978 | blob_appendf(&manifest, "T +sym-%s *\n", zTag); |
| 979 | } |
| 980 | db_reset(&qTags); |
| 981 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", rev); |
| 982 | if( zParentBranch ) { |
| 983 | blob_appendf(&manifest, "T -sym-%s *\n", zParentBranch); |
| 984 | zParentBranch = 0; |
| 985 | } |
| 986 | if( zUser ){ |
| 987 | blob_appendf(&manifest, "U %F\n", zUser); |
| 988 | }else{ |
| 989 | const char *zUserOvrd = find_option("user-override",0,1); |
| 990 | blob_appendf(&manifest, "U %F\n", |
| 991 | zUserOvrd ? zUserOvrd : login_name()); |
| 992 | } |
| 993 | md5sum_blob(&manifest, &mcksum); |
| 994 | blob_appendf(&manifest, "Z %b\n", &mcksum); |
| 995 | blob_reset(&mcksum); |
| 996 | |
| 997 | rid = content_put(&manifest); |
| 998 | db_bind_int(&setUuid, ":rid", rid); |
| 999 | db_bind_int(&setUuid, ":rev", rev); |
| 1000 | db_step(&setUuid); |
| 1001 | db_reset(&setUuid); |
| 1002 | } |
| 1003 | db_finalize(&qRev); |
| 1004 | db_finalize(&qParent); |
| 1005 | db_finalize(&qFiles); |
| 1006 | db_finalize(&qTags); |
| 1007 | db_finalize(&setUuid); |
| 1008 | } |
| 1009 | |
| 1010 | static u64 svn_get_varint(const char **pz){ |
| 1011 | unsigned int v = 0; |
| 1012 | do{ |
| @@ -1062,23 +1055,18 @@ | |
| 1062 | |
| 1063 | /* |
| 1064 | ** Read the svn-dump format from pIn and insert the corresponding |
| 1065 | ** content into the database. |
| 1066 | */ |
| 1067 | static void svn_dump_import(FILE *pIn, int flatFlag){ |
| 1068 | SvnRecord rec; |
| 1069 | int ver; |
| 1070 | const char *zTemp; |
| 1071 | const char *zUuid; |
| 1072 | char zBranch[200] = {0}; |
| 1073 | Stmt insRev; |
| 1074 | Stmt insFile; |
| 1075 | Stmt insTag; |
| 1076 | Stmt delFile; |
| 1077 | Stmt setBranch; |
| 1078 | Stmt setParent; |
| 1079 | int rev = 0; |
| 1080 | |
| 1081 | /* version */ |
| 1082 | if( svn_read_rec(pIn, &rec) |
| 1083 | && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ |
| 1084 | ver = atoi(zTemp); |
| @@ -1093,71 +1081,55 @@ | |
| 1093 | if( !svn_read_rec(pIn, &rec) || !(zUuid = svn_find_header(rec, "UUID")) ){ |
| 1094 | fossil_fatal("Missing UUID!"); |
| 1095 | } |
| 1096 | svn_free_rec(&rec); |
| 1097 | /* content */ |
| 1098 | db_prepare(&insRev, |
| 1099 | "INSERT INTO xrevisions (trev, tuser, tmsg, ttime) " |
| 1100 | "VALUES(:rev, :user, :msg, :time)" |
| 1101 | ); |
| 1102 | db_prepare(&insFile, |
| 1103 | "INSERT INTO xfiles (trev, tpath, trid, tperm) " |
| 1104 | "VALUES(:rev, :path, :rid, :perm)" |
| 1105 | ); |
| 1106 | db_prepare(&insTag, "INSERT INTO xtags (trev, ttag) VALUES(:rev, :tag)"); |
| 1107 | db_prepare(&delFile, |
| 1108 | "DELETE FROM xfiles " |
| 1109 | "WHERE trev=:rev " |
| 1110 | " AND (tpath=:path OR (tpath>:path||'/' AND tpath<:path||'0'))" |
| 1111 | ); |
| 1112 | db_prepare(&setBranch, |
| 1113 | "UPDATE xrevisions SET tbranch=:branch " |
| 1114 | "WHERE trev=:rev" |
| 1115 | ); |
| 1116 | db_prepare(&setParent, |
| 1117 | "UPDATE xrevisions SET tparent=:parent " |
| 1118 | "WHERE trev=:rev" |
| 1119 | ); |
| 1120 | while( svn_read_rec(pIn, &rec) ){ |
| 1121 | if( zTemp = svn_find_header(rec, "Revision-number") ){ |
| 1122 | const char *zUser = svn_find_prop(rec, "svn:author"); |
| 1123 | const char *zLog = svn_find_prop(rec, "svn:log"); |
| 1124 | const char *zDate = svn_find_prop(rec, "svn:date"); |
| 1125 | if( !flatFlag ){ |
| 1126 | if( *zBranch ){ |
| 1127 | db_bind_text(&setBranch, ":branch", zBranch); |
| 1128 | db_bind_int(&setBranch, ":rev", rev); |
| 1129 | db_step(&setBranch); |
| 1130 | db_reset(&setBranch); |
| 1131 | zBranch[0] = 0; |
| 1132 | } |
| 1133 | } |
| 1134 | zDate = date_in_standard_format(zDate); |
| 1135 | rev = atoi(zTemp); |
| 1136 | db_bind_int(&insRev, ":rev", rev); |
| 1137 | db_bind_text(&insRev, ":user", zUser); |
| 1138 | db_bind_text(&insRev, ":msg", zLog); |
| 1139 | db_bind_text(&insRev, ":time", zDate); |
| 1140 | db_step(&insRev); |
| 1141 | db_reset(&insRev); |
| 1142 | fossil_free(zDate); |
| 1143 | if( rev>0 ){ |
| 1144 | db_multi_exec("INSERT INTO xfiles (trev, tpath, trid, tperm) " |
| 1145 | "SELECT %d, tpath, trid, tperm FROM xfiles " |
| 1146 | "WHERE trev=%d", rev, rev-1); |
| 1147 | } |
| 1148 | }else |
| 1149 | if( zTemp = svn_find_header(rec, "Node-path") ){ |
| 1150 | const char *zPath = zTemp; |
| 1151 | const char *zAction = svn_find_header(rec, "Node-action"); |
| 1152 | const char *zKind = svn_find_header(rec, "Node-kind"); |
| 1153 | const char *zSrcPath = svn_find_header(rec, "Node-copyfrom-path"); |
| 1154 | const char *zPerm = svn_find_prop(rec, "svn:executable") ? "x" : 0; |
| 1155 | int deltaFlag = 0; |
| 1156 | int srcRev = -1; |
| 1157 | int rid = 0; |
| 1158 | if( zTemp = svn_find_header(rec, "Text-delta") ){ |
| 1159 | deltaFlag = strncmp(zTemp, "true", 4)==0; |
| 1160 | } |
| 1161 | if( zSrcPath ){ |
| 1162 | zTemp = svn_find_header(rec, "Node-copyfrom-rev"); |
| 1163 | if( zTemp ){ |
| @@ -1164,53 +1136,56 @@ | |
| 1164 | srcRev = atoi(zTemp); |
| 1165 | }else{ |
| 1166 | fossil_fatal("Missing copyfrom-rev"); |
| 1167 | } |
| 1168 | } |
| 1169 | if( !flatFlag ){ |
| 1170 | if( strncmp(zPath, "branches/", 9)==0 ){ |
| 1171 | int i; |
| 1172 | sqlite3_snprintf(sizeof(zBranch), zBranch, "%s", zPath+9); |
| 1173 | for( i=0; zBranch[i]; i++ ){ |
| 1174 | if( zBranch[i]=='/' ) zBranch[i]=0; |
| 1175 | } |
| 1176 | }else |
| 1177 | if( strncmp(zPath, "trunk/", 6)==0 ){ |
| 1178 | memcpy(zBranch, "trunk", 6); |
| 1179 | } |
| 1180 | } |
| 1181 | if( strncmp(zAction, "delete", 6)==0 |
| 1182 | || strncmp(zAction, "replace", 7)==0 ) |
| 1183 | { |
| 1184 | db_bind_int(&delFile, ":rev", rev); |
| 1185 | db_bind_text(&delFile, ":path", zPath); |
| 1186 | db_step(&delFile); |
| 1187 | db_reset(&delFile); |
| 1188 | } /* no 'else' here since 'replace' does both a 'delete' and an 'add' */ |
| 1189 | if( strncmp(zAction, "add", 3)==0 |
| 1190 | || strncmp(zAction, "replace", 7)==0 ) |
| 1191 | { |
| 1192 | if( zKind==0 ){ |
| 1193 | fossil_fatal("Missing Node-kind"); |
| 1194 | }else if( strncmp(zKind, "dir", 3)==0 ){ |
| 1195 | if( zSrcPath ){ |
| 1196 | db_multi_exec( |
| 1197 | "INSERT INTO xfiles (trev, tpath, trid, tperm) " |
| 1198 | " SELECT %d, %Q||substr(tpath, length(%Q)+1), trid, tperm " |
| 1199 | " FROM xfiles " |
| 1200 | " WHERE trev=%d AND tpath GLOB '%q/*'", |
| 1201 | rev, zPath, zSrcPath, srcRev, zSrcPath |
| 1202 | ); |
| 1203 | if( !flatFlag ){ |
| 1204 | if( strncmp(zPath, "branches/", 9)==0 ){ |
| 1205 | zTemp = zPath+9; |
| 1206 | while( *zTemp && *zTemp!='/' ){ zTemp++; } |
| 1207 | if( *zTemp==0 ){ |
| 1208 | db_bind_int(&setParent, ":parent", srcRev); |
| 1209 | db_bind_int(&setParent, ":rev", rev); |
| 1210 | db_step(&setParent); |
| 1211 | db_reset(&setParent); |
| 1212 | } |
| 1213 | }else if( strncmp(zPath, "tags/", 5)==0 ){ |
| 1214 | zTemp = zPath+5; |
| 1215 | db_bind_int(&insTag, ":rev", srcRev); |
| 1216 | db_bind_text(&insTag, ":tag", zTemp); |
| @@ -1218,14 +1193,17 @@ | |
| 1218 | db_reset(&insTag); |
| 1219 | } |
| 1220 | } |
| 1221 | } |
| 1222 | }else{ |
| 1223 | if( zSrcPath ){ |
| 1224 | rid = db_int(0, |
| 1225 | "SELECT trid FROM xfiles WHERE trev=%d AND tpath=%Q", |
| 1226 | srcRev, zSrcPath); |
| 1227 | } |
| 1228 | if( deltaFlag ){ |
| 1229 | Blob deltaSrc; |
| 1230 | Blob target; |
| 1231 | if( rid!=0 ){ |
| @@ -1236,64 +1214,58 @@ | |
| 1236 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1237 | rid = content_put(&target); |
| 1238 | }else if( rec.contentFlag ){ |
| 1239 | rid = content_put(&rec.content); |
| 1240 | } |
| 1241 | db_bind_int(&insFile, ":rev", rev); |
| 1242 | db_bind_int(&insFile, ":rid", rid); |
| 1243 | db_bind_text(&insFile, ":path", zPath); |
| 1244 | db_bind_text(&insFile, ":perm", zPerm); |
| 1245 | db_step(&insFile); |
| 1246 | db_reset(&insFile); |
| 1247 | } |
| 1248 | }else |
| 1249 | if( strncmp(zAction, "change", 6)==0 ){ |
| 1250 | if( zKind==0 ){ |
| 1251 | fossil_fatal("Missing Node-kind"); |
| 1252 | } |
| 1253 | if( strncmp(zKind, "dir", 3)==0 ) continue; |
| 1254 | if( deltaFlag ){ |
| 1255 | Blob deltaSrc; |
| 1256 | Blob target; |
| 1257 | rid = db_int(0, "SELECT trid FROM xfiles WHERE tpath=%Q AND trev=%d", |
| 1258 | zPath, rev-1); |
| 1259 | content_get(rid, &deltaSrc); |
| 1260 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1261 | rid = content_put(&target); |
| 1262 | }else{ |
| 1263 | rid = content_put(&rec.content); |
| 1264 | } |
| 1265 | db_bind_int(&insFile, ":rev", rev); |
| 1266 | db_bind_int(&insFile, ":rid", rid); |
| 1267 | db_bind_text(&insFile, ":path", zPath); |
| 1268 | db_bind_text(&insFile, ":perm", zPerm); |
| 1269 | db_step(&insFile); |
| 1270 | db_reset(&insFile); |
| 1271 | }else |
| 1272 | if( strncmp(zAction, "delete", 6)==0){ /* already did this above */ |
| 1273 | }else{ |
| 1274 | fossil_fatal("Unknown Node-action"); |
| 1275 | } |
| 1276 | }else{ |
| 1277 | fossil_fatal("Unknown record type"); |
| 1278 | } |
| 1279 | svn_free_rec(&rec); |
| 1280 | } |
| 1281 | if( !flatFlag ){ |
| 1282 | if( *zBranch ){ |
| 1283 | db_bind_text(&setBranch, ":branch", zBranch); |
| 1284 | db_bind_int(&setBranch, ":rev", rev); |
| 1285 | db_step(&setBranch); |
| 1286 | } |
| 1287 | } |
| 1288 | db_finalize(&insRev); |
| 1289 | db_finalize(&insFile); |
| 1290 | db_finalize(&insTag); |
| 1291 | db_finalize(&delFile); |
| 1292 | db_finalize(&setBranch); |
| 1293 | db_finalize(&setParent); |
| 1294 | svn_create_manifests(flatFlag); |
| 1295 | } |
| 1296 | |
| 1297 | /* |
| 1298 | ** COMMAND: import |
| 1299 | ** |
| @@ -1325,11 +1297,11 @@ | |
| 1325 | char *zPassword; |
| 1326 | FILE *pIn; |
| 1327 | Stmt q; |
| 1328 | int forceFlag = find_option("force", "f", 0)!=0; |
| 1329 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1330 | int flatFlag = find_option("flat", 0, 0)!=0; |
| 1331 | |
| 1332 | verify_all_options(); |
| 1333 | if( g.argc!=4 && g.argc!=5 ){ |
| 1334 | usage("FORMAT REPOSITORY-NAME"); |
| 1335 | } |
| @@ -1386,24 +1358,34 @@ | |
| 1386 | db_finalize(&q); |
| 1387 | }else |
| 1388 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1389 | db_multi_exec( |
| 1390 | "CREATE TEMP TABLE xrevisions(" |
| 1391 | " trev INTEGER PRIMARY KEY, tuser TEXT, tmsg TEXT, ttime DATETIME," |
| 1392 | " tparent INT, tbranch TEXT, tuuid TEXT" |
| 1393 | ");" |
| 1394 | "CREATE TEMP TABLE xfiles(" |
| 1395 | " trev INT, tpath TEXT, trid TEXT, tperm TEXT," |
| 1396 | " UNIQUE (trev, tpath) ON CONFLICT REPLACE" |
| 1397 | ");" |
| 1398 | "CREATE TEMP TABLE xtags(" |
| 1399 | " trev INT, ttag TEXT" |
| 1400 | ");" |
| 1401 | ); |
| 1402 | svn_dump_import(pIn, flatFlag); |
| 1403 | } |
| 1404 | |
| 1405 | db_end_transaction(0); |
| 1406 | db_begin_transaction(); |
| 1407 | fossil_print("Rebuilding repository meta-data...\n"); |
| 1408 | rebuild_db(0, 1, !incrFlag); |
| 1409 | verify_cancel(); |
| 1410 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -717,10 +717,19 @@ | |
| 717 | trim_newline(zLine); |
| 718 | fossil_fatal("bad fast-import line: [%s]", zLine); |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | static struct{ |
| 723 | int rev; /* SVN revision number */ |
| 724 | int parent; /* SVN revision number of parent check-in */ |
| 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; |
| 735 | typedef struct { |
| @@ -880,133 +889,117 @@ | |
| 889 | rec->contentFlag = 0; |
| 890 | } |
| 891 | return 1; |
| 892 | } |
| 893 | |
| 894 | static void svn_create_manifest( |
| 895 | ){ |
| 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 | |
| 907 | db_static_prepare(&insRev, "REPLACE INTO xrevisions (trev, tbranch, tuuid) " |
| 908 | "VALUES(:rev, :branch, " |
| 909 | " (SELECT uuid FROM blob WHERE rid=:rid))"); |
| 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); |
| 923 | db_bind_text(&insRev, ":branch", gsvn.zBranch); |
| 924 | db_bind_int(&insRev, ":rid", 0); |
| 925 | db_step(&insRev); |
| 926 | db_reset(&insRev); |
| 927 | }else{ |
| 928 | static int prevRev = -1; |
| 929 | gsvn.parent = prevRev; |
| 930 | prevRev = gsvn.rev; |
| 931 | } |
| 932 | blob_zero(&manifest); |
| 933 | if( gsvn.zComment ){ |
| 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); |
| 961 | blob_appendf(&manifest, "P %s\n", zParentUuid); |
| 962 | if( !gsvn.flatFlag ){ |
| 963 | zParentBranch = db_column_text(&qParent, 1); |
| 964 | if( strcmp(gsvn.zBranch, zParentBranch)!=0 ){ |
| 965 | blob_appendf(&manifest, "T *branch * %s\n", gsvn.zBranch); |
| 966 | blob_appendf(&manifest, "T *sym-%s *\n", gsvn.zBranch); |
| 967 | zParentBranch = mprintf("%s", zParentBranch); |
| 968 | }else{ |
| 969 | zParentBranch = 0; |
| 970 | } |
| 971 | } |
| 972 | }else{ |
| 973 | blob_appendf(&manifest, "T *branch * trunk\n"); |
| 974 | blob_appendf(&manifest, "T *sym-trunk *\n"); |
| 975 | } |
| 976 | db_bind_int(&qTags, ":rev", gsvn.rev); |
| 977 | while( db_step(&qTags)==SQLITE_ROW ){ |
| 978 | const char *zTag = db_column_text(&qTags, 0); |
| 979 | blob_appendf(&manifest, "T +sym-%s *\n", zTag); |
| 980 | } |
| 981 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 982 | if( zParentBranch ) { |
| 983 | blob_appendf(&manifest, "T -sym-%s *\n", zParentBranch); |
| 984 | } |
| 985 | if( gsvn.zUser ){ |
| 986 | blob_appendf(&manifest, "U %F\n", gsvn.zUser); |
| 987 | }else{ |
| 988 | const char *zUserOvrd = find_option("user-override",0,1); |
| 989 | blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : login_name()); |
| 990 | } |
| 991 | md5sum_blob(&manifest, &mcksum); |
| 992 | blob_appendf(&manifest, "Z %b\n", &mcksum); |
| 993 | blob_reset(&mcksum); |
| 994 | |
| 995 | rid = content_put(&manifest); |
| 996 | blob_reset(&manifest); |
| 997 | db_bind_int(&insRev, ":rev", gsvn.rev); |
| 998 | db_bind_text(&insRev, ":branch", gsvn.zBranch); |
| 999 | db_bind_int(&insRev, ":rid", rid); |
| 1000 | db_step(&insRev); |
| 1001 | } |
| 1002 | |
| 1003 | static u64 svn_get_varint(const char **pz){ |
| 1004 | unsigned int v = 0; |
| 1005 | do{ |
| @@ -1062,23 +1055,18 @@ | |
| 1055 | |
| 1056 | /* |
| 1057 | ** Read the svn-dump format from pIn and insert the corresponding |
| 1058 | ** content into the database. |
| 1059 | */ |
| 1060 | static void svn_dump_import(FILE *pIn){ |
| 1061 | SvnRecord rec; |
| 1062 | int ver; |
| 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); |
| @@ -1093,71 +1081,55 @@ | |
| 1081 | if( !svn_read_rec(pIn, &rec) || !(zUuid = svn_find_header(rec, "UUID")) ){ |
| 1082 | fossil_fatal("Missing UUID!"); |
| 1083 | } |
| 1084 | svn_free_rec(&rec); |
| 1085 | /* content */ |
| 1086 | db_prepare(&addHist, |
| 1087 | "INSERT INTO xhist (trev, tpath, trid, tperm) " |
| 1088 | "VALUES(:rev, :path, :rid, :perm)" |
| 1089 | ); |
| 1090 | db_prepare(&insTag, "INSERT INTO xtags (trev, ttag) VALUES(:rev, :tag)"); |
| 1091 | db_prepare(&cpyPath, |
| 1092 | "WITH xsrc AS (SELECT * FROM (" |
| 1093 | " SELECT tpath, trid, tperm, max(trev) trev FROM xhist" |
| 1094 | " WHERE trev<=:srcrev GROUP BY tpath" |
| 1095 | " ) WHERE trid NOTNULL)" |
| 1096 | "INSERT INTO xhist (trev, tpath, trid, tperm)" |
| 1097 | " SELECT :rev, :path||substr(tpath, length(:srcpath)+1), trid, tperm" |
| 1098 | " FROM xsrc WHERE tpath>:srcpath||'/' AND tpath<:srcpath||0" |
| 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); |
| 1110 | } |
| 1111 | /* start new revision */ |
| 1112 | gsvn.rev = atoi(zTemp); |
| 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 */ |
| 1123 | const char *zPath = zTemp; |
| 1124 | const char *zAction = svn_find_header(rec, "Node-action"); |
| 1125 | const char *zKind = svn_find_header(rec, "Node-kind"); |
| 1126 | const char *zSrcPath = svn_find_header(rec, "Node-copyfrom-path"); |
| 1127 | const char *zPerm = svn_find_prop(rec, "svn:executable") ? "x" : 0; |
| 1128 | int deltaFlag = 0; |
| 1129 | int srcRev = 0; |
| 1130 | if( (zTemp = svn_find_header(rec, "Text-delta")) ){ |
| 1131 | deltaFlag = strncmp(zTemp, "true", 4)==0; |
| 1132 | } |
| 1133 | if( zSrcPath ){ |
| 1134 | zTemp = svn_find_header(rec, "Node-copyfrom-rev"); |
| 1135 | if( zTemp ){ |
| @@ -1164,53 +1136,56 @@ | |
| 1136 | srcRev = atoi(zTemp); |
| 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 | { |
| 1164 | db_bind_null(&addHist, ":rid"); |
| 1165 | db_bind_text(&addHist, ":path", zPath); |
| 1166 | db_bind_null(&addHist, ":perm"); |
| 1167 | db_step(&addHist); |
| 1168 | db_reset(&addHist); |
| 1169 | } /* no 'else' here since 'replace' does both a 'delete' and an 'add' */ |
| 1170 | if( strncmp(zAction, "add", 3)==0 |
| 1171 | || strncmp(zAction, "replace", 7)==0 ) |
| 1172 | { |
| 1173 | if( zKind==0 ){ |
| 1174 | fossil_fatal("Missing Node-kind"); |
| 1175 | }else if( strncmp(zKind, "dir", 3)==0 ){ |
| 1176 | if( zSrcPath ){ |
| 1177 | db_bind_int(&cpyPath, ":srcrev", srcRev); |
| 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); |
| @@ -1218,14 +1193,17 @@ | |
| 1193 | db_reset(&insTag); |
| 1194 | } |
| 1195 | } |
| 1196 | } |
| 1197 | }else{ |
| 1198 | int rid = 0; |
| 1199 | if( zSrcPath ){ |
| 1200 | rid = db_int(0, "SELECT trid, max(trev) FROM xhist" |
| 1201 | " WHERE trev<=%d AND tpath=%Q", srcRev, zSrcPath); |
| 1202 | if( rid==0 ){ |
| 1203 | fossil_fatal("Reference to non-existent path/revision"); |
| 1204 | } |
| 1205 | } |
| 1206 | if( deltaFlag ){ |
| 1207 | Blob deltaSrc; |
| 1208 | Blob target; |
| 1209 | if( rid!=0 ){ |
| @@ -1236,64 +1214,58 @@ | |
| 1214 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1215 | rid = content_put(&target); |
| 1216 | }else if( rec.contentFlag ){ |
| 1217 | rid = content_put(&rec.content); |
| 1218 | } |
| 1219 | db_bind_int(&addHist, ":rid", rid); |
| 1220 | db_bind_text(&addHist, ":path", zPath); |
| 1221 | db_bind_text(&addHist, ":perm", zPerm); |
| 1222 | db_step(&addHist); |
| 1223 | db_reset(&addHist); |
| 1224 | } |
| 1225 | }else |
| 1226 | if( strncmp(zAction, "change", 6)==0 ){ |
| 1227 | int rid = 0; |
| 1228 | if( zKind==0 ){ |
| 1229 | fossil_fatal("Missing Node-kind"); |
| 1230 | } |
| 1231 | if( strncmp(zKind, "dir", 3)==0 ) continue; |
| 1232 | if( deltaFlag ){ |
| 1233 | Blob deltaSrc; |
| 1234 | Blob target; |
| 1235 | rid = db_int(0, "SELECT trid, max(trev) FROM xhist" |
| 1236 | " WHERE trev<=%d AND tpath=%Q", gsvn.rev-1, zPath); |
| 1237 | content_get(rid, &deltaSrc); |
| 1238 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1239 | rid = content_put(&target); |
| 1240 | }else{ |
| 1241 | rid = content_put(&rec.content); |
| 1242 | } |
| 1243 | db_bind_int(&addHist, ":rid", rid); |
| 1244 | db_bind_text(&addHist, ":path", zPath); |
| 1245 | db_bind_text(&addHist, ":perm", zPerm); |
| 1246 | db_step(&addHist); |
| 1247 | db_reset(&addHist); |
| 1248 | }else |
| 1249 | if( strncmp(zAction, "delete", 6)!=0 ){ /* already did this above */ |
| 1250 | fossil_fatal("Unknown Node-action"); |
| 1251 | } |
| 1252 | }else{ |
| 1253 | fossil_fatal("Unknown record type"); |
| 1254 | } |
| 1255 | svn_free_rec(&rec); |
| 1256 | } |
| 1257 | if( gsvn.rev>0 ){ |
| 1258 | svn_create_manifest(); |
| 1259 | } |
| 1260 | fossil_free(gsvn.zUser); |
| 1261 | fossil_free(gsvn.zComment); |
| 1262 | fossil_free(gsvn.zDate); |
| 1263 | db_finalize(&addHist); |
| 1264 | db_finalize(&insTag); |
| 1265 | db_finalize(&cpyPath); |
| 1266 | fossil_print(" Done!\n"); |
| 1267 | } |
| 1268 | |
| 1269 | /* |
| 1270 | ** COMMAND: import |
| 1271 | ** |
| @@ -1325,11 +1297,11 @@ | |
| 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"); |
| 1307 | } |
| @@ -1386,24 +1358,34 @@ | |
| 1358 | db_finalize(&q); |
| 1359 | }else |
| 1360 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1361 | db_multi_exec( |
| 1362 | "CREATE TEMP TABLE xrevisions(" |
| 1363 | " trev INTEGER PRIMARY KEY, tbranch TEXT, tuuid TEXT" |
| 1364 | ");" |
| 1365 | "CREATE TEMP TABLE xhist(" |
| 1366 | " trev INT, tpath TEXT NOT NULL, trid TEXT, tperm TEXT," |
| 1367 | " UNIQUE (trev, tpath) ON CONFLICT REPLACE" |
| 1368 | ");" |
| 1369 | "CREATE TEMP TABLE xfiles(" |
| 1370 | " tpath TEXT NOT NULL, trid TEXT, tperm TEXT," |
| 1371 | " UNIQUE (tpath) ON CONFLICT REPLACE" |
| 1372 | ");" |
| 1373 | "CREATE TEMP TRIGGER xfilesdeltrig AFTER INSERT ON xhist FOR EACH ROW" |
| 1374 | " WHEN new.trid ISNULL" |
| 1375 | " BEGIN DELETE FROM xfiles WHERE xfiles.tpath=new.tpath; END;" |
| 1376 | "CREATE TEMP TRIGGER xfilesaddtrig AFTER INSERT ON xhist FOR EACH ROW" |
| 1377 | " WHEN new.trid NOTNULL BEGIN INSERT INTO xfiles(tpath,trid,tperm)" |
| 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 | db_begin_transaction(); |
| 1389 | fossil_print("Rebuilding repository meta-data...\n"); |
| 1390 | rebuild_db(0, 1, !incrFlag); |
| 1391 | verify_cancel(); |
| 1392 |