Fossil SCM

Improved error message propagation and added several checkin flags.

stephan 2020-04-28 11:45 checkin-without-checkout
Commit 1d0cc12583de3976ab37416e094fd84326cb4011a611e1cd8e426e325597ebc4
1 file changed +153 -76
+153 -76
--- src/checkin.c
+++ src/checkin.c
@@ -2679,26 +2679,36 @@
26792679
/*
26802680
** State for the "web-checkin" infrastructure, which enables the
26812681
** ability to commit changes to a single file via an HTTP request.
26822682
*/
26832683
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
- const char *zUser; /* User name */
2689
- char *zFilename; /* Name of single file to commit. */
2690
- Blob fileContent; /* Content of the modified file. */
2691
- Blob fileHash; /* Hash of this->fileContent */
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
+ 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 */
26922696
};
26932697
#endif /* INTERFACE */
26942698
2699
+/*
2700
+** Initializes p to a known-valid default state.
2701
+*/
26952702
static void CheckinOneFileInfo_init( CheckinOneFileInfo * p ){
26962703
memset(p, 0, sizeof(struct CheckinOneFileInfo));
26972704
p->comment = p->fileContent = p->fileHash = empty_blob;
26982705
}
26992706
2707
+/*
2708
+** Frees all memory owned by p, but does not free p.
2709
+ */
27002710
static void CheckinOneFileInfo_cleanup( CheckinOneFileInfo * p ){
27012711
blob_reset(&p->comment);
27022712
blob_reset(&p->fileContent);
27032713
blob_reset(&p->fileHash);
27042714
if(p->pParent){
@@ -2705,12 +2715,32 @@
27052715
manifest_destroy(p->pParent);
27062716
}
27072717
fossil_free(p->zFilename);
27082718
fossil_free(p->zMimetype);
27092719
fossil_free(p->zParentUuid);
2720
+ fossil_free(p->zUser);
2721
+ fossil_free(p->zDate);
27102722
CheckinOneFileInfo_init(p);
27112723
}
2724
+
2725
+/*
2726
+** Flags for checkin_one_file()
2727
+*/
2728
+enum fossil_ckin1_flags {
2729
+/*
2730
+** Tells checkin_one_file() to use dry-run mode.
2731
+*/
2732
+CKIN1_DRY_RUN = 1,
2733
+/*
2734
+** Tells checkin_one_file() to allow forking from a non-leaf commit.
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
+};
27122742
27132743
/*
27142744
** Creates a manifest file, written to pOut, from the state in the
27152745
** fully-populated pCI argument. Returns true on success. On error,
27162746
** returns 0 and, if pErr is not NULL, writes an error message there.
@@ -2722,11 +2752,10 @@
27222752
int cmp = -99; /* filename comparison result */
27232753
int fperm = 0; /* file permissions */
27242754
const char *zPerm = 0; /* permissions for new F-card */
27252755
const char *zFilename = 0; /* filename to use for F-card */
27262756
const char *zUuid = 0; /* UUID for F-card */
2727
- const char *zErrMsg = 0; /* For error reporting. */
27282757
int (*fncmp)(char const *, char const *) = /* filename comparator */
27292758
filenames_are_case_sensitive()
27302759
? fossil_strcmp
27312760
: fossil_stricmp;
27322761
@@ -2733,11 +2762,11 @@
27332762
assert(blob_str(&pCI->fileHash));
27342763
assert(pCI->pParent);
27352764
assert(pCI->zFilename);
27362765
assert(pCI->zUser);
27372766
2738
-#define mf_err(MSG) zErrMsg = MSG; goto manifest_error
2767
+#define mf_err(EXPR) if(pErr) blob_appendf EXPR; return 0
27392768
/* Potential TODOs include...
27402769
** - Create a delta manifest, if possible, rather than a baseline.
27412770
** - Enable adding of new files? It's implemented by disabled until
27422771
** we at least ensure that pCI->zFilename is a path-relative
27432772
** filename.
@@ -2753,11 +2782,28 @@
27532782
if(blob_size(&pCI->comment)!=0){
27542783
blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment));
27552784
}else{
27562785
blob_append(pOut, "C (no\\scomment)\n", 16);
27572786
}
2758
- blob_appendf(pOut, "D %z\n", date_in_standard_format("now"));
2787
+ {
2788
+ /*
2789
+ ** We don't use date_in_standard_format() because that has
2790
+ ** side-effects we don't want to trigger here.
2791
+ */
2792
+ char * zDVal = db_text(
2793
+ 0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%f',%Q)",
2794
+ pCI->zDate
2795
+ ? pCI->zDate
2796
+ : "now");
2797
+ if(zDVal[0]==0){
2798
+ fossil_free(zDVal);
2799
+ mf_err((pErr,
2800
+ "Invalid date format (%s): use \"YYYY-MM-DD HH:MM:SS.SSS\"",
2801
+ pCI->zDate));
2802
+ }
2803
+ blob_appendf(pOut, "D %z\n", zDVal);
2804
+ }
27592805
27602806
manifest_file_rewind(pCI->pParent);
27612807
while((zFile = manifest_file_next(pCI->pParent, 0))){
27622808
cmp = fncmp(zFile->zName, pCI->zFilename);
27632809
if(cmp<0){
@@ -2784,11 +2830,11 @@
27842830
--pCI->pParent->iFile
27852831
/* so that the next step picks up that entry again */;
27862832
}
27872833
}
27882834
if(PERM_LNK==fperm){
2789
- mf_err("Cannot commit symlinks with this approach.");
2835
+ mf_err((pErr,"Cannot commit symlinks with this approach."));
27902836
}else if(PERM_EXE==fperm){
27912837
zPerm = " x";
27922838
}else{
27932839
zPerm = "";
27942840
}
@@ -2798,11 +2844,11 @@
27982844
blob_appendf(pOut, "F %F %s%s\n", zFilename, zUuid, zPerm);
27992845
while((zFile = manifest_file_next(pCI->pParent, 0))){
28002846
cmp = fncmp(zFile->zName, pCI->zFilename);
28012847
assert(cmp>0);
28022848
if(cmp<=0){
2803
- mf_err("Internal error: mis-ordering of F-cards detected.");
2849
+ mf_err((pErr,"Internal error: mis-ordering of F-cards detected."));
28042850
}
28052851
blob_appendf(pOut, "F %F %s%s%s\n",
28062852
zFile->zName, zFile->zUuid,
28072853
(zFile->zPerm && *zFile->zPerm) ? " " : "",
28082854
(zFile->zPerm && *zFile->zPerm) ? zFile->zPerm : "");
@@ -2818,22 +2864,13 @@
28182864
blob_appendf(pOut, "U %F\n", pCI->zUser);
28192865
md5sum_blob(pOut, &zCard);
28202866
blob_appendf(pOut, "Z %b\n", &zCard);
28212867
blob_reset(&zCard);
28222868
return 1;
2823
-manifest_error:
2824
- assert( zErrMsg );
2825
- if(pErr) blob_append(pErr,zErrMsg,-1);
2826
- return 0;
28272869
#undef mf_err
28282870
}
28292871
2830
-enum fossil_ckin1_flags {
2831
-CKIN1_DRY_RUN = 1,
2832
-CKIN1_ALLOW_FORK = 1<<1
2833
-};
2834
-
28352872
/*
28362873
** EXPERIMENTAL! Subject to change or removal at any time.
28372874
**
28382875
** A so-called "single-file checkin" is a slimmed-down form of the
28392876
** checkin command which accepts only a single file and is intended to
@@ -2843,63 +2880,61 @@
28432880
** This routine uses the state from the given fully-populated pCI
28442881
** argument to add pCI->fileContent to the database, and create and
28452882
** save a manifest for that change. Ownership of pCI and its contents
28462883
** are unchanged.
28472884
**
2848
-** Fails fatally on error. If pRid is not NULL, the RID of the
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
28492889
** resulting manifest is written to *pRid.
28502890
**
2851
-** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags enum:
2852
-**
2853
-** CKIN1_DRY_RUN: rolls back the transaction, else it commits as
2854
-** usual.
2855
-**
2856
-** CKIN1_ALLOW_FORK: if false, checkin will fail if pCI->pParent is not
2857
-** currently a leaf.
2891
+** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags
2892
+** enum. See that enum for the docs for each flag.
28582893
**
28592894
*/
2860
-void checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int ckin1Flags ){
2861
- Blob mf = empty_blob;
2862
- Blob err = empty_blob;
2863
- int rid = 0, frid = 0, parentRid;
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 */
28642899
const int isPrivate = content_is_private(pCI->pParent->rid);
2865
- ManifestFile * zFile;
2866
- const char * zFilePrevUuid = 0; /* UUID of previous version of
2867
- the file */
2868
-
2900
+ ManifestFile * zFile; /* file from pCI->pParent */;
2901
+ const char * zFilePrevUuid = 0; /* UUID of previous version of
2902
+ the file */
2903
+#define ci_err(EXPR) if(pErr!=0){blob_appendf EXPR;} goto ci_error
28692904
db_begin_transaction();
28702905
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){
2871
- fossil_fatal("no such user: %s", pCI->zUser);
2906
+ ci_err((pErr,"No such user: %s", pCI->zUser));
28722907
}
2873
- parentRid = name_to_typed_rid(pCI->zParentUuid, "ci");
2874
- assert(parentRid>0);
2908
+ assert(pCI->pParent->rid>0);
28752909
if(!(CKIN1_ALLOW_FORK & ckin1Flags)
2876
- && !is_a_leaf(parentRid)){
2877
- fossil_fatal("Parent [%S] is not a leaf and forking is disabled.");
2910
+ && !is_a_leaf(pCI->pParent->rid)){
2911
+ ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.",
2912
+ pCI->zParentUuid));
28782913
}
28792914
/*
28802915
** Confirm that pCI->zFilename can be found in pCI->pParent.
28812916
** If not, fail. This is admittedly an artificial limitation,
28822917
** not strictly necessary.
28832918
*/
28842919
manifest_file_rewind(pCI->pParent);
28852920
zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0);
28862921
if(!zFile){
2887
- fossil_fatal("File [%s] not found in manifest [%S]. "
2888
- "Adding new files is currently not allowed.",
2889
- pCI->zFilename, pCI->zParentUuid);
2922
+ ci_err((pErr,"File [%s] not found in manifest [%S]. "
2923
+ "Adding new files is currently not allowed.",
2924
+ pCI->zFilename, pCI->zParentUuid));
28902925
}else if(zFile->zPerm && strstr(zFile->zPerm, "l")){
2891
- fossil_fatal("Cannot save a symlink this way.");
2926
+ ci_err((pErr,"Cannot save a symlink this way."));
28922927
}else{
28932928
if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){
2894
- fossil_fatal("File is unchanged. Not saving.");
2929
+ ci_err((pErr,"File is unchanged. Not saving."));
28952930
}
28962931
zFilePrevUuid = zFile->zUuid;
28972932
}
28982933
/* Create the manifest... */
2899
- if(create_manifest_one_file(&mf, pCI, &err)==0){
2900
- fossil_fatal("create_manifest_one_file() failed: %B", &err);
2934
+ if(create_manifest_one_file(&mf, pCI, pErr)==0){
2935
+ return 0;
29012936
}
29022937
/* Add the file content to the db... */
29032938
frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash),
29042939
0, 0, isPrivate);
29052940
if(zFilePrevUuid!=0){
@@ -2912,22 +2947,27 @@
29122947
/* Save and crosslink the manifest... */
29132948
rid = content_put_ex(&mf, 0, 0, 0, isPrivate);
29142949
if(pRid!=0){
29152950
*pRid = rid;
29162951
}
2917
-#if 1
2918
- /* Only for development/debugging... */
2919
- fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf);
2920
-#endif
2952
+ if( ckin1Flags & CKIN1_DUMP_MANIFEST ){
2953
+ fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf);
2954
+ }
29212955
manifest_crosslink(rid, &mf, 0);
29222956
if(CKIN1_DRY_RUN & ckin1Flags){
29232957
fossil_print("Rolling back transaction.\n");
29242958
db_end_transaction(1);
29252959
}else{
29262960
db_end_transaction(0);
29272961
}
29282962
blob_reset(&mf);
2963
+ return 1;
2964
+ci_error:
2965
+ assert(db_transaction_nesting_depth()>0);
2966
+ db_end_transaction(1);
2967
+ return 0;
2968
+#undef ci_err
29292969
}
29302970
29312971
/*
29322972
** COMMAND: test-ci-one
29332973
**
@@ -2939,50 +2979,79 @@
29392979
** where FILENAME is a repo-relative name as it would appear in the
29402980
** vfile table.
29412981
**
29422982
** Options:
29432983
**
2944
-** --as FILENAME The repository-side name of the input file,
2945
-** relative to the top of the repostory.
2946
-** Default is the same as the input file name.
2947
-** --comment|-m COMMENT Optional checkin comment.
2948
-** --revision|-r VERSION Commit from this version. Default is
2949
-** the checkout version (if available) or
2950
-** trunk (if used without a checkout).
2951
-** --wet-run Disables the default dry-run mode.
2952
-** --allow-fork Allows the commit to be made against a
2953
-** non-leaf parent. Note that no autosync
2954
-** is performed beforehand.
2984
+** --repository|-R REPO The repository file to commit to.
2985
+** --as FILENAME The repository-side name of the input file,
2986
+** relative to the top of the repository.
2987
+** Default is the same as the input file name.
2988
+** --comment|-m COMMENT Required checkin comment.
2989
+** --comment-file|-M FILE Reads checkin comment from the given file.
2990
+** --revision|-r VERSION Commit from this version. Default is
2991
+** the checkout version (if available) or
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.
29553000
**
29563001
** Example:
29573002
**
29583003
** %fossil test-ci-one -R REPO -m ... -r foo --as src/myfile.c myfile.c
29593004
**
29603005
*/
29613006
void test_ci_one_cmd(){
2962
- CheckinOneFileInfo cinf; /* checkin state */
3007
+ CheckinOneFileInfo cinf; /* checkin state */
29633008
int parentVid = 0, newRid = 0; /* RID of parent version and new
29643009
version */
29653010
const char * zFilename; /* argv[2] */
29663011
const char * zComment; /* -m comment */
3012
+ const char * zCommentFile; /* -M FILE */
29673013
const char * zAsFilename; /* --as filename */
29683014
const char * zRevision; /* --revision|-r [=trunk|checkout] */
3015
+ const char * zUser; /* --user-override */
3016
+ const char * zDate; /* --date-override */
29693017
int ckin1Flags = 0; /* flags for checkin_one_file(). */
29703018
if(g.argc<3){
29713019
usage("INFILE");
29723020
}
29733021
zComment = find_option("comment","m",1);
3022
+ zCommentFile = find_option("comment-file","M",1);
29743023
zAsFilename = find_option("as",0,1);
29753024
zRevision = find_option("revision","r",1);
2976
-
3025
+ zUser = find_option("user-override",0,1);
3026
+ zDate = find_option("date-override",0,1);
29773027
if(find_option("wet-run",0,0)==0){
29783028
ckin1Flags |= CKIN1_DRY_RUN;
29793029
}
2980
- if(find_option("allow-fork",0,0)==0){
3030
+ if(find_option("allow-fork",0,0)!=0){
29813031
ckin1Flags |= CKIN1_ALLOW_FORK;
29823032
}
3033
+ if(find_option("dump-manifest","d",0)!=0){
3034
+ ckin1Flags |= CKIN1_DUMP_MANIFEST;
3035
+ }
3036
+
3037
+ CheckinOneFileInfo_init(&cinf);
29833038
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
+ }
3051
+ }
3052
+
29843053
db_find_and_open_repository(0, 0);
29853054
verify_all_options();
29863055
user_select();
29873056
29883057
if(1){
@@ -2995,17 +3064,16 @@
29953064
"repo.");
29963065
}
29973066
}
29983067
29993068
zFilename = g.argv[2];
3000
- CheckinOneFileInfo_init(&cinf);
3001
- blob_append(&cinf.comment,
3002
- zComment ? zComment : "This is a test comment.",
3003
- -1);
3069
+ blob_append(&cinf.comment, zComment, -1);
30043070
cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename);
3005
- cinf.zUser = login_name();
3006
-
3071
+ cinf.zUser = mprintf("%s", zUser ? zUser : login_name());
3072
+ if(zDate){
3073
+ cinf.zDate = mprintf("%s", zDate);
3074
+ }
30073075
if(zRevision==0 || zRevision[0]==0){
30083076
if(g.localOpen/*checkout*/){
30093077
zRevision = db_lget("checkout-hash", 0)/*leak*/;
30103078
}else{
30113079
zRevision = "trunk";
@@ -3021,13 +3089,22 @@
30213089
blob_read_from_file(&cinf.fileContent, zFilename,
30223090
ExtFILE/*may want to reconsider*/);
30233091
sha3sum_init(256);
30243092
sha3sum_step_blob(&cinf.fileContent);
30253093
sha3sum_finish(&cinf.fileHash);
3026
- checkin_one_file(&cinf, &newRid, ckin1Flags);
3027
- CheckinOneFileInfo_cleanup(&cinf);
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
+ assert(blob_size(&errMsg)==0);
3100
+ }else{
3101
+ assert(blob_size(&errMsg));
3102
+ fossil_fatal("%b", &errMsg);
3103
+ }
3104
+ }
30283105
if(!(ckin1Flags & CKIN1_DRY_RUN) && newRid!=0 && g.localOpen!=0){
30293106
fossil_warning("The checkout state is now out of sync "
30303107
"with regards to this commit. It needs to be "
30313108
"'update'd or 'close'd and re-'open'ed.");
30323109
}
30333110
}
30343111
--- src/checkin.c
+++ src/checkin.c
@@ -2679,26 +2679,36 @@
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 const char *zUser; /* User name */
2689 char *zFilename; /* Name of single file to commit. */
2690 Blob fileContent; /* Content of the modified file. */
2691 Blob fileHash; /* Hash of this->fileContent */
 
 
 
 
2692 };
2693 #endif /* INTERFACE */
2694
 
 
 
2695 static void CheckinOneFileInfo_init( CheckinOneFileInfo * p ){
2696 memset(p, 0, sizeof(struct CheckinOneFileInfo));
2697 p->comment = p->fileContent = p->fileHash = empty_blob;
2698 }
2699
 
 
 
2700 static void CheckinOneFileInfo_cleanup( CheckinOneFileInfo * p ){
2701 blob_reset(&p->comment);
2702 blob_reset(&p->fileContent);
2703 blob_reset(&p->fileHash);
2704 if(p->pParent){
@@ -2705,12 +2715,32 @@
2705 manifest_destroy(p->pParent);
2706 }
2707 fossil_free(p->zFilename);
2708 fossil_free(p->zMimetype);
2709 fossil_free(p->zParentUuid);
 
 
2710 CheckinOneFileInfo_init(p);
2711 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2712
2713 /*
2714 ** Creates a manifest file, written to pOut, from the state in the
2715 ** fully-populated pCI argument. Returns true on success. On error,
2716 ** returns 0 and, if pErr is not NULL, writes an error message there.
@@ -2722,11 +2752,10 @@
2722 int cmp = -99; /* filename comparison result */
2723 int fperm = 0; /* file permissions */
2724 const char *zPerm = 0; /* permissions for new F-card */
2725 const char *zFilename = 0; /* filename to use for F-card */
2726 const char *zUuid = 0; /* UUID for F-card */
2727 const char *zErrMsg = 0; /* For error reporting. */
2728 int (*fncmp)(char const *, char const *) = /* filename comparator */
2729 filenames_are_case_sensitive()
2730 ? fossil_strcmp
2731 : fossil_stricmp;
2732
@@ -2733,11 +2762,11 @@
2733 assert(blob_str(&pCI->fileHash));
2734 assert(pCI->pParent);
2735 assert(pCI->zFilename);
2736 assert(pCI->zUser);
2737
2738 #define mf_err(MSG) zErrMsg = MSG; goto manifest_error
2739 /* Potential TODOs include...
2740 ** - Create a delta manifest, if possible, rather than a baseline.
2741 ** - Enable adding of new files? It's implemented by disabled until
2742 ** we at least ensure that pCI->zFilename is a path-relative
2743 ** filename.
@@ -2753,11 +2782,28 @@
2753 if(blob_size(&pCI->comment)!=0){
2754 blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment));
2755 }else{
2756 blob_append(pOut, "C (no\\scomment)\n", 16);
2757 }
2758 blob_appendf(pOut, "D %z\n", date_in_standard_format("now"));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2759
2760 manifest_file_rewind(pCI->pParent);
2761 while((zFile = manifest_file_next(pCI->pParent, 0))){
2762 cmp = fncmp(zFile->zName, pCI->zFilename);
2763 if(cmp<0){
@@ -2784,11 +2830,11 @@
2784 --pCI->pParent->iFile
2785 /* so that the next step picks up that entry again */;
2786 }
2787 }
2788 if(PERM_LNK==fperm){
2789 mf_err("Cannot commit symlinks with this approach.");
2790 }else if(PERM_EXE==fperm){
2791 zPerm = " x";
2792 }else{
2793 zPerm = "";
2794 }
@@ -2798,11 +2844,11 @@
2798 blob_appendf(pOut, "F %F %s%s\n", zFilename, zUuid, zPerm);
2799 while((zFile = manifest_file_next(pCI->pParent, 0))){
2800 cmp = fncmp(zFile->zName, pCI->zFilename);
2801 assert(cmp>0);
2802 if(cmp<=0){
2803 mf_err("Internal error: mis-ordering of F-cards detected.");
2804 }
2805 blob_appendf(pOut, "F %F %s%s%s\n",
2806 zFile->zName, zFile->zUuid,
2807 (zFile->zPerm && *zFile->zPerm) ? " " : "",
2808 (zFile->zPerm && *zFile->zPerm) ? zFile->zPerm : "");
@@ -2818,22 +2864,13 @@
2818 blob_appendf(pOut, "U %F\n", pCI->zUser);
2819 md5sum_blob(pOut, &zCard);
2820 blob_appendf(pOut, "Z %b\n", &zCard);
2821 blob_reset(&zCard);
2822 return 1;
2823 manifest_error:
2824 assert( zErrMsg );
2825 if(pErr) blob_append(pErr,zErrMsg,-1);
2826 return 0;
2827 #undef mf_err
2828 }
2829
2830 enum fossil_ckin1_flags {
2831 CKIN1_DRY_RUN = 1,
2832 CKIN1_ALLOW_FORK = 1<<1
2833 };
2834
2835 /*
2836 ** EXPERIMENTAL! Subject to change or removal at any time.
2837 **
2838 ** A so-called "single-file checkin" is a slimmed-down form of the
2839 ** checkin command which accepts only a single file and is intended to
@@ -2843,63 +2880,61 @@
2843 ** This routine uses the state from the given fully-populated pCI
2844 ** argument to add pCI->fileContent to the database, and create and
2845 ** save a manifest for that change. Ownership of pCI and its contents
2846 ** are unchanged.
2847 **
2848 ** Fails fatally on error. If pRid is not NULL, the RID of the
 
 
 
2849 ** resulting manifest is written to *pRid.
2850 **
2851 ** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags enum:
2852 **
2853 ** CKIN1_DRY_RUN: rolls back the transaction, else it commits as
2854 ** usual.
2855 **
2856 ** CKIN1_ALLOW_FORK: if false, checkin will fail if pCI->pParent is not
2857 ** currently a leaf.
2858 **
2859 */
2860 void checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int ckin1Flags ){
2861 Blob mf = empty_blob;
2862 Blob err = empty_blob;
2863 int rid = 0, frid = 0, parentRid;
2864 const int isPrivate = content_is_private(pCI->pParent->rid);
2865 ManifestFile * zFile;
2866 const char * zFilePrevUuid = 0; /* UUID of previous version of
2867 the file */
2868
2869 db_begin_transaction();
2870 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){
2871 fossil_fatal("no such user: %s", pCI->zUser);
2872 }
2873 parentRid = name_to_typed_rid(pCI->zParentUuid, "ci");
2874 assert(parentRid>0);
2875 if(!(CKIN1_ALLOW_FORK & ckin1Flags)
2876 && !is_a_leaf(parentRid)){
2877 fossil_fatal("Parent [%S] is not a leaf and forking is disabled.");
 
2878 }
2879 /*
2880 ** Confirm that pCI->zFilename can be found in pCI->pParent.
2881 ** If not, fail. This is admittedly an artificial limitation,
2882 ** not strictly necessary.
2883 */
2884 manifest_file_rewind(pCI->pParent);
2885 zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0);
2886 if(!zFile){
2887 fossil_fatal("File [%s] not found in manifest [%S]. "
2888 "Adding new files is currently not allowed.",
2889 pCI->zFilename, pCI->zParentUuid);
2890 }else if(zFile->zPerm && strstr(zFile->zPerm, "l")){
2891 fossil_fatal("Cannot save a symlink this way.");
2892 }else{
2893 if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){
2894 fossil_fatal("File is unchanged. Not saving.");
2895 }
2896 zFilePrevUuid = zFile->zUuid;
2897 }
2898 /* Create the manifest... */
2899 if(create_manifest_one_file(&mf, pCI, &err)==0){
2900 fossil_fatal("create_manifest_one_file() failed: %B", &err);
2901 }
2902 /* Add the file content to the db... */
2903 frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash),
2904 0, 0, isPrivate);
2905 if(zFilePrevUuid!=0){
@@ -2912,22 +2947,27 @@
2912 /* Save and crosslink the manifest... */
2913 rid = content_put_ex(&mf, 0, 0, 0, isPrivate);
2914 if(pRid!=0){
2915 *pRid = rid;
2916 }
2917 #if 1
2918 /* Only for development/debugging... */
2919 fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf);
2920 #endif
2921 manifest_crosslink(rid, &mf, 0);
2922 if(CKIN1_DRY_RUN & ckin1Flags){
2923 fossil_print("Rolling back transaction.\n");
2924 db_end_transaction(1);
2925 }else{
2926 db_end_transaction(0);
2927 }
2928 blob_reset(&mf);
 
 
 
 
 
 
2929 }
2930
2931 /*
2932 ** COMMAND: test-ci-one
2933 **
@@ -2939,50 +2979,79 @@
2939 ** where FILENAME is a repo-relative name as it would appear in the
2940 ** vfile table.
2941 **
2942 ** Options:
2943 **
2944 ** --as FILENAME The repository-side name of the input file,
2945 ** relative to the top of the repostory.
2946 ** Default is the same as the input file name.
2947 ** --comment|-m COMMENT Optional checkin comment.
2948 ** --revision|-r VERSION Commit from this version. Default is
2949 ** the checkout version (if available) or
2950 ** trunk (if used without a checkout).
2951 ** --wet-run Disables the default dry-run mode.
2952 ** --allow-fork Allows the commit to be made against a
2953 ** non-leaf parent. Note that no autosync
2954 ** is performed beforehand.
 
 
 
 
 
2955 **
2956 ** Example:
2957 **
2958 ** %fossil test-ci-one -R REPO -m ... -r foo --as src/myfile.c myfile.c
2959 **
2960 */
2961 void test_ci_one_cmd(){
2962 CheckinOneFileInfo cinf; /* checkin state */
2963 int parentVid = 0, newRid = 0; /* RID of parent version and new
2964 version */
2965 const char * zFilename; /* argv[2] */
2966 const char * zComment; /* -m comment */
 
2967 const char * zAsFilename; /* --as filename */
2968 const char * zRevision; /* --revision|-r [=trunk|checkout] */
 
 
2969 int ckin1Flags = 0; /* flags for checkin_one_file(). */
2970 if(g.argc<3){
2971 usage("INFILE");
2972 }
2973 zComment = find_option("comment","m",1);
 
2974 zAsFilename = find_option("as",0,1);
2975 zRevision = find_option("revision","r",1);
2976
 
2977 if(find_option("wet-run",0,0)==0){
2978 ckin1Flags |= CKIN1_DRY_RUN;
2979 }
2980 if(find_option("allow-fork",0,0)==0){
2981 ckin1Flags |= CKIN1_ALLOW_FORK;
2982 }
 
 
 
 
 
2983
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2984 db_find_and_open_repository(0, 0);
2985 verify_all_options();
2986 user_select();
2987
2988 if(1){
@@ -2995,17 +3064,16 @@
2995 "repo.");
2996 }
2997 }
2998
2999 zFilename = g.argv[2];
3000 CheckinOneFileInfo_init(&cinf);
3001 blob_append(&cinf.comment,
3002 zComment ? zComment : "This is a test comment.",
3003 -1);
3004 cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename);
3005 cinf.zUser = login_name();
3006
 
 
3007 if(zRevision==0 || zRevision[0]==0){
3008 if(g.localOpen/*checkout*/){
3009 zRevision = db_lget("checkout-hash", 0)/*leak*/;
3010 }else{
3011 zRevision = "trunk";
@@ -3021,13 +3089,22 @@
3021 blob_read_from_file(&cinf.fileContent, zFilename,
3022 ExtFILE/*may want to reconsider*/);
3023 sha3sum_init(256);
3024 sha3sum_step_blob(&cinf.fileContent);
3025 sha3sum_finish(&cinf.fileHash);
3026 checkin_one_file(&cinf, &newRid, ckin1Flags);
3027 CheckinOneFileInfo_cleanup(&cinf);
 
 
 
 
 
 
 
 
 
3028 if(!(ckin1Flags & CKIN1_DRY_RUN) && newRid!=0 && g.localOpen!=0){
3029 fossil_warning("The checkout state is now out of sync "
3030 "with regards to this commit. It needs to be "
3031 "'update'd or 'close'd and re-'open'ed.");
3032 }
3033 }
3034
--- src/checkin.c
+++ src/checkin.c
@@ -2679,26 +2679,36 @@
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 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.
2709 */
2710 static void CheckinOneFileInfo_cleanup( CheckinOneFileInfo * p ){
2711 blob_reset(&p->comment);
2712 blob_reset(&p->fileContent);
2713 blob_reset(&p->fileHash);
2714 if(p->pParent){
@@ -2705,12 +2715,32 @@
2715 manifest_destroy(p->pParent);
2716 }
2717 fossil_free(p->zFilename);
2718 fossil_free(p->zMimetype);
2719 fossil_free(p->zParentUuid);
2720 fossil_free(p->zUser);
2721 fossil_free(p->zDate);
2722 CheckinOneFileInfo_init(p);
2723 }
2724
2725 /*
2726 ** Flags for checkin_one_file()
2727 */
2728 enum fossil_ckin1_flags {
2729 /*
2730 ** Tells checkin_one_file() to use dry-run mode.
2731 */
2732 CKIN1_DRY_RUN = 1,
2733 /*
2734 ** Tells checkin_one_file() to allow forking from a non-leaf commit.
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,
2746 ** returns 0 and, if pErr is not NULL, writes an error message there.
@@ -2722,11 +2752,10 @@
2752 int cmp = -99; /* filename comparison result */
2753 int fperm = 0; /* file permissions */
2754 const char *zPerm = 0; /* permissions for new F-card */
2755 const char *zFilename = 0; /* filename to use for F-card */
2756 const char *zUuid = 0; /* UUID for F-card */
 
2757 int (*fncmp)(char const *, char const *) = /* filename comparator */
2758 filenames_are_case_sensitive()
2759 ? fossil_strcmp
2760 : fossil_stricmp;
2761
@@ -2733,11 +2762,11 @@
2762 assert(blob_str(&pCI->fileHash));
2763 assert(pCI->pParent);
2764 assert(pCI->zFilename);
2765 assert(pCI->zUser);
2766
2767 #define mf_err(EXPR) if(pErr) blob_appendf EXPR; return 0
2768 /* Potential TODOs include...
2769 ** - Create a delta manifest, if possible, rather than a baseline.
2770 ** - Enable adding of new files? It's implemented by disabled until
2771 ** we at least ensure that pCI->zFilename is a path-relative
2772 ** filename.
@@ -2753,11 +2782,28 @@
2782 if(blob_size(&pCI->comment)!=0){
2783 blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment));
2784 }else{
2785 blob_append(pOut, "C (no\\scomment)\n", 16);
2786 }
2787 {
2788 /*
2789 ** We don't use date_in_standard_format() because that has
2790 ** side-effects we don't want to trigger here.
2791 */
2792 char * zDVal = db_text(
2793 0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%f',%Q)",
2794 pCI->zDate
2795 ? pCI->zDate
2796 : "now");
2797 if(zDVal[0]==0){
2798 fossil_free(zDVal);
2799 mf_err((pErr,
2800 "Invalid date format (%s): use \"YYYY-MM-DD HH:MM:SS.SSS\"",
2801 pCI->zDate));
2802 }
2803 blob_appendf(pOut, "D %z\n", zDVal);
2804 }
2805
2806 manifest_file_rewind(pCI->pParent);
2807 while((zFile = manifest_file_next(pCI->pParent, 0))){
2808 cmp = fncmp(zFile->zName, pCI->zFilename);
2809 if(cmp<0){
@@ -2784,11 +2830,11 @@
2830 --pCI->pParent->iFile
2831 /* so that the next step picks up that entry again */;
2832 }
2833 }
2834 if(PERM_LNK==fperm){
2835 mf_err((pErr,"Cannot commit symlinks with this approach."));
2836 }else if(PERM_EXE==fperm){
2837 zPerm = " x";
2838 }else{
2839 zPerm = "";
2840 }
@@ -2798,11 +2844,11 @@
2844 blob_appendf(pOut, "F %F %s%s\n", zFilename, zUuid, zPerm);
2845 while((zFile = manifest_file_next(pCI->pParent, 0))){
2846 cmp = fncmp(zFile->zName, pCI->zFilename);
2847 assert(cmp>0);
2848 if(cmp<=0){
2849 mf_err((pErr,"Internal error: mis-ordering of F-cards detected."));
2850 }
2851 blob_appendf(pOut, "F %F %s%s%s\n",
2852 zFile->zName, zFile->zUuid,
2853 (zFile->zPerm && *zFile->zPerm) ? " " : "",
2854 (zFile->zPerm && *zFile->zPerm) ? zFile->zPerm : "");
@@ -2818,22 +2864,13 @@
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;
 
 
 
 
2869 #undef mf_err
2870 }
2871
 
 
 
 
 
2872 /*
2873 ** EXPERIMENTAL! Subject to change or removal at any time.
2874 **
2875 ** A so-called "single-file checkin" is a slimmed-down form of the
2876 ** checkin command which accepts only a single file and is intended to
@@ -2843,63 +2880,61 @@
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
2889 ** resulting manifest is written to *pRid.
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
2902 the file */
2903 #define ci_err(EXPR) if(pErr!=0){blob_appendf EXPR;} goto ci_error
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]. "
2923 "Adding new files is currently not allowed.",
2924 pCI->zFilename, pCI->zParentUuid));
2925 }else if(zFile->zPerm && strstr(zFile->zPerm, "l")){
2926 ci_err((pErr,"Cannot save a symlink this way."));
2927 }else{
2928 if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){
2929 ci_err((pErr,"File is unchanged. Not saving."));
2930 }
2931 zFilePrevUuid = zFile->zUuid;
2932 }
2933 /* Create the manifest... */
2934 if(create_manifest_one_file(&mf, pCI, pErr)==0){
2935 return 0;
2936 }
2937 /* Add the file content to the db... */
2938 frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash),
2939 0, 0, isPrivate);
2940 if(zFilePrevUuid!=0){
@@ -2912,22 +2947,27 @@
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;
2968 #undef ci_err
2969 }
2970
2971 /*
2972 ** COMMAND: test-ci-one
2973 **
@@ -2939,50 +2979,79 @@
2979 ** where FILENAME is a repo-relative name as it would appear in the
2980 ** vfile table.
2981 **
2982 ** Options:
2983 **
2984 ** --repository|-R REPO The repository file to commit to.
2985 ** --as FILENAME The repository-side name of the input file,
2986 ** relative to the top of the repository.
2987 ** Default is the same as the input file name.
2988 ** --comment|-m COMMENT Required checkin comment.
2989 ** --comment-file|-M FILE Reads checkin comment from the given file.
2990 ** --revision|-r VERSION Commit from this version. Default is
2991 ** the checkout version (if available) or
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:
3002 **
3003 ** %fossil test-ci-one -R REPO -m ... -r foo --as src/myfile.c myfile.c
3004 **
3005 */
3006 void test_ci_one_cmd(){
3007 CheckinOneFileInfo cinf; /* checkin state */
3008 int parentVid = 0, newRid = 0; /* RID of parent version and new
3009 version */
3010 const char * zFilename; /* argv[2] */
3011 const char * zComment; /* -m comment */
3012 const char * zCommentFile; /* -M FILE */
3013 const char * zAsFilename; /* --as filename */
3014 const char * zRevision; /* --revision|-r [=trunk|checkout] */
3015 const char * zUser; /* --user-override */
3016 const char * zDate; /* --date-override */
3017 int ckin1Flags = 0; /* flags for checkin_one_file(). */
3018 if(g.argc<3){
3019 usage("INFILE");
3020 }
3021 zComment = find_option("comment","m",1);
3022 zCommentFile = find_option("comment-file","M",1);
3023 zAsFilename = find_option("as",0,1);
3024 zRevision = find_option("revision","r",1);
3025 zUser = find_option("user-override",0,1);
3026 zDate = find_option("date-override",0,1);
3027 if(find_option("wet-run",0,0)==0){
3028 ckin1Flags |= CKIN1_DRY_RUN;
3029 }
3030 if(find_option("allow-fork",0,0)!=0){
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 }
3051 }
3052
3053 db_find_and_open_repository(0, 0);
3054 verify_all_options();
3055 user_select();
3056
3057 if(1){
@@ -2995,17 +3064,16 @@
3064 "repo.");
3065 }
3066 }
3067
3068 zFilename = g.argv[2];
3069 blob_append(&cinf.comment, zComment, -1);
 
 
 
3070 cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename);
3071 cinf.zUser = mprintf("%s", zUser ? zUser : login_name());
3072 if(zDate){
3073 cinf.zDate = mprintf("%s", zDate);
3074 }
3075 if(zRevision==0 || zRevision[0]==0){
3076 if(g.localOpen/*checkout*/){
3077 zRevision = db_lget("checkout-hash", 0)/*leak*/;
3078 }else{
3079 zRevision = "trunk";
@@ -3021,13 +3089,22 @@
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 assert(blob_size(&errMsg)==0);
3100 }else{
3101 assert(blob_size(&errMsg));
3102 fossil_fatal("%b", &errMsg);
3103 }
3104 }
3105 if(!(ckin1Flags & CKIN1_DRY_RUN) && newRid!=0 && g.localOpen!=0){
3106 fossil_warning("The checkout state is now out of sync "
3107 "with regards to this commit. It needs to be "
3108 "'update'd or 'close'd and re-'open'ed.");
3109 }
3110 }
3111

Keyboard Shortcuts

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