Fossil SCM
Reworked error reporting/propagation and added toggle to allow/disallow forking.
Commit
e9e68a6e0179db95ef6cbe81669a7d40fd08a3d788646c2e23dbca58d391b092
Parent
7e880c7898db049…
2 files changed
+52
-20
+1
-1
+52
-20
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -2682,10 +2682,11 @@ | ||
| 2682 | 2682 | */ |
| 2683 | 2683 | struct CheckinOneFileInfo { |
| 2684 | 2684 | Blob comment; /* Check-in comment text */ |
| 2685 | 2685 | char *zMimetype; /* Mimetype of check-in command. May be NULL */ |
| 2686 | 2686 | Manifest * pParent; /* parent checkin */ |
| 2687 | + char *zParentUuid; /* UUID of pParent */ | |
| 2687 | 2688 | const char *zUser; /* User name */ |
| 2688 | 2689 | char *zFilename; /* Name of single file to commit. */ |
| 2689 | 2690 | Blob fileContent; /* Content of the modified file. */ |
| 2690 | 2691 | Blob fileHash; /* Hash of this->fileContent */ |
| 2691 | 2692 | }; |
| @@ -2703,10 +2704,11 @@ | ||
| 2703 | 2704 | if(p->pParent){ |
| 2704 | 2705 | manifest_destroy(p->pParent); |
| 2705 | 2706 | } |
| 2706 | 2707 | fossil_free(p->zFilename); |
| 2707 | 2708 | fossil_free(p->zMimetype); |
| 2709 | + fossil_free(p->zParentUuid); | |
| 2708 | 2710 | CheckinOneFileInfo_init(p); |
| 2709 | 2711 | } |
| 2710 | 2712 | |
| 2711 | 2713 | /* |
| 2712 | 2714 | ** Creates a manifest file, written to pOut, from the state in the |
| @@ -2823,10 +2825,15 @@ | ||
| 2823 | 2825 | if(pErr) blob_append(pErr,zErrMsg,-1); |
| 2824 | 2826 | return 0; |
| 2825 | 2827 | #undef mf_err |
| 2826 | 2828 | } |
| 2827 | 2829 | |
| 2830 | +enum fossil_ckin1_flags { | |
| 2831 | +CKIN1_DRY_RUN = 1, | |
| 2832 | +CKIN1_ALLOW_FORK = 1<<1 | |
| 2833 | +}; | |
| 2834 | + | |
| 2828 | 2835 | /* |
| 2829 | 2836 | ** EXPERIMENTAL! Subject to change or removal at any time. |
| 2830 | 2837 | ** |
| 2831 | 2838 | ** A so-called "single-file checkin" is a slimmed-down form of the |
| 2832 | 2839 | ** checkin command which accepts only a single file and is intended to |
| @@ -2837,37 +2844,51 @@ | ||
| 2837 | 2844 | ** argument to add pCI->fileContent to the database, and create and |
| 2838 | 2845 | ** save a manifest for that change. Ownership of pCI and its contents |
| 2839 | 2846 | ** are unchanged. |
| 2840 | 2847 | ** |
| 2841 | 2848 | ** Fails fatally on error. If pRid is not NULL, the RID of the |
| 2842 | -** resulting manifest is written to *pRid. If bDryRun is true, | |
| 2843 | -** it rolls back its transaction, else it commits as usual. | |
| 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 | +** | |
| 2844 | 2859 | */ |
| 2845 | -void checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int bDryRun ){ | |
| 2860 | +void checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int ckin1Flags ){ | |
| 2846 | 2861 | Blob mf = empty_blob; |
| 2847 | 2862 | Blob err = empty_blob; |
| 2848 | - int rid = 0, frid = 0; | |
| 2863 | + int rid = 0, frid = 0, parentRid; | |
| 2849 | 2864 | const int isPrivate = content_is_private(pCI->pParent->rid); |
| 2850 | 2865 | ManifestFile * zFile; |
| 2851 | 2866 | const char * zFilePrevUuid = 0; /* UUID of previous version of |
| 2852 | 2867 | the file */ |
| 2853 | 2868 | |
| 2854 | 2869 | db_begin_transaction(); |
| 2855 | 2870 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){ |
| 2856 | 2871 | fossil_fatal("no such user: %s", pCI->zUser); |
| 2857 | 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 | + } | |
| 2858 | 2879 | /* |
| 2859 | 2880 | ** Confirm that pCI->zFilename can be found in pCI->pParent. |
| 2860 | 2881 | ** If not, fail. This is admittedly an artificial limitation, |
| 2861 | 2882 | ** not strictly necessary. |
| 2862 | 2883 | */ |
| 2863 | 2884 | manifest_file_rewind(pCI->pParent); |
| 2864 | 2885 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2865 | 2886 | if(!zFile){ |
| 2866 | - fossil_fatal("File [%s] not found in manifest. " | |
| 2887 | + fossil_fatal("File [%s] not found in manifest [%S]. " | |
| 2867 | 2888 | "Adding new files is currently not allowed.", |
| 2868 | - pCI->zFilename); | |
| 2889 | + pCI->zFilename, pCI->zParentUuid); | |
| 2869 | 2890 | }else if(zFile->zPerm && strstr(zFile->zPerm, "l")){ |
| 2870 | 2891 | fossil_fatal("Cannot save a symlink this way."); |
| 2871 | 2892 | }else{ |
| 2872 | 2893 | if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){ |
| 2873 | 2894 | fossil_fatal("File is unchanged. Not saving."); |
| @@ -2893,17 +2914,19 @@ | ||
| 2893 | 2914 | if(pRid!=0){ |
| 2894 | 2915 | *pRid = rid; |
| 2895 | 2916 | } |
| 2896 | 2917 | #if 1 |
| 2897 | 2918 | /* Only for development/debugging... */ |
| 2898 | - fossil_print("Manifest:\n%b", &mf); | |
| 2919 | + fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf); | |
| 2899 | 2920 | #endif |
| 2900 | 2921 | manifest_crosslink(rid, &mf, 0); |
| 2901 | - if(bDryRun){ | |
| 2922 | + if(CKIN1_DRY_RUN & ckin1Flags){ | |
| 2902 | 2923 | fossil_print("Rolling back transaction.\n"); |
| 2924 | + db_end_transaction(1); | |
| 2925 | + }else{ | |
| 2926 | + db_end_transaction(0); | |
| 2903 | 2927 | } |
| 2904 | - db_end_transaction(bDryRun ? 1 : 0); | |
| 2905 | 2928 | blob_reset(&mf); |
| 2906 | 2929 | } |
| 2907 | 2930 | |
| 2908 | 2931 | /* |
| 2909 | 2932 | ** COMMAND: test-ci-one |
| @@ -2924,14 +2947,17 @@ | ||
| 2924 | 2947 | ** --comment|-m COMMENT Optional checkin comment. |
| 2925 | 2948 | ** --revision|-r VERSION Commit from this version. Default is |
| 2926 | 2949 | ** the checkout version (if available) or |
| 2927 | 2950 | ** trunk (if used without a checkout). |
| 2928 | 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. | |
| 2929 | 2955 | ** |
| 2930 | 2956 | ** Example: |
| 2931 | 2957 | ** |
| 2932 | -** %fossil -m ... -r foo --as src/myfile.c myfile.c | |
| 2958 | +** %fossil test-ci-one -R REPO -m ... -r foo --as src/myfile.c myfile.c | |
| 2933 | 2959 | ** |
| 2934 | 2960 | */ |
| 2935 | 2961 | void test_ci_one_cmd(){ |
| 2936 | 2962 | CheckinOneFileInfo cinf; /* checkin state */ |
| 2937 | 2963 | int parentVid = 0, newRid = 0; /* RID of parent version and new |
| @@ -2938,20 +2964,25 @@ | ||
| 2938 | 2964 | version */ |
| 2939 | 2965 | const char * zFilename; /* argv[2] */ |
| 2940 | 2966 | const char * zComment; /* -m comment */ |
| 2941 | 2967 | const char * zAsFilename; /* --as filename */ |
| 2942 | 2968 | const char * zRevision; /* --revision|-r [=trunk|checkout] */ |
| 2943 | - int wetRunFlag = 0; | |
| 2944 | - | |
| 2969 | + int ckin1Flags = 0; /* flags for checkin_one_file(). */ | |
| 2945 | 2970 | if(g.argc<3){ |
| 2946 | 2971 | usage("INFILE"); |
| 2947 | 2972 | } |
| 2948 | - wetRunFlag = find_option("wet-run",0,0)!=0; | |
| 2949 | 2973 | zComment = find_option("comment","m",1); |
| 2950 | 2974 | zAsFilename = find_option("as",0,1); |
| 2951 | 2975 | zRevision = find_option("revision","r",1); |
| 2952 | 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 | + | |
| 2953 | 2984 | db_find_and_open_repository(0, 0); |
| 2954 | 2985 | verify_all_options(); |
| 2955 | 2986 | user_select(); |
| 2956 | 2987 | |
| 2957 | 2988 | if(1){ |
| @@ -2973,29 +3004,30 @@ | ||
| 2973 | 3004 | cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename); |
| 2974 | 3005 | cinf.zUser = login_name(); |
| 2975 | 3006 | |
| 2976 | 3007 | if(zRevision==0 || zRevision[0]==0){ |
| 2977 | 3008 | if(g.localOpen/*checkout*/){ |
| 2978 | - zRevision = db_lget("checkout-hash", 0) /*leak*/; | |
| 3009 | + zRevision = db_lget("checkout-hash", 0)/*leak*/; | |
| 2979 | 3010 | }else{ |
| 2980 | 3011 | zRevision = "trunk"; |
| 2981 | 3012 | } |
| 2982 | - if(zRevision==0 || zRevision[0]==0){ | |
| 2983 | - fossil_fatal("Cannot determine version to commit to."); | |
| 2984 | - } | |
| 3013 | + } | |
| 3014 | + name_to_uuid2(zRevision, "ci", &cinf.zParentUuid); | |
| 3015 | + if(cinf.zParentUuid==0){ | |
| 3016 | + fossil_fatal("Cannot determine version to commit to."); | |
| 2985 | 3017 | } |
| 2986 | - cinf.pParent = manifest_get_by_name(zRevision, &parentVid); | |
| 3018 | + cinf.pParent = manifest_get_by_name(cinf.zParentUuid, &parentVid); | |
| 2987 | 3019 | assert(parentVid>0); |
| 2988 | 3020 | assert(cinf.pParent!=0); |
| 2989 | 3021 | blob_read_from_file(&cinf.fileContent, zFilename, |
| 2990 | 3022 | ExtFILE/*may want to reconsider*/); |
| 2991 | 3023 | sha3sum_init(256); |
| 2992 | 3024 | sha3sum_step_blob(&cinf.fileContent); |
| 2993 | 3025 | sha3sum_finish(&cinf.fileHash); |
| 2994 | - checkin_one_file(&cinf, &newRid, wetRunFlag ? 0 : 1); | |
| 3026 | + checkin_one_file(&cinf, &newRid, ckin1Flags); | |
| 2995 | 3027 | CheckinOneFileInfo_cleanup(&cinf); |
| 2996 | - if(wetRunFlag!=0 && newRid!=0 && g.localOpen!=0){ | |
| 3028 | + if(!(ckin1Flags & CKIN1_DRY_RUN) && newRid!=0 && g.localOpen!=0){ | |
| 2997 | 3029 | fossil_warning("The checkout state is now out of sync " |
| 2998 | 3030 | "with regards to this commit. It needs to be " |
| 2999 | 3031 | "'update'd or 'close'd and re-'open'ed."); |
| 3000 | 3032 | } |
| 3001 | 3033 | } |
| 3002 | 3034 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2682,10 +2682,11 @@ | |
| 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 | const char *zUser; /* User name */ |
| 2688 | char *zFilename; /* Name of single file to commit. */ |
| 2689 | Blob fileContent; /* Content of the modified file. */ |
| 2690 | Blob fileHash; /* Hash of this->fileContent */ |
| 2691 | }; |
| @@ -2703,10 +2704,11 @@ | |
| 2703 | if(p->pParent){ |
| 2704 | manifest_destroy(p->pParent); |
| 2705 | } |
| 2706 | fossil_free(p->zFilename); |
| 2707 | fossil_free(p->zMimetype); |
| 2708 | CheckinOneFileInfo_init(p); |
| 2709 | } |
| 2710 | |
| 2711 | /* |
| 2712 | ** Creates a manifest file, written to pOut, from the state in the |
| @@ -2823,10 +2825,15 @@ | |
| 2823 | if(pErr) blob_append(pErr,zErrMsg,-1); |
| 2824 | return 0; |
| 2825 | #undef mf_err |
| 2826 | } |
| 2827 | |
| 2828 | /* |
| 2829 | ** EXPERIMENTAL! Subject to change or removal at any time. |
| 2830 | ** |
| 2831 | ** A so-called "single-file checkin" is a slimmed-down form of the |
| 2832 | ** checkin command which accepts only a single file and is intended to |
| @@ -2837,37 +2844,51 @@ | |
| 2837 | ** argument to add pCI->fileContent to the database, and create and |
| 2838 | ** save a manifest for that change. Ownership of pCI and its contents |
| 2839 | ** are unchanged. |
| 2840 | ** |
| 2841 | ** Fails fatally on error. If pRid is not NULL, the RID of the |
| 2842 | ** resulting manifest is written to *pRid. If bDryRun is true, |
| 2843 | ** it rolls back its transaction, else it commits as usual. |
| 2844 | */ |
| 2845 | void checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, int bDryRun ){ |
| 2846 | Blob mf = empty_blob; |
| 2847 | Blob err = empty_blob; |
| 2848 | int rid = 0, frid = 0; |
| 2849 | const int isPrivate = content_is_private(pCI->pParent->rid); |
| 2850 | ManifestFile * zFile; |
| 2851 | const char * zFilePrevUuid = 0; /* UUID of previous version of |
| 2852 | the file */ |
| 2853 | |
| 2854 | db_begin_transaction(); |
| 2855 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){ |
| 2856 | fossil_fatal("no such user: %s", pCI->zUser); |
| 2857 | } |
| 2858 | /* |
| 2859 | ** Confirm that pCI->zFilename can be found in pCI->pParent. |
| 2860 | ** If not, fail. This is admittedly an artificial limitation, |
| 2861 | ** not strictly necessary. |
| 2862 | */ |
| 2863 | manifest_file_rewind(pCI->pParent); |
| 2864 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2865 | if(!zFile){ |
| 2866 | fossil_fatal("File [%s] not found in manifest. " |
| 2867 | "Adding new files is currently not allowed.", |
| 2868 | pCI->zFilename); |
| 2869 | }else if(zFile->zPerm && strstr(zFile->zPerm, "l")){ |
| 2870 | fossil_fatal("Cannot save a symlink this way."); |
| 2871 | }else{ |
| 2872 | if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){ |
| 2873 | fossil_fatal("File is unchanged. Not saving."); |
| @@ -2893,17 +2914,19 @@ | |
| 2893 | if(pRid!=0){ |
| 2894 | *pRid = rid; |
| 2895 | } |
| 2896 | #if 1 |
| 2897 | /* Only for development/debugging... */ |
| 2898 | fossil_print("Manifest:\n%b", &mf); |
| 2899 | #endif |
| 2900 | manifest_crosslink(rid, &mf, 0); |
| 2901 | if(bDryRun){ |
| 2902 | fossil_print("Rolling back transaction.\n"); |
| 2903 | } |
| 2904 | db_end_transaction(bDryRun ? 1 : 0); |
| 2905 | blob_reset(&mf); |
| 2906 | } |
| 2907 | |
| 2908 | /* |
| 2909 | ** COMMAND: test-ci-one |
| @@ -2924,14 +2947,17 @@ | |
| 2924 | ** --comment|-m COMMENT Optional checkin comment. |
| 2925 | ** --revision|-r VERSION Commit from this version. Default is |
| 2926 | ** the checkout version (if available) or |
| 2927 | ** trunk (if used without a checkout). |
| 2928 | ** --wet-run Disables the default dry-run mode. |
| 2929 | ** |
| 2930 | ** Example: |
| 2931 | ** |
| 2932 | ** %fossil -m ... -r foo --as src/myfile.c myfile.c |
| 2933 | ** |
| 2934 | */ |
| 2935 | void test_ci_one_cmd(){ |
| 2936 | CheckinOneFileInfo cinf; /* checkin state */ |
| 2937 | int parentVid = 0, newRid = 0; /* RID of parent version and new |
| @@ -2938,20 +2964,25 @@ | |
| 2938 | version */ |
| 2939 | const char * zFilename; /* argv[2] */ |
| 2940 | const char * zComment; /* -m comment */ |
| 2941 | const char * zAsFilename; /* --as filename */ |
| 2942 | const char * zRevision; /* --revision|-r [=trunk|checkout] */ |
| 2943 | int wetRunFlag = 0; |
| 2944 | |
| 2945 | if(g.argc<3){ |
| 2946 | usage("INFILE"); |
| 2947 | } |
| 2948 | wetRunFlag = find_option("wet-run",0,0)!=0; |
| 2949 | zComment = find_option("comment","m",1); |
| 2950 | zAsFilename = find_option("as",0,1); |
| 2951 | zRevision = find_option("revision","r",1); |
| 2952 | |
| 2953 | db_find_and_open_repository(0, 0); |
| 2954 | verify_all_options(); |
| 2955 | user_select(); |
| 2956 | |
| 2957 | if(1){ |
| @@ -2973,29 +3004,30 @@ | |
| 2973 | cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename); |
| 2974 | cinf.zUser = login_name(); |
| 2975 | |
| 2976 | if(zRevision==0 || zRevision[0]==0){ |
| 2977 | if(g.localOpen/*checkout*/){ |
| 2978 | zRevision = db_lget("checkout-hash", 0) /*leak*/; |
| 2979 | }else{ |
| 2980 | zRevision = "trunk"; |
| 2981 | } |
| 2982 | if(zRevision==0 || zRevision[0]==0){ |
| 2983 | fossil_fatal("Cannot determine version to commit to."); |
| 2984 | } |
| 2985 | } |
| 2986 | cinf.pParent = manifest_get_by_name(zRevision, &parentVid); |
| 2987 | assert(parentVid>0); |
| 2988 | assert(cinf.pParent!=0); |
| 2989 | blob_read_from_file(&cinf.fileContent, zFilename, |
| 2990 | ExtFILE/*may want to reconsider*/); |
| 2991 | sha3sum_init(256); |
| 2992 | sha3sum_step_blob(&cinf.fileContent); |
| 2993 | sha3sum_finish(&cinf.fileHash); |
| 2994 | checkin_one_file(&cinf, &newRid, wetRunFlag ? 0 : 1); |
| 2995 | CheckinOneFileInfo_cleanup(&cinf); |
| 2996 | if(wetRunFlag!=0 && newRid!=0 && g.localOpen!=0){ |
| 2997 | fossil_warning("The checkout state is now out of sync " |
| 2998 | "with regards to this commit. It needs to be " |
| 2999 | "'update'd or 'close'd and re-'open'ed."); |
| 3000 | } |
| 3001 | } |
| 3002 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2682,10 +2682,11 @@ | |
| 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 | }; |
| @@ -2703,10 +2704,11 @@ | |
| 2704 | if(p->pParent){ |
| 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 |
| @@ -2823,10 +2825,15 @@ | |
| 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 |
| @@ -2837,37 +2844,51 @@ | |
| 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."); |
| @@ -2893,17 +2914,19 @@ | |
| 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 |
| @@ -2924,14 +2947,17 @@ | |
| 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 |
| @@ -2938,20 +2964,25 @@ | |
| 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){ |
| @@ -2973,29 +3004,30 @@ | |
| 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"; |
| 3012 | } |
| 3013 | } |
| 3014 | name_to_uuid2(zRevision, "ci", &cinf.zParentUuid); |
| 3015 | if(cinf.zParentUuid==0){ |
| 3016 | fossil_fatal("Cannot determine version to commit to."); |
| 3017 | } |
| 3018 | cinf.pParent = manifest_get_by_name(cinf.zParentUuid, &parentVid); |
| 3019 | assert(parentVid>0); |
| 3020 | assert(cinf.pParent!=0); |
| 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 |
+1
-1
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -1064,11 +1064,11 @@ | ||
| 1064 | 1064 | if( !isRepeat ) g.parseCnt[p->type]++; |
| 1065 | 1065 | return p; |
| 1066 | 1066 | |
| 1067 | 1067 | manifest_syntax_error: |
| 1068 | 1068 | { |
| 1069 | - char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 1069 | + char *zUuid = rid_to_uuid(rid); | |
| 1070 | 1070 | if( zUuid ){ |
| 1071 | 1071 | blob_appendf(pErr, "artifact [%s] ", zUuid); |
| 1072 | 1072 | fossil_free(zUuid); |
| 1073 | 1073 | } |
| 1074 | 1074 | } |
| 1075 | 1075 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1064,11 +1064,11 @@ | |
| 1064 | if( !isRepeat ) g.parseCnt[p->type]++; |
| 1065 | return p; |
| 1066 | |
| 1067 | manifest_syntax_error: |
| 1068 | { |
| 1069 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1070 | if( zUuid ){ |
| 1071 | blob_appendf(pErr, "artifact [%s] ", zUuid); |
| 1072 | fossil_free(zUuid); |
| 1073 | } |
| 1074 | } |
| 1075 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1064,11 +1064,11 @@ | |
| 1064 | if( !isRepeat ) g.parseCnt[p->type]++; |
| 1065 | return p; |
| 1066 | |
| 1067 | manifest_syntax_error: |
| 1068 | { |
| 1069 | char *zUuid = rid_to_uuid(rid); |
| 1070 | if( zUuid ){ |
| 1071 | blob_appendf(pErr, "artifact [%s] ", zUuid); |
| 1072 | fossil_free(zUuid); |
| 1073 | } |
| 1074 | } |
| 1075 |