Fossil SCM
The mirror command is now able to export all of Fossil itself, though tags are still not exported.
Commit
a3471a5eef0b4764e316f15d478d990d0b176956e68857db03a94d999b398413
Parent
4a480954e7335ee…
1 file changed
+54
-9
+54
-9
| --- src/export.c | ||
| +++ src/export.c | ||
| @@ -867,10 +867,49 @@ | ||
| 867 | 867 | || (i>0 && zu[i-1]=='.')) ){ |
| 868 | 868 | zu[i] = '_'; |
| 869 | 869 | } |
| 870 | 870 | } |
| 871 | 871 | } |
| 872 | + | |
| 873 | +/* | |
| 874 | +** Quote a filename as a C-style string using \\ and \" if necessary. | |
| 875 | +** If quoting is not necessary, just return a copy of the input string. | |
| 876 | +** | |
| 877 | +** The return value is a held in memory obtained from fossil_malloc() | |
| 878 | +** and must be freed by the caller. | |
| 879 | +*/ | |
| 880 | +static char *mirror_quote_filename_if_needed(const char *zIn){ | |
| 881 | + int i, j; | |
| 882 | + char c; | |
| 883 | + int nSpecial = 0; | |
| 884 | + char *zOut; | |
| 885 | + for(i=0; (c = zIn[i])!=0; i++){ | |
| 886 | + if( c=='\\' || c=='"' || c=='\n' ){ | |
| 887 | + nSpecial++; | |
| 888 | + } | |
| 889 | + } | |
| 890 | + if( nSpecial==0 ){ | |
| 891 | + return fossil_strdup(zIn); | |
| 892 | + } | |
| 893 | + zOut = fossil_malloc( i+nSpecial+3 ); | |
| 894 | + zOut[0] = '"'; | |
| 895 | + for(i=0, j=1; (c = zIn[i])!=0; i++){ | |
| 896 | + if( c=='\\' || c=='"' || c=='\n' ){ | |
| 897 | + zOut[j++] = '\\'; | |
| 898 | + if( c=='\n' ){ | |
| 899 | + zOut[j++] = 'n'; | |
| 900 | + }else{ | |
| 901 | + zOut[j++] = c; | |
| 902 | + } | |
| 903 | + }else{ | |
| 904 | + zOut[j++] = c; | |
| 905 | + } | |
| 906 | + } | |
| 907 | + zOut[j++] = '"'; | |
| 908 | + zOut[j] = 0; | |
| 909 | + return zOut; | |
| 910 | +} | |
| 872 | 911 | |
| 873 | 912 | /* |
| 874 | 913 | ** Transfer a tag over to the mirror. "rid" is the BLOB.RID value for |
| 875 | 914 | ** the record that describes the tag. |
| 876 | 915 | ** |
| @@ -948,16 +987,18 @@ | ||
| 948 | 987 | FILE *xCmd, /* Write fast-import text on this pipe */ |
| 949 | 988 | int rid, /* BLOB.RID for the check-in to export */ |
| 950 | 989 | const char *zUuid, /* BLOB.UUID for the check-in to export */ |
| 951 | 990 | int *pnLimit /* Stop when the counter reaches zero */ |
| 952 | 991 | ){ |
| 953 | - Manifest *pMan; | |
| 954 | - int i, iParent; | |
| 955 | - Stmt q; | |
| 956 | - char *zBranch; | |
| 957 | - int iMark; | |
| 958 | - Blob sql; | |
| 992 | + Manifest *pMan; /* The check-in to be output */ | |
| 993 | + int i; /* Loop counter */ | |
| 994 | + int iParent; /* Which immediate ancestor is primary. -1 for none */ | |
| 995 | + Stmt q; /* An SQL query */ | |
| 996 | + char *zBranch; /* The branch of the check-in */ | |
| 997 | + int iMark; /* The mark for the check-in */ | |
| 998 | + Blob sql; /* String of SQL for part of the query */ | |
| 999 | + char *zCom; /* The check-in comment */ | |
| 959 | 1000 | |
| 960 | 1001 | pMan = manifest_get(rid, CFTYPE_MANIFEST, 0); |
| 961 | 1002 | if( pMan==0 ){ |
| 962 | 1003 | /* Must be a phantom. Return without doing anything, and in particular |
| 963 | 1004 | ** without creating a mark for this check-in. */ |
| @@ -1012,12 +1053,13 @@ | ||
| 1012 | 1053 | fprintf(xCmd, "mark :%d\n", iMark); |
| 1013 | 1054 | fprintf(xCmd, "committer %s <%[email protected]> %lld +0000\n", |
| 1014 | 1055 | pMan->zUser, pMan->zUser, |
| 1015 | 1056 | (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) |
| 1016 | 1057 | ); |
| 1017 | - fprintf(xCmd, "data %d\n", (int)strlen(pMan->zComment)); | |
| 1018 | - fprintf(xCmd, "%s\n", pMan->zComment); | |
| 1058 | + zCom = pMan->zComment; | |
| 1059 | + if( zCom==0 ) zCom = "(no comment)"; | |
| 1060 | + fprintf(xCmd, "data %d\n%s\n", (int)strlen(zCom), zCom); | |
| 1019 | 1061 | iParent = -1; /* Which ancestor is the primary parent */ |
| 1020 | 1062 | for(i=0; i<pMan->nParent; i++){ |
| 1021 | 1063 | int iOther = mirror_find_mark(pMan->azParent[i], 0); |
| 1022 | 1064 | if( iOther==0 ) continue; |
| 1023 | 1065 | if( iParent<0 ){ |
| @@ -1057,15 +1099,18 @@ | ||
| 1057 | 1099 | while( db_step(&q)==SQLITE_ROW ){ |
| 1058 | 1100 | const char *zFilename = db_column_text(&q,0); |
| 1059 | 1101 | const char *zMode = db_column_text(&q,1); |
| 1060 | 1102 | int iMark = db_column_int(&q,2); |
| 1061 | 1103 | const char *zGitMode = "100644"; |
| 1104 | + char *zFNQuoted = 0; | |
| 1062 | 1105 | if( zMode ){ |
| 1063 | 1106 | if( strchr(zMode,'x') ) zGitMode = "100755"; |
| 1064 | 1107 | if( strchr(zMode,'l') ) zGitMode = "120000"; |
| 1065 | 1108 | } |
| 1066 | - fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFilename); | |
| 1109 | + zFNQuoted = mirror_quote_filename_if_needed(zFilename); | |
| 1110 | + fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFNQuoted); | |
| 1111 | + fossil_free(zFNQuoted); | |
| 1067 | 1112 | } |
| 1068 | 1113 | db_finalize(&q); |
| 1069 | 1114 | |
| 1070 | 1115 | /* The check-in is finished, so decrement the counter */ |
| 1071 | 1116 | (*pnLimit)--; |
| 1072 | 1117 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -867,10 +867,49 @@ | |
| 867 | || (i>0 && zu[i-1]=='.')) ){ |
| 868 | zu[i] = '_'; |
| 869 | } |
| 870 | } |
| 871 | } |
| 872 | |
| 873 | /* |
| 874 | ** Transfer a tag over to the mirror. "rid" is the BLOB.RID value for |
| 875 | ** the record that describes the tag. |
| 876 | ** |
| @@ -948,16 +987,18 @@ | |
| 948 | FILE *xCmd, /* Write fast-import text on this pipe */ |
| 949 | int rid, /* BLOB.RID for the check-in to export */ |
| 950 | const char *zUuid, /* BLOB.UUID for the check-in to export */ |
| 951 | int *pnLimit /* Stop when the counter reaches zero */ |
| 952 | ){ |
| 953 | Manifest *pMan; |
| 954 | int i, iParent; |
| 955 | Stmt q; |
| 956 | char *zBranch; |
| 957 | int iMark; |
| 958 | Blob sql; |
| 959 | |
| 960 | pMan = manifest_get(rid, CFTYPE_MANIFEST, 0); |
| 961 | if( pMan==0 ){ |
| 962 | /* Must be a phantom. Return without doing anything, and in particular |
| 963 | ** without creating a mark for this check-in. */ |
| @@ -1012,12 +1053,13 @@ | |
| 1012 | fprintf(xCmd, "mark :%d\n", iMark); |
| 1013 | fprintf(xCmd, "committer %s <%[email protected]> %lld +0000\n", |
| 1014 | pMan->zUser, pMan->zUser, |
| 1015 | (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) |
| 1016 | ); |
| 1017 | fprintf(xCmd, "data %d\n", (int)strlen(pMan->zComment)); |
| 1018 | fprintf(xCmd, "%s\n", pMan->zComment); |
| 1019 | iParent = -1; /* Which ancestor is the primary parent */ |
| 1020 | for(i=0; i<pMan->nParent; i++){ |
| 1021 | int iOther = mirror_find_mark(pMan->azParent[i], 0); |
| 1022 | if( iOther==0 ) continue; |
| 1023 | if( iParent<0 ){ |
| @@ -1057,15 +1099,18 @@ | |
| 1057 | while( db_step(&q)==SQLITE_ROW ){ |
| 1058 | const char *zFilename = db_column_text(&q,0); |
| 1059 | const char *zMode = db_column_text(&q,1); |
| 1060 | int iMark = db_column_int(&q,2); |
| 1061 | const char *zGitMode = "100644"; |
| 1062 | if( zMode ){ |
| 1063 | if( strchr(zMode,'x') ) zGitMode = "100755"; |
| 1064 | if( strchr(zMode,'l') ) zGitMode = "120000"; |
| 1065 | } |
| 1066 | fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFilename); |
| 1067 | } |
| 1068 | db_finalize(&q); |
| 1069 | |
| 1070 | /* The check-in is finished, so decrement the counter */ |
| 1071 | (*pnLimit)--; |
| 1072 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -867,10 +867,49 @@ | |
| 867 | || (i>0 && zu[i-1]=='.')) ){ |
| 868 | zu[i] = '_'; |
| 869 | } |
| 870 | } |
| 871 | } |
| 872 | |
| 873 | /* |
| 874 | ** Quote a filename as a C-style string using \\ and \" if necessary. |
| 875 | ** If quoting is not necessary, just return a copy of the input string. |
| 876 | ** |
| 877 | ** The return value is a held in memory obtained from fossil_malloc() |
| 878 | ** and must be freed by the caller. |
| 879 | */ |
| 880 | static char *mirror_quote_filename_if_needed(const char *zIn){ |
| 881 | int i, j; |
| 882 | char c; |
| 883 | int nSpecial = 0; |
| 884 | char *zOut; |
| 885 | for(i=0; (c = zIn[i])!=0; i++){ |
| 886 | if( c=='\\' || c=='"' || c=='\n' ){ |
| 887 | nSpecial++; |
| 888 | } |
| 889 | } |
| 890 | if( nSpecial==0 ){ |
| 891 | return fossil_strdup(zIn); |
| 892 | } |
| 893 | zOut = fossil_malloc( i+nSpecial+3 ); |
| 894 | zOut[0] = '"'; |
| 895 | for(i=0, j=1; (c = zIn[i])!=0; i++){ |
| 896 | if( c=='\\' || c=='"' || c=='\n' ){ |
| 897 | zOut[j++] = '\\'; |
| 898 | if( c=='\n' ){ |
| 899 | zOut[j++] = 'n'; |
| 900 | }else{ |
| 901 | zOut[j++] = c; |
| 902 | } |
| 903 | }else{ |
| 904 | zOut[j++] = c; |
| 905 | } |
| 906 | } |
| 907 | zOut[j++] = '"'; |
| 908 | zOut[j] = 0; |
| 909 | return zOut; |
| 910 | } |
| 911 | |
| 912 | /* |
| 913 | ** Transfer a tag over to the mirror. "rid" is the BLOB.RID value for |
| 914 | ** the record that describes the tag. |
| 915 | ** |
| @@ -948,16 +987,18 @@ | |
| 987 | FILE *xCmd, /* Write fast-import text on this pipe */ |
| 988 | int rid, /* BLOB.RID for the check-in to export */ |
| 989 | const char *zUuid, /* BLOB.UUID for the check-in to export */ |
| 990 | int *pnLimit /* Stop when the counter reaches zero */ |
| 991 | ){ |
| 992 | Manifest *pMan; /* The check-in to be output */ |
| 993 | int i; /* Loop counter */ |
| 994 | int iParent; /* Which immediate ancestor is primary. -1 for none */ |
| 995 | Stmt q; /* An SQL query */ |
| 996 | char *zBranch; /* The branch of the check-in */ |
| 997 | int iMark; /* The mark for the check-in */ |
| 998 | Blob sql; /* String of SQL for part of the query */ |
| 999 | char *zCom; /* The check-in comment */ |
| 1000 | |
| 1001 | pMan = manifest_get(rid, CFTYPE_MANIFEST, 0); |
| 1002 | if( pMan==0 ){ |
| 1003 | /* Must be a phantom. Return without doing anything, and in particular |
| 1004 | ** without creating a mark for this check-in. */ |
| @@ -1012,12 +1053,13 @@ | |
| 1053 | fprintf(xCmd, "mark :%d\n", iMark); |
| 1054 | fprintf(xCmd, "committer %s <%[email protected]> %lld +0000\n", |
| 1055 | pMan->zUser, pMan->zUser, |
| 1056 | (sqlite3_int64)((pMan->rDate-2440587.5)*86400.0) |
| 1057 | ); |
| 1058 | zCom = pMan->zComment; |
| 1059 | if( zCom==0 ) zCom = "(no comment)"; |
| 1060 | fprintf(xCmd, "data %d\n%s\n", (int)strlen(zCom), zCom); |
| 1061 | iParent = -1; /* Which ancestor is the primary parent */ |
| 1062 | for(i=0; i<pMan->nParent; i++){ |
| 1063 | int iOther = mirror_find_mark(pMan->azParent[i], 0); |
| 1064 | if( iOther==0 ) continue; |
| 1065 | if( iParent<0 ){ |
| @@ -1057,15 +1099,18 @@ | |
| 1099 | while( db_step(&q)==SQLITE_ROW ){ |
| 1100 | const char *zFilename = db_column_text(&q,0); |
| 1101 | const char *zMode = db_column_text(&q,1); |
| 1102 | int iMark = db_column_int(&q,2); |
| 1103 | const char *zGitMode = "100644"; |
| 1104 | char *zFNQuoted = 0; |
| 1105 | if( zMode ){ |
| 1106 | if( strchr(zMode,'x') ) zGitMode = "100755"; |
| 1107 | if( strchr(zMode,'l') ) zGitMode = "120000"; |
| 1108 | } |
| 1109 | zFNQuoted = mirror_quote_filename_if_needed(zFilename); |
| 1110 | fprintf(xCmd,"M %s :%d %s\n", zGitMode, iMark, zFNQuoted); |
| 1111 | fossil_free(zFNQuoted); |
| 1112 | } |
| 1113 | db_finalize(&q); |
| 1114 | |
| 1115 | /* The check-in is finished, so decrement the counter */ |
| 1116 | (*pnLimit)--; |
| 1117 |