Fossil SCM

Various unrelated improvements in the single-file commit process. Moved leaf-is-closed check into its own function (affects the commit command).

stephan 2020-04-28 14:27 checkin-without-checkout
Commit 3a71400423dcfdc595e707779bde9d20fe337cb9583fc10be1d300f41f07790c
2 files changed +69 -33 +11
+69 -33
--- src/checkin.c
+++ src/checkin.c
@@ -2321,13 +2321,11 @@
23212321
** Do not allow a commit against a closed leaf unless the commit
23222322
** ends up on a different branch.
23232323
*/
23242324
if(
23252325
/* parent check-in has the "closed" tag... */
2326
- db_exists("SELECT 1 FROM tagxref"
2327
- " WHERE tagid=%d AND rid=%d AND tagtype>0",
2328
- TAG_CLOSED, vid)
2326
+ leaf_is_closed(vid)
23292327
/* ... and the new check-in has no --branch option or the --branch
23302328
** option does not actually change the branch */
23312329
&& (sCiInfo.zBranch==0
23322330
|| db_exists("SELECT 1 FROM tagxref"
23332331
" WHERE tagid=%d AND rid=%d AND tagtype>0"
@@ -2673,15 +2671,17 @@
26732671
if( count_nonbranch_children(vid)>1 ){
26742672
fossil_print("**** warning: a fork has occurred *****\n");
26752673
}
26762674
}
26772675
2678
-#if INTERFACE
26792676
/*
26802677
** State for the "web-checkin" infrastructure, which enables the
26812678
** ability to commit changes to a single file via an HTTP request.
2682
- */
2679
+**
2680
+** Memory for all non-const (char *) members is owned by the
2681
+** CheckinOneFileInfo instance.
2682
+*/
26832683
struct CheckinOneFileInfo {
26842684
Blob comment; /* Check-in comment text */
26852685
char *zMimetype; /* Mimetype of check-in command. May be NULL */
26862686
Manifest * pParent; /* parent checkin */
26872687
char *zParentUuid; /* UUID of pParent */
@@ -2688,21 +2688,22 @@
26882688
char *zUser; /* User name */
26892689
char *zDate; /* Optionally force this date string
26902690
(anything supported by
26912691
date_in_standard_format().
26922692
Maybe be NULL. */
2693
- char *zFilename; /* Name of single file to commit. */
2694
- Blob fileContent; /* Content of the modified file. */
2695
- Blob fileHash; /* Hash of this->fileContent */
2693
+ char *zFilename; /* Name of single file to commit. Must be
2694
+ relative to the top of the repo. */
2695
+ Blob fileContent; /* Content of file referred to by zFilename. */
2696
+ Blob fileHash; /* Hash of this->fileContent, using the
2697
+ repo's preferred hash method. */
26962698
};
2697
-#endif /* INTERFACE */
2698
-
2699
+typedef struct CheckinOneFileInfo CheckinOneFileInfo;
26992700
/*
27002701
** Initializes p to a known-valid default state.
27012702
*/
27022703
static void CheckinOneFileInfo_init( CheckinOneFileInfo * p ){
2703
- memset(p, 0, sizeof(struct CheckinOneFileInfo));
2704
+ memset(p, 0, sizeof(CheckinOneFileInfo));
27042705
p->comment = p->fileContent = p->fileHash = empty_blob;
27052706
}
27062707
27072708
/*
27082709
** Frees all memory owned by p, but does not free p.
@@ -2735,11 +2736,22 @@
27352736
*/
27362737
CKIN1_ALLOW_FORK = 1<<1,
27372738
/*
27382739
** Tells checkin_one_file() to dump its generated manifest to stdout.
27392740
*/
2740
-CKIN1_DUMP_MANIFEST = 1<<2
2741
+CKIN1_DUMP_MANIFEST = 1<<2,
2742
+
2743
+/*
2744
+** By default, content containing what appears to be a merge conflict
2745
+** marker is not permitted. This flag relaxes that requirement.
2746
+*/
2747
+CKIN1_ALLOW_MERGE_MARKER = 1<<3,
2748
+
2749
+/*
2750
+** NOT YET IMPLEMENTED.
2751
+*/
2752
+CKIN1_ALLOW_CLOSED_LEAF = 1<<4
27412753
};
27422754
27432755
/*
27442756
** Creates a manifest file, written to pOut, from the state in the
27452757
** fully-populated pCI argument. Returns true on success. On error,
@@ -2856,13 +2868,11 @@
28562868
28572869
if(pCI->zMimetype!=0 && pCI->zMimetype[0]!=0){
28582870
blob_appendf(pOut, "N %F\n", pCI->zMimetype);
28592871
}
28602872
2861
- blob_appendf(pOut, "P %z\n",
2862
- db_text(0,"SELECT uuid FROM blob WHERE rid=%d",
2863
- pCI->pParent->rid));
2873
+ blob_appendf(pOut, "P %s\n", pCI->zParentUuid);
28642874
blob_appendf(pOut, "U %F\n", pCI->zUser);
28652875
md5sum_blob(pOut, &zCard);
28662876
blob_appendf(pOut, "Z %b\n", &zCard);
28672877
blob_reset(&zCard);
28682878
return 1;
@@ -2879,10 +2889,13 @@
28792889
**
28802890
** This routine uses the state from the given fully-populated pCI
28812891
** argument to add pCI->fileContent to the database, and create and
28822892
** save a manifest for that change. Ownership of pCI and its contents
28832893
** are unchanged.
2894
+**
2895
+** If pCI->fileHash is empty, this routine populates it with the
2896
+** repository's preferred hash algorithm.
28842897
**
28852898
** On error, returns false (0) and, if pErr is not NULL, writes a
28862899
** diagnostic message there.
28872900
**
28882901
** Returns true on success. If pRid is not NULL, the RID of the
@@ -2890,12 +2903,12 @@
28902903
**
28912904
** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags
28922905
** enum. See that enum for the docs for each flag.
28932906
**
28942907
*/
2895
-int checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int ckin1Flags,
2896
- Blob * pErr ){
2908
+static int checkin_one_file( CheckinOneFileInfo * pCI, int *pRid,
2909
+ int ckin1Flags, Blob * pErr ){
28972910
Blob mf = empty_blob; /* output manifest */
28982911
int rid = 0, frid = 0; /* various RIDs */
28992912
const int isPrivate = content_is_private(pCI->pParent->rid);
29002913
ManifestFile * zFile; /* file from pCI->pParent */;
29012914
const char * zFilePrevUuid = 0; /* UUID of previous version of
@@ -2904,19 +2917,45 @@
29042917
db_begin_transaction();
29052918
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){
29062919
ci_err((pErr,"No such user: %s", pCI->zUser));
29072920
}
29082921
assert(pCI->pParent->rid>0);
2922
+ if(leaf_is_closed(pCI->pParent->rid)){
2923
+ ci_err((pErr,"Cannot commit to a closed leaf."));
2924
+ /* Remember that in order to override this we'd also need to
2925
+ ** cancel TAG_CLOSED on pCI->pParent. There would seem to be
2926
+ ** no reason we can't do that via the generated manifest,
2927
+ ** but the commit command does not offer that option, so
2928
+ ** we won't, either.
2929
+ */
2930
+ }
29092931
if(!(CKIN1_ALLOW_FORK & ckin1Flags)
29102932
&& !is_a_leaf(pCI->pParent->rid)){
29112933
ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.",
29122934
pCI->zParentUuid));
29132935
}
2936
+ if(!(CKIN1_ALLOW_MERGE_MARKER & ckin1Flags)
2937
+ && contains_merge_marker(&pCI->fileContent)){
2938
+ ci_err((pErr,"Content appears to contain a merge conflict marker."));
2939
+ }
2940
+ if(blob_size(&pCI->fileHash)==0){
2941
+ hname_hash(&pCI->fileContent, 0, &pCI->fileHash);
2942
+ assert(blob_size(&pCI->fileHash)>0);
2943
+ }
2944
+ /* Potential TODOs include:
2945
+ **
2946
+ ** - Commit allows an empty checkin only with a flag, but we
2947
+ ** currently disallow it entirely. Conform with commit?
2948
+ */
2949
+
29142950
/*
2915
- ** Confirm that pCI->zFilename can be found in pCI->pParent.
2916
- ** If not, fail. This is admittedly an artificial limitation,
2917
- ** not strictly necessary.
2951
+ ** Confirm that pCI->zFilename can be found in pCI->pParent. If
2952
+ ** not, fail. This is admittedly an artificial limitation, not
2953
+ ** strictly necessary. We do it to hopefully reduce the chance of an
2954
+ ** "oops" where file X/Y/z gets committed as X/Y/Z due to a typo or
2955
+ ** case-sensitivity mismatch between the user and repo, or some
2956
+ ** such.
29182957
*/
29192958
manifest_file_rewind(pCI->pParent);
29202959
zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0);
29212960
if(!zFile){
29222961
ci_err((pErr,"File [%s] not found in manifest [%S]. "
@@ -2942,26 +2981,22 @@
29422981
int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
29432982
zFilePrevUuid);
29442983
assert(prevFRid>0);
29452984
content_deltify(frid, &prevFRid, 1, 0);
29462985
}
2947
- /* Save and crosslink the manifest... */
2986
+ /* Save, deltify, and crosslink the manifest... */
29482987
rid = content_put_ex(&mf, 0, 0, 0, isPrivate);
2988
+ content_deltify(rid, &pCI->pParent->rid, 1, 0);
29492989
if(pRid!=0){
29502990
*pRid = rid;
29512991
}
29522992
if( ckin1Flags & CKIN1_DUMP_MANIFEST ){
29532993
fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf);
29542994
}
29552995
manifest_crosslink(rid, &mf, 0);
2956
- if(CKIN1_DRY_RUN & ckin1Flags){
2957
- fossil_print("Rolling back transaction.\n");
2958
- db_end_transaction(1);
2959
- }else{
2960
- db_end_transaction(0);
2961
- }
29622996
blob_reset(&mf);
2997
+ db_end_transaction((CKIN1_DRY_RUN & ckin1Flags) ? 1 : 0);
29632998
return 1;
29642999
ci_error:
29653000
assert(db_transaction_nesting_depth()>0);
29663001
db_end_transaction(1);
29673002
return 0;
@@ -2992,10 +3027,12 @@
29923027
** trunk (if used without a checkout).
29933028
** --wet-run Disables the default dry-run mode.
29943029
** --allow-fork Allows the commit to be made against a
29953030
** non-leaf parent. Note that no autosync
29963031
** is performed beforehand.
3032
+** --allow-merge-conflict Allows checkin of a file even if it appears
3033
+** to contain a fossil merge conflict marker.
29973034
** --user-override USER USER to use instead of the current default.
29983035
** --date-override DATETIME DATE to use instead of 'now'.
29993036
** --dump-manifest|-d Dumps the generated manifest to stdout.
30003037
**
30013038
** Example:
@@ -3031,20 +3068,22 @@
30313068
ckin1Flags |= CKIN1_ALLOW_FORK;
30323069
}
30333070
if(find_option("dump-manifest","d",0)!=0){
30343071
ckin1Flags |= CKIN1_DUMP_MANIFEST;
30353072
}
3073
+ if(find_option("allow-merge-conflict",0,0)!=0){
3074
+ ckin1Flags |= CKIN1_ALLOW_MERGE_MARKER;
3075
+ }
30363076
30373077
CheckinOneFileInfo_init(&cinf);
30383078
30393079
if(zComment && zCommentFile){
30403080
fossil_fatal("Only one of -m or -M, not both, may be used.");
30413081
}else{
3042
- if(zCommentFile){
3082
+ if(zCommentFile && *zCommentFile){
30433083
blob_read_from_file(&cinf.comment, zCommentFile, ExtFILE);
3044
- }else{
3045
- assert(zComment);
3084
+ }else if(zComment && *zComment){
30463085
blob_append(&cinf.comment, zComment, -1);
30473086
}
30483087
if(!blob_size(&cinf.comment)){
30493088
fossil_fatal("Non-empty checkin comment is required.");
30503089
}
@@ -3086,13 +3125,10 @@
30863125
cinf.pParent = manifest_get_by_name(cinf.zParentUuid, &parentVid);
30873126
assert(parentVid>0);
30883127
assert(cinf.pParent!=0);
30893128
blob_read_from_file(&cinf.fileContent, zFilename,
30903129
ExtFILE/*may want to reconsider*/);
3091
- sha3sum_init(256);
3092
- sha3sum_step_blob(&cinf.fileContent);
3093
- sha3sum_finish(&cinf.fileHash);
30943130
{
30953131
Blob errMsg = empty_blob;
30963132
const int rc = checkin_one_file(&cinf, &newRid, ckin1Flags, &errMsg);
30973133
CheckinOneFileInfo_cleanup(&cinf);
30983134
if(rc){
30993135
--- src/checkin.c
+++ src/checkin.c
@@ -2321,13 +2321,11 @@
2321 ** Do not allow a commit against a closed leaf unless the commit
2322 ** ends up on a different branch.
2323 */
2324 if(
2325 /* parent check-in has the "closed" tag... */
2326 db_exists("SELECT 1 FROM tagxref"
2327 " WHERE tagid=%d AND rid=%d AND tagtype>0",
2328 TAG_CLOSED, vid)
2329 /* ... and the new check-in has no --branch option or the --branch
2330 ** option does not actually change the branch */
2331 && (sCiInfo.zBranch==0
2332 || db_exists("SELECT 1 FROM tagxref"
2333 " WHERE tagid=%d AND rid=%d AND tagtype>0"
@@ -2673,15 +2671,17 @@
2673 if( count_nonbranch_children(vid)>1 ){
2674 fossil_print("**** warning: a fork has occurred *****\n");
2675 }
2676 }
2677
2678 #if INTERFACE
2679 /*
2680 ** State for the "web-checkin" infrastructure, which enables the
2681 ** ability to commit changes to a single file via an HTTP request.
2682 */
 
 
 
2683 struct CheckinOneFileInfo {
2684 Blob comment; /* Check-in comment text */
2685 char *zMimetype; /* Mimetype of check-in command. May be NULL */
2686 Manifest * pParent; /* parent checkin */
2687 char *zParentUuid; /* UUID of pParent */
@@ -2688,21 +2688,22 @@
2688 char *zUser; /* User name */
2689 char *zDate; /* Optionally force this date string
2690 (anything supported by
2691 date_in_standard_format().
2692 Maybe be NULL. */
2693 char *zFilename; /* Name of single file to commit. */
2694 Blob fileContent; /* Content of the modified file. */
2695 Blob fileHash; /* Hash of this->fileContent */
 
 
2696 };
2697 #endif /* INTERFACE */
2698
2699 /*
2700 ** Initializes p to a known-valid default state.
2701 */
2702 static void CheckinOneFileInfo_init( CheckinOneFileInfo * p ){
2703 memset(p, 0, sizeof(struct CheckinOneFileInfo));
2704 p->comment = p->fileContent = p->fileHash = empty_blob;
2705 }
2706
2707 /*
2708 ** Frees all memory owned by p, but does not free p.
@@ -2735,11 +2736,22 @@
2735 */
2736 CKIN1_ALLOW_FORK = 1<<1,
2737 /*
2738 ** Tells checkin_one_file() to dump its generated manifest to stdout.
2739 */
2740 CKIN1_DUMP_MANIFEST = 1<<2
 
 
 
 
 
 
 
 
 
 
 
2741 };
2742
2743 /*
2744 ** Creates a manifest file, written to pOut, from the state in the
2745 ** fully-populated pCI argument. Returns true on success. On error,
@@ -2856,13 +2868,11 @@
2856
2857 if(pCI->zMimetype!=0 && pCI->zMimetype[0]!=0){
2858 blob_appendf(pOut, "N %F\n", pCI->zMimetype);
2859 }
2860
2861 blob_appendf(pOut, "P %z\n",
2862 db_text(0,"SELECT uuid FROM blob WHERE rid=%d",
2863 pCI->pParent->rid));
2864 blob_appendf(pOut, "U %F\n", pCI->zUser);
2865 md5sum_blob(pOut, &zCard);
2866 blob_appendf(pOut, "Z %b\n", &zCard);
2867 blob_reset(&zCard);
2868 return 1;
@@ -2879,10 +2889,13 @@
2879 **
2880 ** This routine uses the state from the given fully-populated pCI
2881 ** argument to add pCI->fileContent to the database, and create and
2882 ** save a manifest for that change. Ownership of pCI and its contents
2883 ** are unchanged.
 
 
 
2884 **
2885 ** On error, returns false (0) and, if pErr is not NULL, writes a
2886 ** diagnostic message there.
2887 **
2888 ** Returns true on success. If pRid is not NULL, the RID of the
@@ -2890,12 +2903,12 @@
2890 **
2891 ** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags
2892 ** enum. See that enum for the docs for each flag.
2893 **
2894 */
2895 int checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int ckin1Flags,
2896 Blob * pErr ){
2897 Blob mf = empty_blob; /* output manifest */
2898 int rid = 0, frid = 0; /* various RIDs */
2899 const int isPrivate = content_is_private(pCI->pParent->rid);
2900 ManifestFile * zFile; /* file from pCI->pParent */;
2901 const char * zFilePrevUuid = 0; /* UUID of previous version of
@@ -2904,19 +2917,45 @@
2904 db_begin_transaction();
2905 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){
2906 ci_err((pErr,"No such user: %s", pCI->zUser));
2907 }
2908 assert(pCI->pParent->rid>0);
 
 
 
 
 
 
 
 
 
2909 if(!(CKIN1_ALLOW_FORK & ckin1Flags)
2910 && !is_a_leaf(pCI->pParent->rid)){
2911 ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.",
2912 pCI->zParentUuid));
2913 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2914 /*
2915 ** Confirm that pCI->zFilename can be found in pCI->pParent.
2916 ** If not, fail. This is admittedly an artificial limitation,
2917 ** not strictly necessary.
 
 
 
2918 */
2919 manifest_file_rewind(pCI->pParent);
2920 zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0);
2921 if(!zFile){
2922 ci_err((pErr,"File [%s] not found in manifest [%S]. "
@@ -2942,26 +2981,22 @@
2942 int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
2943 zFilePrevUuid);
2944 assert(prevFRid>0);
2945 content_deltify(frid, &prevFRid, 1, 0);
2946 }
2947 /* Save and crosslink the manifest... */
2948 rid = content_put_ex(&mf, 0, 0, 0, isPrivate);
 
2949 if(pRid!=0){
2950 *pRid = rid;
2951 }
2952 if( ckin1Flags & CKIN1_DUMP_MANIFEST ){
2953 fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf);
2954 }
2955 manifest_crosslink(rid, &mf, 0);
2956 if(CKIN1_DRY_RUN & ckin1Flags){
2957 fossil_print("Rolling back transaction.\n");
2958 db_end_transaction(1);
2959 }else{
2960 db_end_transaction(0);
2961 }
2962 blob_reset(&mf);
 
2963 return 1;
2964 ci_error:
2965 assert(db_transaction_nesting_depth()>0);
2966 db_end_transaction(1);
2967 return 0;
@@ -2992,10 +3027,12 @@
2992 ** trunk (if used without a checkout).
2993 ** --wet-run Disables the default dry-run mode.
2994 ** --allow-fork Allows the commit to be made against a
2995 ** non-leaf parent. Note that no autosync
2996 ** is performed beforehand.
 
 
2997 ** --user-override USER USER to use instead of the current default.
2998 ** --date-override DATETIME DATE to use instead of 'now'.
2999 ** --dump-manifest|-d Dumps the generated manifest to stdout.
3000 **
3001 ** Example:
@@ -3031,20 +3068,22 @@
3031 ckin1Flags |= CKIN1_ALLOW_FORK;
3032 }
3033 if(find_option("dump-manifest","d",0)!=0){
3034 ckin1Flags |= CKIN1_DUMP_MANIFEST;
3035 }
 
 
 
3036
3037 CheckinOneFileInfo_init(&cinf);
3038
3039 if(zComment && zCommentFile){
3040 fossil_fatal("Only one of -m or -M, not both, may be used.");
3041 }else{
3042 if(zCommentFile){
3043 blob_read_from_file(&cinf.comment, zCommentFile, ExtFILE);
3044 }else{
3045 assert(zComment);
3046 blob_append(&cinf.comment, zComment, -1);
3047 }
3048 if(!blob_size(&cinf.comment)){
3049 fossil_fatal("Non-empty checkin comment is required.");
3050 }
@@ -3086,13 +3125,10 @@
3086 cinf.pParent = manifest_get_by_name(cinf.zParentUuid, &parentVid);
3087 assert(parentVid>0);
3088 assert(cinf.pParent!=0);
3089 blob_read_from_file(&cinf.fileContent, zFilename,
3090 ExtFILE/*may want to reconsider*/);
3091 sha3sum_init(256);
3092 sha3sum_step_blob(&cinf.fileContent);
3093 sha3sum_finish(&cinf.fileHash);
3094 {
3095 Blob errMsg = empty_blob;
3096 const int rc = checkin_one_file(&cinf, &newRid, ckin1Flags, &errMsg);
3097 CheckinOneFileInfo_cleanup(&cinf);
3098 if(rc){
3099
--- src/checkin.c
+++ src/checkin.c
@@ -2321,13 +2321,11 @@
2321 ** Do not allow a commit against a closed leaf unless the commit
2322 ** ends up on a different branch.
2323 */
2324 if(
2325 /* parent check-in has the "closed" tag... */
2326 leaf_is_closed(vid)
 
 
2327 /* ... and the new check-in has no --branch option or the --branch
2328 ** option does not actually change the branch */
2329 && (sCiInfo.zBranch==0
2330 || db_exists("SELECT 1 FROM tagxref"
2331 " WHERE tagid=%d AND rid=%d AND tagtype>0"
@@ -2673,15 +2671,17 @@
2671 if( count_nonbranch_children(vid)>1 ){
2672 fossil_print("**** warning: a fork has occurred *****\n");
2673 }
2674 }
2675
 
2676 /*
2677 ** State for the "web-checkin" infrastructure, which enables the
2678 ** ability to commit changes to a single file via an HTTP request.
2679 **
2680 ** Memory for all non-const (char *) members is owned by the
2681 ** CheckinOneFileInfo instance.
2682 */
2683 struct CheckinOneFileInfo {
2684 Blob comment; /* Check-in comment text */
2685 char *zMimetype; /* Mimetype of check-in command. May be NULL */
2686 Manifest * pParent; /* parent checkin */
2687 char *zParentUuid; /* UUID of pParent */
@@ -2688,21 +2688,22 @@
2688 char *zUser; /* User name */
2689 char *zDate; /* Optionally force this date string
2690 (anything supported by
2691 date_in_standard_format().
2692 Maybe be NULL. */
2693 char *zFilename; /* Name of single file to commit. Must be
2694 relative to the top of the repo. */
2695 Blob fileContent; /* Content of file referred to by zFilename. */
2696 Blob fileHash; /* Hash of this->fileContent, using the
2697 repo's preferred hash method. */
2698 };
2699 typedef struct CheckinOneFileInfo CheckinOneFileInfo;
 
2700 /*
2701 ** Initializes p to a known-valid default state.
2702 */
2703 static void CheckinOneFileInfo_init( CheckinOneFileInfo * p ){
2704 memset(p, 0, sizeof(CheckinOneFileInfo));
2705 p->comment = p->fileContent = p->fileHash = empty_blob;
2706 }
2707
2708 /*
2709 ** Frees all memory owned by p, but does not free p.
@@ -2735,11 +2736,22 @@
2736 */
2737 CKIN1_ALLOW_FORK = 1<<1,
2738 /*
2739 ** Tells checkin_one_file() to dump its generated manifest to stdout.
2740 */
2741 CKIN1_DUMP_MANIFEST = 1<<2,
2742
2743 /*
2744 ** By default, content containing what appears to be a merge conflict
2745 ** marker is not permitted. This flag relaxes that requirement.
2746 */
2747 CKIN1_ALLOW_MERGE_MARKER = 1<<3,
2748
2749 /*
2750 ** NOT YET IMPLEMENTED.
2751 */
2752 CKIN1_ALLOW_CLOSED_LEAF = 1<<4
2753 };
2754
2755 /*
2756 ** Creates a manifest file, written to pOut, from the state in the
2757 ** fully-populated pCI argument. Returns true on success. On error,
@@ -2856,13 +2868,11 @@
2868
2869 if(pCI->zMimetype!=0 && pCI->zMimetype[0]!=0){
2870 blob_appendf(pOut, "N %F\n", pCI->zMimetype);
2871 }
2872
2873 blob_appendf(pOut, "P %s\n", pCI->zParentUuid);
 
 
2874 blob_appendf(pOut, "U %F\n", pCI->zUser);
2875 md5sum_blob(pOut, &zCard);
2876 blob_appendf(pOut, "Z %b\n", &zCard);
2877 blob_reset(&zCard);
2878 return 1;
@@ -2879,10 +2889,13 @@
2889 **
2890 ** This routine uses the state from the given fully-populated pCI
2891 ** argument to add pCI->fileContent to the database, and create and
2892 ** save a manifest for that change. Ownership of pCI and its contents
2893 ** are unchanged.
2894 **
2895 ** If pCI->fileHash is empty, this routine populates it with the
2896 ** repository's preferred hash algorithm.
2897 **
2898 ** On error, returns false (0) and, if pErr is not NULL, writes a
2899 ** diagnostic message there.
2900 **
2901 ** Returns true on success. If pRid is not NULL, the RID of the
@@ -2890,12 +2903,12 @@
2903 **
2904 ** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags
2905 ** enum. See that enum for the docs for each flag.
2906 **
2907 */
2908 static int checkin_one_file( CheckinOneFileInfo * pCI, int *pRid,
2909 int ckin1Flags, Blob * pErr ){
2910 Blob mf = empty_blob; /* output manifest */
2911 int rid = 0, frid = 0; /* various RIDs */
2912 const int isPrivate = content_is_private(pCI->pParent->rid);
2913 ManifestFile * zFile; /* file from pCI->pParent */;
2914 const char * zFilePrevUuid = 0; /* UUID of previous version of
@@ -2904,19 +2917,45 @@
2917 db_begin_transaction();
2918 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){
2919 ci_err((pErr,"No such user: %s", pCI->zUser));
2920 }
2921 assert(pCI->pParent->rid>0);
2922 if(leaf_is_closed(pCI->pParent->rid)){
2923 ci_err((pErr,"Cannot commit to a closed leaf."));
2924 /* Remember that in order to override this we'd also need to
2925 ** cancel TAG_CLOSED on pCI->pParent. There would seem to be
2926 ** no reason we can't do that via the generated manifest,
2927 ** but the commit command does not offer that option, so
2928 ** we won't, either.
2929 */
2930 }
2931 if(!(CKIN1_ALLOW_FORK & ckin1Flags)
2932 && !is_a_leaf(pCI->pParent->rid)){
2933 ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.",
2934 pCI->zParentUuid));
2935 }
2936 if(!(CKIN1_ALLOW_MERGE_MARKER & ckin1Flags)
2937 && contains_merge_marker(&pCI->fileContent)){
2938 ci_err((pErr,"Content appears to contain a merge conflict marker."));
2939 }
2940 if(blob_size(&pCI->fileHash)==0){
2941 hname_hash(&pCI->fileContent, 0, &pCI->fileHash);
2942 assert(blob_size(&pCI->fileHash)>0);
2943 }
2944 /* Potential TODOs include:
2945 **
2946 ** - Commit allows an empty checkin only with a flag, but we
2947 ** currently disallow it entirely. Conform with commit?
2948 */
2949
2950 /*
2951 ** Confirm that pCI->zFilename can be found in pCI->pParent. If
2952 ** not, fail. This is admittedly an artificial limitation, not
2953 ** strictly necessary. We do it to hopefully reduce the chance of an
2954 ** "oops" where file X/Y/z gets committed as X/Y/Z due to a typo or
2955 ** case-sensitivity mismatch between the user and repo, or some
2956 ** such.
2957 */
2958 manifest_file_rewind(pCI->pParent);
2959 zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0);
2960 if(!zFile){
2961 ci_err((pErr,"File [%s] not found in manifest [%S]. "
@@ -2942,26 +2981,22 @@
2981 int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
2982 zFilePrevUuid);
2983 assert(prevFRid>0);
2984 content_deltify(frid, &prevFRid, 1, 0);
2985 }
2986 /* Save, deltify, and crosslink the manifest... */
2987 rid = content_put_ex(&mf, 0, 0, 0, isPrivate);
2988 content_deltify(rid, &pCI->pParent->rid, 1, 0);
2989 if(pRid!=0){
2990 *pRid = rid;
2991 }
2992 if( ckin1Flags & CKIN1_DUMP_MANIFEST ){
2993 fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf);
2994 }
2995 manifest_crosslink(rid, &mf, 0);
 
 
 
 
 
 
2996 blob_reset(&mf);
2997 db_end_transaction((CKIN1_DRY_RUN & ckin1Flags) ? 1 : 0);
2998 return 1;
2999 ci_error:
3000 assert(db_transaction_nesting_depth()>0);
3001 db_end_transaction(1);
3002 return 0;
@@ -2992,10 +3027,12 @@
3027 ** trunk (if used without a checkout).
3028 ** --wet-run Disables the default dry-run mode.
3029 ** --allow-fork Allows the commit to be made against a
3030 ** non-leaf parent. Note that no autosync
3031 ** is performed beforehand.
3032 ** --allow-merge-conflict Allows checkin of a file even if it appears
3033 ** to contain a fossil merge conflict marker.
3034 ** --user-override USER USER to use instead of the current default.
3035 ** --date-override DATETIME DATE to use instead of 'now'.
3036 ** --dump-manifest|-d Dumps the generated manifest to stdout.
3037 **
3038 ** Example:
@@ -3031,20 +3068,22 @@
3068 ckin1Flags |= CKIN1_ALLOW_FORK;
3069 }
3070 if(find_option("dump-manifest","d",0)!=0){
3071 ckin1Flags |= CKIN1_DUMP_MANIFEST;
3072 }
3073 if(find_option("allow-merge-conflict",0,0)!=0){
3074 ckin1Flags |= CKIN1_ALLOW_MERGE_MARKER;
3075 }
3076
3077 CheckinOneFileInfo_init(&cinf);
3078
3079 if(zComment && zCommentFile){
3080 fossil_fatal("Only one of -m or -M, not both, may be used.");
3081 }else{
3082 if(zCommentFile && *zCommentFile){
3083 blob_read_from_file(&cinf.comment, zCommentFile, ExtFILE);
3084 }else if(zComment && *zComment){
 
3085 blob_append(&cinf.comment, zComment, -1);
3086 }
3087 if(!blob_size(&cinf.comment)){
3088 fossil_fatal("Non-empty checkin comment is required.");
3089 }
@@ -3086,13 +3125,10 @@
3125 cinf.pParent = manifest_get_by_name(cinf.zParentUuid, &parentVid);
3126 assert(parentVid>0);
3127 assert(cinf.pParent!=0);
3128 blob_read_from_file(&cinf.fileContent, zFilename,
3129 ExtFILE/*may want to reconsider*/);
 
 
 
3130 {
3131 Blob errMsg = empty_blob;
3132 const int rc = checkin_one_file(&cinf, &newRid, ckin1Flags, &errMsg);
3133 CheckinOneFileInfo_cleanup(&cinf);
3134 if(rc){
3135
+11
--- src/leaf.c
+++ src/leaf.c
@@ -152,10 +152,21 @@
152152
" AND tx.tagid=%d"
153153
" AND tx.tagtype>0)",
154154
zVar, TAG_CLOSED
155155
);
156156
}
157
+
158
+/*
159
+** Returns true if vid refers to a closed leaf, else false. vid is
160
+** assumed to refer to a manifest, but this function does not verify
161
+** that.
162
+*/
163
+int leaf_is_closed(int vid){
164
+ return db_exists("SELECT 1 FROM tagxref"
165
+ " WHERE tagid=%d AND rid=%d AND tagtype>0",
166
+ TAG_CLOSED, vid);
167
+}
157168
158169
/*
159170
** Schedule a leaf check for "rid" and its parents.
160171
*/
161172
void leaf_eventually_check(int rid){
162173
--- src/leaf.c
+++ src/leaf.c
@@ -152,10 +152,21 @@
152 " AND tx.tagid=%d"
153 " AND tx.tagtype>0)",
154 zVar, TAG_CLOSED
155 );
156 }
 
 
 
 
 
 
 
 
 
 
 
157
158 /*
159 ** Schedule a leaf check for "rid" and its parents.
160 */
161 void leaf_eventually_check(int rid){
162
--- src/leaf.c
+++ src/leaf.c
@@ -152,10 +152,21 @@
152 " AND tx.tagid=%d"
153 " AND tx.tagtype>0)",
154 zVar, TAG_CLOSED
155 );
156 }
157
158 /*
159 ** Returns true if vid refers to a closed leaf, else false. vid is
160 ** assumed to refer to a manifest, but this function does not verify
161 ** that.
162 */
163 int leaf_is_closed(int vid){
164 return db_exists("SELECT 1 FROM tagxref"
165 " WHERE tagid=%d AND rid=%d AND tagtype>0",
166 TAG_CLOSED, vid);
167 }
168
169 /*
170 ** Schedule a leaf check for "rid" and its parents.
171 */
172 void leaf_eventually_check(int rid){
173

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button