Fossil SCM
Renamed the various "one" pieces to "mini", e.g. checkin_mini().
Commit
d84c5149164fc0870c7360683beb2942caabfd72c9d2defe4c0cd472167fcdfc
Parent
2af794163c3ba55…
1 file changed
+72
-66
+72
-66
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -2676,13 +2676,13 @@ | ||
| 2676 | 2676 | /* |
| 2677 | 2677 | ** State for the "web-checkin" infrastructure, which enables the |
| 2678 | 2678 | ** ability to commit changes to a single file via an HTTP request. |
| 2679 | 2679 | ** |
| 2680 | 2680 | ** Memory for all non-const (char *) members is owned by the |
| 2681 | -** CheckinOneFileInfo instance. | |
| 2681 | +** CheckinMiniInfo instance. | |
| 2682 | 2682 | */ |
| 2683 | -struct CheckinOneFileInfo { | |
| 2683 | +struct CheckinMiniInfo { | |
| 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 | 2687 | char *zParentUuid; /* UUID of pParent */ |
| 2688 | 2688 | char *zUser; /* User name */ |
| @@ -2694,23 +2694,23 @@ | ||
| 2694 | 2694 | relative to the top of the repo. */ |
| 2695 | 2695 | Blob fileContent; /* Content of file referred to by zFilename. */ |
| 2696 | 2696 | Blob fileHash; /* Hash of this->fileContent, using the |
| 2697 | 2697 | repo's preferred hash method. */ |
| 2698 | 2698 | }; |
| 2699 | -typedef struct CheckinOneFileInfo CheckinOneFileInfo; | |
| 2699 | +typedef struct CheckinMiniInfo CheckinMiniInfo; | |
| 2700 | 2700 | /* |
| 2701 | 2701 | ** Initializes p to a known-valid default state. |
| 2702 | 2702 | */ |
| 2703 | -static void CheckinOneFileInfo_init( CheckinOneFileInfo * p ){ | |
| 2704 | - memset(p, 0, sizeof(CheckinOneFileInfo)); | |
| 2703 | +static void CheckinMiniInfo_init( CheckinMiniInfo * p ){ | |
| 2704 | + memset(p, 0, sizeof(CheckinMiniInfo)); | |
| 2705 | 2705 | p->comment = p->fileContent = p->fileHash = empty_blob; |
| 2706 | 2706 | } |
| 2707 | 2707 | |
| 2708 | 2708 | /* |
| 2709 | 2709 | ** Frees all memory owned by p, but does not free p. |
| 2710 | 2710 | */ |
| 2711 | -static void CheckinOneFileInfo_cleanup( CheckinOneFileInfo * p ){ | |
| 2711 | +static void CheckinMiniInfo_cleanup( CheckinMiniInfo * p ){ | |
| 2712 | 2712 | blob_reset(&p->comment); |
| 2713 | 2713 | blob_reset(&p->fileContent); |
| 2714 | 2714 | blob_reset(&p->fileHash); |
| 2715 | 2715 | if(p->pParent){ |
| 2716 | 2716 | manifest_destroy(p->pParent); |
| @@ -2718,40 +2718,40 @@ | ||
| 2718 | 2718 | fossil_free(p->zFilename); |
| 2719 | 2719 | fossil_free(p->zMimetype); |
| 2720 | 2720 | fossil_free(p->zParentUuid); |
| 2721 | 2721 | fossil_free(p->zUser); |
| 2722 | 2722 | fossil_free(p->zDate); |
| 2723 | - CheckinOneFileInfo_init(p); | |
| 2723 | + CheckinMiniInfo_init(p); | |
| 2724 | 2724 | } |
| 2725 | 2725 | |
| 2726 | 2726 | /* |
| 2727 | -** Flags for checkin_one_file() | |
| 2728 | -*/ | |
| 2729 | -enum fossil_ckin1_flags { | |
| 2730 | -/* | |
| 2731 | -** Tells checkin_one_file() to use dry-run mode. | |
| 2732 | -*/ | |
| 2733 | -CKIN1_DRY_RUN = 1, | |
| 2734 | -/* | |
| 2735 | -** Tells checkin_one_file() to allow forking from a non-leaf commit. | |
| 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, | |
| 2727 | +** Flags for checkin_mini() | |
| 2728 | +*/ | |
| 2729 | +enum fossil_cimini_flags { | |
| 2730 | +/* | |
| 2731 | +** Tells checkin_mini() to use dry-run mode. | |
| 2732 | +*/ | |
| 2733 | +CIMINI_DRY_RUN = 1, | |
| 2734 | +/* | |
| 2735 | +** Tells checkin_mini() to allow forking from a non-leaf commit. | |
| 2736 | +*/ | |
| 2737 | +CIMINI_ALLOW_FORK = 1<<1, | |
| 2738 | +/* | |
| 2739 | +** Tells checkin_mini() to dump its generated manifest to stdout. | |
| 2740 | +*/ | |
| 2741 | +CIMINI_DUMP_MANIFEST = 1<<2, | |
| 2742 | 2742 | |
| 2743 | 2743 | /* |
| 2744 | 2744 | ** By default, content containing what appears to be a merge conflict |
| 2745 | 2745 | ** marker is not permitted. This flag relaxes that requirement. |
| 2746 | 2746 | */ |
| 2747 | -CKIN1_ALLOW_MERGE_MARKER = 1<<3, | |
| 2747 | +CIMINI_ALLOW_MERGE_MARKER = 1<<3, | |
| 2748 | 2748 | |
| 2749 | 2749 | /* |
| 2750 | 2750 | ** NOT YET IMPLEMENTED. |
| 2751 | 2751 | */ |
| 2752 | -CKIN1_ALLOW_CLOSED_LEAF = 1<<4 | |
| 2752 | +CIMINI_ALLOW_CLOSED_LEAF = 1<<4 | |
| 2753 | 2753 | }; |
| 2754 | 2754 | |
| 2755 | 2755 | /* |
| 2756 | 2756 | ** Creates a manifest file, written to pOut, from the state in the |
| 2757 | 2757 | ** fully-populated pCI argument. pCI is not *semantically* modified |
| @@ -2759,13 +2759,12 @@ | ||
| 2759 | 2759 | ** any given blob. |
| 2760 | 2760 | ** |
| 2761 | 2761 | ** Returns true on success. On error, returns 0 and, if pErr is not |
| 2762 | 2762 | ** NULL, writes an error message there. |
| 2763 | 2763 | */ |
| 2764 | -static int create_manifest_one_file( Blob * pOut, | |
| 2765 | - CheckinOneFileInfo * pCI, | |
| 2766 | - Blob * pErr){ | |
| 2764 | +static int create_manifest_mini( Blob * pOut, CheckinMiniInfo * pCI, | |
| 2765 | + Blob * pErr){ | |
| 2767 | 2766 | Blob zCard = empty_blob; /* Z-card checksum */ |
| 2768 | 2767 | ManifestFile *zFile; /* One file entry from the pCI->pParent*/ |
| 2769 | 2768 | int cmp = -99; /* filename comparison result */ |
| 2770 | 2769 | int fperm = 0; /* file permissions */ |
| 2771 | 2770 | const char *zPerm = 0; /* permissions for new F-card */ |
| @@ -2881,35 +2880,42 @@ | ||
| 2881 | 2880 | } |
| 2882 | 2881 | |
| 2883 | 2882 | /* |
| 2884 | 2883 | ** EXPERIMENTAL! Subject to change or removal at any time. |
| 2885 | 2884 | ** |
| 2886 | -** A so-called "single-file checkin" is a slimmed-down form of the | |
| 2887 | -** checkin command which accepts only a single file and is intended to | |
| 2888 | -** accept edits to a file via the web interface or from the CLI from | |
| 2889 | -** outside of a checkout. | |
| 2885 | +** A so-called "single-file/mini/web checkin" is a slimmed-down form | |
| 2886 | +** of the checkin command which accepts only a single file and is | |
| 2887 | +** intended to accept edits to a file via the web interface or from | |
| 2888 | +** the CLI from outside of a checkout. | |
| 2889 | +** | |
| 2890 | +** Being fully non-interactive is a requirement for this function, | |
| 2891 | +** thus it cannot perform autosync or similar activities. | |
| 2890 | 2892 | ** |
| 2891 | 2893 | ** This routine uses the state from the given fully-populated pCI |
| 2892 | 2894 | ** argument to add pCI->fileContent to the database, and create and |
| 2893 | 2895 | ** save a manifest for that change. Ownership of pCI and its contents |
| 2894 | 2896 | ** are unchanged. |
| 2895 | 2897 | ** |
| 2896 | 2898 | ** If pCI->fileHash is empty, this routine populates it with the |
| 2897 | -** repository's preferred hash algorithm. | |
| 2899 | +** repository's preferred hash algorithm. pCI is not otherwise | |
| 2900 | +** modified, nor is its ownership modified. | |
| 2901 | +** | |
| 2902 | +** This function validates several of the inputs and fails if any | |
| 2903 | +** validation fails. | |
| 2898 | 2904 | ** |
| 2899 | 2905 | ** On error, returns false (0) and, if pErr is not NULL, writes a |
| 2900 | 2906 | ** diagnostic message there. |
| 2901 | 2907 | ** |
| 2902 | 2908 | ** Returns true on success. If pRid is not NULL, the RID of the |
| 2903 | 2909 | ** resulting manifest is written to *pRid. |
| 2904 | 2910 | ** |
| 2905 | -** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags | |
| 2911 | +** ciminiFlags is a bitmask of optional flags from fossil_cimini_flags | |
| 2906 | 2912 | ** enum. See that enum for the docs for each flag. Pass 0 for no |
| 2907 | 2913 | ** flags. |
| 2908 | 2914 | */ |
| 2909 | -static int checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, | |
| 2910 | - int ckin1Flags, Blob * pErr ){ | |
| 2915 | +static int checkin_mini( CheckinMiniInfo * pCI, int *pRid, | |
| 2916 | + int ciminiFlags, Blob * pErr ){ | |
| 2911 | 2917 | Blob mf = empty_blob; /* output manifest */ |
| 2912 | 2918 | int rid = 0, frid = 0; /* various RIDs */ |
| 2913 | 2919 | const int isPrivate = content_is_private(pCI->pParent->rid); |
| 2914 | 2920 | ManifestFile * zFile; /* file from pCI->pParent */; |
| 2915 | 2921 | const char * zFilePrevUuid = 0; /* UUID of previous version of |
| @@ -2927,23 +2933,19 @@ | ||
| 2927 | 2933 | ** no reason we can't do that via the generated manifest, |
| 2928 | 2934 | ** but the commit command does not offer that option, so |
| 2929 | 2935 | ** we won't, either. |
| 2930 | 2936 | */ |
| 2931 | 2937 | } |
| 2932 | - if(!(CKIN1_ALLOW_FORK & ckin1Flags) | |
| 2933 | - && !is_a_leaf(pCI->pParent->rid)){ | |
| 2938 | + if(!(CIMINI_ALLOW_FORK & ciminiFlags) | |
| 2939 | + && !is_a_leaf(pCI->pParent->rid)){ | |
| 2934 | 2940 | ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.", |
| 2935 | 2941 | pCI->zParentUuid)); |
| 2936 | 2942 | } |
| 2937 | - if(!(CKIN1_ALLOW_MERGE_MARKER & ckin1Flags) | |
| 2938 | - && contains_merge_marker(&pCI->fileContent)){ | |
| 2943 | + if(!(CIMINI_ALLOW_MERGE_MARKER & ciminiFlags) | |
| 2944 | + && contains_merge_marker(&pCI->fileContent)){ | |
| 2939 | 2945 | ci_err((pErr,"Content appears to contain a merge conflict marker.")); |
| 2940 | 2946 | } |
| 2941 | - if(blob_size(&pCI->fileHash)==0){ | |
| 2942 | - hname_hash(&pCI->fileContent, 0, &pCI->fileHash); | |
| 2943 | - assert(blob_size(&pCI->fileHash)>0); | |
| 2944 | - } | |
| 2945 | 2947 | /* Potential TODOs include: |
| 2946 | 2948 | ** |
| 2947 | 2949 | ** - Commit allows an empty checkin only with a flag, but we |
| 2948 | 2950 | ** currently disallow it entirely. Conform with commit? |
| 2949 | 2951 | ** |
| @@ -2955,11 +2957,13 @@ | ||
| 2955 | 2957 | ** Confirm that pCI->zFilename can be found in pCI->pParent. If |
| 2956 | 2958 | ** not, fail. This is admittedly an artificial limitation, not |
| 2957 | 2959 | ** strictly necessary. We do it to hopefully reduce the chance of an |
| 2958 | 2960 | ** "oops" where file X/Y/z gets committed as X/Y/Z due to a typo or |
| 2959 | 2961 | ** case-sensitivity mismatch between the user/repo/filesystem, or |
| 2960 | - ** some such. | |
| 2962 | + ** some such. That said, the remainder of this function is written | |
| 2963 | + ** as if this check did not exist, so enabling it "should" just be a | |
| 2964 | + ** matter of removing this check or guarding it with a flag. | |
| 2961 | 2965 | */ |
| 2962 | 2966 | manifest_file_rewind(pCI->pParent); |
| 2963 | 2967 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2964 | 2968 | if(!zFile){ |
| 2965 | 2969 | ci_err((pErr,"File [%s] not found in manifest [%S]. " |
| @@ -2971,46 +2975,48 @@ | ||
| 2971 | 2975 | if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){ |
| 2972 | 2976 | ci_err((pErr,"File is unchanged. Not saving.")); |
| 2973 | 2977 | } |
| 2974 | 2978 | zFilePrevUuid = zFile->zUuid; |
| 2975 | 2979 | } |
| 2980 | + if(blob_size(&pCI->fileHash)==0){ | |
| 2981 | + hname_hash(&pCI->fileContent, 0, &pCI->fileHash); | |
| 2982 | + assert(blob_size(&pCI->fileHash)>0); | |
| 2983 | + } | |
| 2976 | 2984 | /* Create the manifest... */ |
| 2977 | - if(create_manifest_one_file(&mf, pCI, pErr)==0){ | |
| 2985 | + if(create_manifest_mini(&mf, pCI, pErr)==0){ | |
| 2978 | 2986 | return 0; |
| 2979 | 2987 | } |
| 2980 | - /* Add the file content to the db... */ | |
| 2988 | + /* Save and deltify the file content... */ | |
| 2981 | 2989 | frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash), |
| 2982 | 2990 | 0, 0, isPrivate); |
| 2983 | 2991 | if(zFilePrevUuid!=0){ |
| 2984 | - /* Deltify against previous file version... */ | |
| 2985 | - int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q", | |
| 2986 | - zFilePrevUuid); | |
| 2992 | + int prevFRid = fast_uuid_to_rid(zFilePrevUuid); | |
| 2987 | 2993 | assert(prevFRid>0); |
| 2988 | 2994 | content_deltify(frid, &prevFRid, 1, 0); |
| 2989 | 2995 | } |
| 2990 | 2996 | /* Save, deltify, and crosslink the manifest... */ |
| 2991 | 2997 | rid = content_put_ex(&mf, 0, 0, 0, isPrivate); |
| 2992 | 2998 | content_deltify(rid, &pCI->pParent->rid, 1, 0); |
| 2993 | 2999 | if(pRid!=0){ |
| 2994 | 3000 | *pRid = rid; |
| 2995 | 3001 | } |
| 2996 | - if( ckin1Flags & CKIN1_DUMP_MANIFEST ){ | |
| 3002 | + if(ciminiFlags & CIMINI_DUMP_MANIFEST){ | |
| 2997 | 3003 | fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf); |
| 2998 | 3004 | } |
| 2999 | 3005 | manifest_crosslink(rid, &mf, 0); |
| 3000 | 3006 | blob_reset(&mf); |
| 3001 | - db_end_transaction((CKIN1_DRY_RUN & ckin1Flags) ? 1 : 0); | |
| 3007 | + db_end_transaction((CIMINI_DRY_RUN & ciminiFlags) ? 1 : 0); | |
| 3002 | 3008 | return 1; |
| 3003 | 3009 | ci_error: |
| 3004 | 3010 | assert(db_transaction_nesting_depth()>0); |
| 3005 | 3011 | db_end_transaction(1); |
| 3006 | 3012 | return 0; |
| 3007 | 3013 | #undef ci_err |
| 3008 | 3014 | } |
| 3009 | 3015 | |
| 3010 | 3016 | /* |
| 3011 | -** COMMAND: test-ci-one | |
| 3017 | +** COMMAND: test-ci-mini | |
| 3012 | 3018 | ** |
| 3013 | 3019 | ** This is an on-going experiment, subject to change or removal at |
| 3014 | 3020 | ** any time. |
| 3015 | 3021 | ** |
| 3016 | 3022 | ** Usage: %fossil ?OPTIONS? FILENAME |
| @@ -3027,55 +3033,55 @@ | ||
| 3027 | 3033 | ** --comment|-m COMMENT Required checkin comment. |
| 3028 | 3034 | ** --comment-file|-M FILE Reads checkin comment from the given file. |
| 3029 | 3035 | ** --revision|-r VERSION Commit from this version. Default is |
| 3030 | 3036 | ** the checkout version (if available) or |
| 3031 | 3037 | ** trunk (if used without a checkout). |
| 3032 | -** --wet-run Disables the default dry-run mode. | |
| 3033 | 3038 | ** --allow-fork Allows the commit to be made against a |
| 3034 | 3039 | ** non-leaf parent. Note that no autosync |
| 3035 | 3040 | ** is performed beforehand. |
| 3036 | 3041 | ** --allow-merge-conflict Allows checkin of a file even if it appears |
| 3037 | 3042 | ** to contain a fossil merge conflict marker. |
| 3038 | 3043 | ** --user-override USER USER to use instead of the current default. |
| 3039 | 3044 | ** --date-override DATETIME DATE to use instead of 'now'. |
| 3040 | 3045 | ** --dump-manifest|-d Dumps the generated manifest to stdout. |
| 3046 | +** --wet-run Disables the default dry-run mode. | |
| 3041 | 3047 | ** |
| 3042 | 3048 | ** Example: |
| 3043 | 3049 | ** |
| 3044 | -** %fossil test-ci-one -R REPO -m ... -r foo --as src/myfile.c myfile.c | |
| 3050 | +** %fossil test-ci-mini -R REPO -m ... -r foo --as src/myfile.c myfile.c | |
| 3045 | 3051 | ** |
| 3046 | 3052 | */ |
| 3047 | -void test_ci_one_cmd(){ | |
| 3048 | - CheckinOneFileInfo cinf; /* checkin state */ | |
| 3053 | +void test_ci_mini_cmd(){ | |
| 3054 | + CheckinMiniInfo cinf; /* checkin state */ | |
| 3049 | 3055 | int newRid = 0; /* RID of new version */ |
| 3050 | 3056 | const char * zFilename; /* argv[2] */ |
| 3051 | 3057 | const char * zComment; /* -m comment */ |
| 3052 | 3058 | const char * zCommentFile; /* -M FILE */ |
| 3053 | 3059 | const char * zAsFilename; /* --as filename */ |
| 3054 | 3060 | const char * zRevision; /* --revision|-r [=trunk|checkout] */ |
| 3055 | 3061 | const char * zUser; /* --user-override */ |
| 3056 | 3062 | const char * zDate; /* --date-override */ |
| 3057 | - int ckin1Flags = 0; /* flags for checkin_one_file(). */ | |
| 3063 | + int ciminiFlags = 0; /* flags for checkin_mini(). */ | |
| 3058 | 3064 | |
| 3059 | - CheckinOneFileInfo_init(&cinf); | |
| 3065 | + CheckinMiniInfo_init(&cinf); | |
| 3060 | 3066 | zComment = find_option("comment","m",1); |
| 3061 | 3067 | zCommentFile = find_option("comment-file","M",1); |
| 3062 | 3068 | zAsFilename = find_option("as",0,1); |
| 3063 | 3069 | zRevision = find_option("revision","r",1); |
| 3064 | 3070 | zUser = find_option("user-override",0,1); |
| 3065 | 3071 | zDate = find_option("date-override",0,1); |
| 3066 | 3072 | if(find_option("wet-run",0,0)==0){ |
| 3067 | - ckin1Flags |= CKIN1_DRY_RUN; | |
| 3073 | + ciminiFlags |= CIMINI_DRY_RUN; | |
| 3068 | 3074 | } |
| 3069 | 3075 | if(find_option("allow-fork",0,0)!=0){ |
| 3070 | - ckin1Flags |= CKIN1_ALLOW_FORK; | |
| 3076 | + ciminiFlags |= CIMINI_ALLOW_FORK; | |
| 3071 | 3077 | } |
| 3072 | 3078 | if(find_option("dump-manifest","d",0)!=0){ |
| 3073 | - ckin1Flags |= CKIN1_DUMP_MANIFEST; | |
| 3079 | + ciminiFlags |= CIMINI_DUMP_MANIFEST; | |
| 3074 | 3080 | } |
| 3075 | 3081 | if(find_option("allow-merge-conflict",0,0)!=0){ |
| 3076 | - ckin1Flags |= CKIN1_ALLOW_MERGE_MARKER; | |
| 3082 | + ciminiFlags |= CIMINI_ALLOW_MERGE_MARKER; | |
| 3077 | 3083 | } |
| 3078 | 3084 | |
| 3079 | 3085 | db_find_and_open_repository(0, 0); |
| 3080 | 3086 | verify_all_options(); |
| 3081 | 3087 | user_select(); |
| @@ -3107,11 +3113,11 @@ | ||
| 3107 | 3113 | fossil_fatal("Non-empty checkin comment is required."); |
| 3108 | 3114 | } |
| 3109 | 3115 | } |
| 3110 | 3116 | |
| 3111 | 3117 | zFilename = g.argv[2]; |
| 3112 | - cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename); | |
| 3118 | + cinf.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename); | |
| 3113 | 3119 | cinf.zUser = mprintf("%s", zUser ? zUser : login_name()); |
| 3114 | 3120 | if(zDate){ |
| 3115 | 3121 | cinf.zDate = mprintf("%s", zDate); |
| 3116 | 3122 | } |
| 3117 | 3123 | if(zRevision==0 || zRevision[0]==0){ |
| @@ -3129,21 +3135,21 @@ | ||
| 3129 | 3135 | assert(cinf.pParent!=0); |
| 3130 | 3136 | blob_read_from_file(&cinf.fileContent, zFilename, |
| 3131 | 3137 | ExtFILE/*may want to reconsider*/); |
| 3132 | 3138 | { |
| 3133 | 3139 | Blob errMsg = empty_blob; |
| 3134 | - const int rc = checkin_one_file(&cinf, &newRid, ckin1Flags, | |
| 3140 | + const int rc = checkin_mini(&cinf, &newRid, ciminiFlags, | |
| 3135 | 3141 | &errMsg); |
| 3136 | - CheckinOneFileInfo_cleanup(&cinf); | |
| 3142 | + CheckinMiniInfo_cleanup(&cinf); | |
| 3137 | 3143 | if(rc){ |
| 3138 | 3144 | assert(blob_size(&errMsg)==0); |
| 3139 | 3145 | }else{ |
| 3140 | 3146 | assert(blob_size(&errMsg)); |
| 3141 | 3147 | fossil_fatal("%b", &errMsg); |
| 3142 | 3148 | } |
| 3143 | 3149 | } |
| 3144 | - if(!(ckin1Flags & CKIN1_DRY_RUN) && newRid!=0 && g.localOpen!=0){ | |
| 3150 | + if(!(ciminiFlags & CIMINI_DRY_RUN) && newRid!=0 && g.localOpen!=0){ | |
| 3145 | 3151 | fossil_warning("The checkout state is now out of sync " |
| 3146 | 3152 | "with regards to this commit. It needs to be " |
| 3147 | 3153 | "'update'd or 'close'd and re-'open'ed."); |
| 3148 | 3154 | } |
| 3149 | 3155 | } |
| 3150 | 3156 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2676,13 +2676,13 @@ | |
| 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 | char *zUser; /* User name */ |
| @@ -2694,23 +2694,23 @@ | |
| 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. |
| 2710 | */ |
| 2711 | static void CheckinOneFileInfo_cleanup( CheckinOneFileInfo * p ){ |
| 2712 | blob_reset(&p->comment); |
| 2713 | blob_reset(&p->fileContent); |
| 2714 | blob_reset(&p->fileHash); |
| 2715 | if(p->pParent){ |
| 2716 | manifest_destroy(p->pParent); |
| @@ -2718,40 +2718,40 @@ | |
| 2718 | fossil_free(p->zFilename); |
| 2719 | fossil_free(p->zMimetype); |
| 2720 | fossil_free(p->zParentUuid); |
| 2721 | fossil_free(p->zUser); |
| 2722 | fossil_free(p->zDate); |
| 2723 | CheckinOneFileInfo_init(p); |
| 2724 | } |
| 2725 | |
| 2726 | /* |
| 2727 | ** Flags for checkin_one_file() |
| 2728 | */ |
| 2729 | enum fossil_ckin1_flags { |
| 2730 | /* |
| 2731 | ** Tells checkin_one_file() to use dry-run mode. |
| 2732 | */ |
| 2733 | CKIN1_DRY_RUN = 1, |
| 2734 | /* |
| 2735 | ** Tells checkin_one_file() to allow forking from a non-leaf commit. |
| 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. pCI is not *semantically* modified |
| @@ -2759,13 +2759,12 @@ | |
| 2759 | ** any given blob. |
| 2760 | ** |
| 2761 | ** Returns true on success. On error, returns 0 and, if pErr is not |
| 2762 | ** NULL, writes an error message there. |
| 2763 | */ |
| 2764 | static int create_manifest_one_file( Blob * pOut, |
| 2765 | CheckinOneFileInfo * pCI, |
| 2766 | Blob * pErr){ |
| 2767 | Blob zCard = empty_blob; /* Z-card checksum */ |
| 2768 | ManifestFile *zFile; /* One file entry from the pCI->pParent*/ |
| 2769 | int cmp = -99; /* filename comparison result */ |
| 2770 | int fperm = 0; /* file permissions */ |
| 2771 | const char *zPerm = 0; /* permissions for new F-card */ |
| @@ -2881,35 +2880,42 @@ | |
| 2881 | } |
| 2882 | |
| 2883 | /* |
| 2884 | ** EXPERIMENTAL! Subject to change or removal at any time. |
| 2885 | ** |
| 2886 | ** A so-called "single-file checkin" is a slimmed-down form of the |
| 2887 | ** checkin command which accepts only a single file and is intended to |
| 2888 | ** accept edits to a file via the web interface or from the CLI from |
| 2889 | ** outside of a checkout. |
| 2890 | ** |
| 2891 | ** This routine uses the state from the given fully-populated pCI |
| 2892 | ** argument to add pCI->fileContent to the database, and create and |
| 2893 | ** save a manifest for that change. Ownership of pCI and its contents |
| 2894 | ** are unchanged. |
| 2895 | ** |
| 2896 | ** If pCI->fileHash is empty, this routine populates it with the |
| 2897 | ** repository's preferred hash algorithm. |
| 2898 | ** |
| 2899 | ** On error, returns false (0) and, if pErr is not NULL, writes a |
| 2900 | ** diagnostic message there. |
| 2901 | ** |
| 2902 | ** Returns true on success. If pRid is not NULL, the RID of the |
| 2903 | ** resulting manifest is written to *pRid. |
| 2904 | ** |
| 2905 | ** ckin1Flags is a bitmask of optional flags from fossil_ckin1_flags |
| 2906 | ** enum. See that enum for the docs for each flag. Pass 0 for no |
| 2907 | ** flags. |
| 2908 | */ |
| 2909 | static int checkin_one_file( CheckinOneFileInfo * pCI, int *pRid, |
| 2910 | int ckin1Flags, Blob * pErr ){ |
| 2911 | Blob mf = empty_blob; /* output manifest */ |
| 2912 | int rid = 0, frid = 0; /* various RIDs */ |
| 2913 | const int isPrivate = content_is_private(pCI->pParent->rid); |
| 2914 | ManifestFile * zFile; /* file from pCI->pParent */; |
| 2915 | const char * zFilePrevUuid = 0; /* UUID of previous version of |
| @@ -2927,23 +2933,19 @@ | |
| 2927 | ** no reason we can't do that via the generated manifest, |
| 2928 | ** but the commit command does not offer that option, so |
| 2929 | ** we won't, either. |
| 2930 | */ |
| 2931 | } |
| 2932 | if(!(CKIN1_ALLOW_FORK & ckin1Flags) |
| 2933 | && !is_a_leaf(pCI->pParent->rid)){ |
| 2934 | ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.", |
| 2935 | pCI->zParentUuid)); |
| 2936 | } |
| 2937 | if(!(CKIN1_ALLOW_MERGE_MARKER & ckin1Flags) |
| 2938 | && contains_merge_marker(&pCI->fileContent)){ |
| 2939 | ci_err((pErr,"Content appears to contain a merge conflict marker.")); |
| 2940 | } |
| 2941 | if(blob_size(&pCI->fileHash)==0){ |
| 2942 | hname_hash(&pCI->fileContent, 0, &pCI->fileHash); |
| 2943 | assert(blob_size(&pCI->fileHash)>0); |
| 2944 | } |
| 2945 | /* Potential TODOs include: |
| 2946 | ** |
| 2947 | ** - Commit allows an empty checkin only with a flag, but we |
| 2948 | ** currently disallow it entirely. Conform with commit? |
| 2949 | ** |
| @@ -2955,11 +2957,13 @@ | |
| 2955 | ** Confirm that pCI->zFilename can be found in pCI->pParent. If |
| 2956 | ** not, fail. This is admittedly an artificial limitation, not |
| 2957 | ** strictly necessary. We do it to hopefully reduce the chance of an |
| 2958 | ** "oops" where file X/Y/z gets committed as X/Y/Z due to a typo or |
| 2959 | ** case-sensitivity mismatch between the user/repo/filesystem, or |
| 2960 | ** some such. |
| 2961 | */ |
| 2962 | manifest_file_rewind(pCI->pParent); |
| 2963 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2964 | if(!zFile){ |
| 2965 | ci_err((pErr,"File [%s] not found in manifest [%S]. " |
| @@ -2971,46 +2975,48 @@ | |
| 2971 | if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){ |
| 2972 | ci_err((pErr,"File is unchanged. Not saving.")); |
| 2973 | } |
| 2974 | zFilePrevUuid = zFile->zUuid; |
| 2975 | } |
| 2976 | /* Create the manifest... */ |
| 2977 | if(create_manifest_one_file(&mf, pCI, pErr)==0){ |
| 2978 | return 0; |
| 2979 | } |
| 2980 | /* Add the file content to the db... */ |
| 2981 | frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash), |
| 2982 | 0, 0, isPrivate); |
| 2983 | if(zFilePrevUuid!=0){ |
| 2984 | /* Deltify against previous file version... */ |
| 2985 | int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q", |
| 2986 | zFilePrevUuid); |
| 2987 | assert(prevFRid>0); |
| 2988 | content_deltify(frid, &prevFRid, 1, 0); |
| 2989 | } |
| 2990 | /* Save, deltify, and crosslink the manifest... */ |
| 2991 | rid = content_put_ex(&mf, 0, 0, 0, isPrivate); |
| 2992 | content_deltify(rid, &pCI->pParent->rid, 1, 0); |
| 2993 | if(pRid!=0){ |
| 2994 | *pRid = rid; |
| 2995 | } |
| 2996 | if( ckin1Flags & CKIN1_DUMP_MANIFEST ){ |
| 2997 | fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf); |
| 2998 | } |
| 2999 | manifest_crosslink(rid, &mf, 0); |
| 3000 | blob_reset(&mf); |
| 3001 | db_end_transaction((CKIN1_DRY_RUN & ckin1Flags) ? 1 : 0); |
| 3002 | return 1; |
| 3003 | ci_error: |
| 3004 | assert(db_transaction_nesting_depth()>0); |
| 3005 | db_end_transaction(1); |
| 3006 | return 0; |
| 3007 | #undef ci_err |
| 3008 | } |
| 3009 | |
| 3010 | /* |
| 3011 | ** COMMAND: test-ci-one |
| 3012 | ** |
| 3013 | ** This is an on-going experiment, subject to change or removal at |
| 3014 | ** any time. |
| 3015 | ** |
| 3016 | ** Usage: %fossil ?OPTIONS? FILENAME |
| @@ -3027,55 +3033,55 @@ | |
| 3027 | ** --comment|-m COMMENT Required checkin comment. |
| 3028 | ** --comment-file|-M FILE Reads checkin comment from the given file. |
| 3029 | ** --revision|-r VERSION Commit from this version. Default is |
| 3030 | ** the checkout version (if available) or |
| 3031 | ** trunk (if used without a checkout). |
| 3032 | ** --wet-run Disables the default dry-run mode. |
| 3033 | ** --allow-fork Allows the commit to be made against a |
| 3034 | ** non-leaf parent. Note that no autosync |
| 3035 | ** is performed beforehand. |
| 3036 | ** --allow-merge-conflict Allows checkin of a file even if it appears |
| 3037 | ** to contain a fossil merge conflict marker. |
| 3038 | ** --user-override USER USER to use instead of the current default. |
| 3039 | ** --date-override DATETIME DATE to use instead of 'now'. |
| 3040 | ** --dump-manifest|-d Dumps the generated manifest to stdout. |
| 3041 | ** |
| 3042 | ** Example: |
| 3043 | ** |
| 3044 | ** %fossil test-ci-one -R REPO -m ... -r foo --as src/myfile.c myfile.c |
| 3045 | ** |
| 3046 | */ |
| 3047 | void test_ci_one_cmd(){ |
| 3048 | CheckinOneFileInfo cinf; /* checkin state */ |
| 3049 | int newRid = 0; /* RID of new version */ |
| 3050 | const char * zFilename; /* argv[2] */ |
| 3051 | const char * zComment; /* -m comment */ |
| 3052 | const char * zCommentFile; /* -M FILE */ |
| 3053 | const char * zAsFilename; /* --as filename */ |
| 3054 | const char * zRevision; /* --revision|-r [=trunk|checkout] */ |
| 3055 | const char * zUser; /* --user-override */ |
| 3056 | const char * zDate; /* --date-override */ |
| 3057 | int ckin1Flags = 0; /* flags for checkin_one_file(). */ |
| 3058 | |
| 3059 | CheckinOneFileInfo_init(&cinf); |
| 3060 | zComment = find_option("comment","m",1); |
| 3061 | zCommentFile = find_option("comment-file","M",1); |
| 3062 | zAsFilename = find_option("as",0,1); |
| 3063 | zRevision = find_option("revision","r",1); |
| 3064 | zUser = find_option("user-override",0,1); |
| 3065 | zDate = find_option("date-override",0,1); |
| 3066 | if(find_option("wet-run",0,0)==0){ |
| 3067 | ckin1Flags |= CKIN1_DRY_RUN; |
| 3068 | } |
| 3069 | if(find_option("allow-fork",0,0)!=0){ |
| 3070 | ckin1Flags |= CKIN1_ALLOW_FORK; |
| 3071 | } |
| 3072 | if(find_option("dump-manifest","d",0)!=0){ |
| 3073 | ckin1Flags |= CKIN1_DUMP_MANIFEST; |
| 3074 | } |
| 3075 | if(find_option("allow-merge-conflict",0,0)!=0){ |
| 3076 | ckin1Flags |= CKIN1_ALLOW_MERGE_MARKER; |
| 3077 | } |
| 3078 | |
| 3079 | db_find_and_open_repository(0, 0); |
| 3080 | verify_all_options(); |
| 3081 | user_select(); |
| @@ -3107,11 +3113,11 @@ | |
| 3107 | fossil_fatal("Non-empty checkin comment is required."); |
| 3108 | } |
| 3109 | } |
| 3110 | |
| 3111 | zFilename = g.argv[2]; |
| 3112 | cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename); |
| 3113 | cinf.zUser = mprintf("%s", zUser ? zUser : login_name()); |
| 3114 | if(zDate){ |
| 3115 | cinf.zDate = mprintf("%s", zDate); |
| 3116 | } |
| 3117 | if(zRevision==0 || zRevision[0]==0){ |
| @@ -3129,21 +3135,21 @@ | |
| 3129 | assert(cinf.pParent!=0); |
| 3130 | blob_read_from_file(&cinf.fileContent, zFilename, |
| 3131 | ExtFILE/*may want to reconsider*/); |
| 3132 | { |
| 3133 | Blob errMsg = empty_blob; |
| 3134 | const int rc = checkin_one_file(&cinf, &newRid, ckin1Flags, |
| 3135 | &errMsg); |
| 3136 | CheckinOneFileInfo_cleanup(&cinf); |
| 3137 | if(rc){ |
| 3138 | assert(blob_size(&errMsg)==0); |
| 3139 | }else{ |
| 3140 | assert(blob_size(&errMsg)); |
| 3141 | fossil_fatal("%b", &errMsg); |
| 3142 | } |
| 3143 | } |
| 3144 | if(!(ckin1Flags & CKIN1_DRY_RUN) && newRid!=0 && g.localOpen!=0){ |
| 3145 | fossil_warning("The checkout state is now out of sync " |
| 3146 | "with regards to this commit. It needs to be " |
| 3147 | "'update'd or 'close'd and re-'open'ed."); |
| 3148 | } |
| 3149 | } |
| 3150 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2676,13 +2676,13 @@ | |
| 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 | ** CheckinMiniInfo instance. |
| 2682 | */ |
| 2683 | struct CheckinMiniInfo { |
| 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 */ |
| @@ -2694,23 +2694,23 @@ | |
| 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 CheckinMiniInfo CheckinMiniInfo; |
| 2700 | /* |
| 2701 | ** Initializes p to a known-valid default state. |
| 2702 | */ |
| 2703 | static void CheckinMiniInfo_init( CheckinMiniInfo * p ){ |
| 2704 | memset(p, 0, sizeof(CheckinMiniInfo)); |
| 2705 | p->comment = p->fileContent = p->fileHash = empty_blob; |
| 2706 | } |
| 2707 | |
| 2708 | /* |
| 2709 | ** Frees all memory owned by p, but does not free p. |
| 2710 | */ |
| 2711 | static void CheckinMiniInfo_cleanup( CheckinMiniInfo * p ){ |
| 2712 | blob_reset(&p->comment); |
| 2713 | blob_reset(&p->fileContent); |
| 2714 | blob_reset(&p->fileHash); |
| 2715 | if(p->pParent){ |
| 2716 | manifest_destroy(p->pParent); |
| @@ -2718,40 +2718,40 @@ | |
| 2718 | fossil_free(p->zFilename); |
| 2719 | fossil_free(p->zMimetype); |
| 2720 | fossil_free(p->zParentUuid); |
| 2721 | fossil_free(p->zUser); |
| 2722 | fossil_free(p->zDate); |
| 2723 | CheckinMiniInfo_init(p); |
| 2724 | } |
| 2725 | |
| 2726 | /* |
| 2727 | ** Flags for checkin_mini() |
| 2728 | */ |
| 2729 | enum fossil_cimini_flags { |
| 2730 | /* |
| 2731 | ** Tells checkin_mini() to use dry-run mode. |
| 2732 | */ |
| 2733 | CIMINI_DRY_RUN = 1, |
| 2734 | /* |
| 2735 | ** Tells checkin_mini() to allow forking from a non-leaf commit. |
| 2736 | */ |
| 2737 | CIMINI_ALLOW_FORK = 1<<1, |
| 2738 | /* |
| 2739 | ** Tells checkin_mini() to dump its generated manifest to stdout. |
| 2740 | */ |
| 2741 | CIMINI_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 | CIMINI_ALLOW_MERGE_MARKER = 1<<3, |
| 2748 | |
| 2749 | /* |
| 2750 | ** NOT YET IMPLEMENTED. |
| 2751 | */ |
| 2752 | CIMINI_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. pCI is not *semantically* modified |
| @@ -2759,13 +2759,12 @@ | |
| 2759 | ** any given blob. |
| 2760 | ** |
| 2761 | ** Returns true on success. On error, returns 0 and, if pErr is not |
| 2762 | ** NULL, writes an error message there. |
| 2763 | */ |
| 2764 | static int create_manifest_mini( Blob * pOut, CheckinMiniInfo * pCI, |
| 2765 | Blob * pErr){ |
| 2766 | Blob zCard = empty_blob; /* Z-card checksum */ |
| 2767 | ManifestFile *zFile; /* One file entry from the pCI->pParent*/ |
| 2768 | int cmp = -99; /* filename comparison result */ |
| 2769 | int fperm = 0; /* file permissions */ |
| 2770 | const char *zPerm = 0; /* permissions for new F-card */ |
| @@ -2881,35 +2880,42 @@ | |
| 2880 | } |
| 2881 | |
| 2882 | /* |
| 2883 | ** EXPERIMENTAL! Subject to change or removal at any time. |
| 2884 | ** |
| 2885 | ** A so-called "single-file/mini/web checkin" is a slimmed-down form |
| 2886 | ** of the checkin command which accepts only a single file and is |
| 2887 | ** intended to accept edits to a file via the web interface or from |
| 2888 | ** the CLI from outside of a checkout. |
| 2889 | ** |
| 2890 | ** Being fully non-interactive is a requirement for this function, |
| 2891 | ** thus it cannot perform autosync or similar activities. |
| 2892 | ** |
| 2893 | ** This routine uses the state from the given fully-populated pCI |
| 2894 | ** argument to add pCI->fileContent to the database, and create and |
| 2895 | ** save a manifest for that change. Ownership of pCI and its contents |
| 2896 | ** are unchanged. |
| 2897 | ** |
| 2898 | ** If pCI->fileHash is empty, this routine populates it with the |
| 2899 | ** repository's preferred hash algorithm. pCI is not otherwise |
| 2900 | ** modified, nor is its ownership modified. |
| 2901 | ** |
| 2902 | ** This function validates several of the inputs and fails if any |
| 2903 | ** validation fails. |
| 2904 | ** |
| 2905 | ** On error, returns false (0) and, if pErr is not NULL, writes a |
| 2906 | ** diagnostic message there. |
| 2907 | ** |
| 2908 | ** Returns true on success. If pRid is not NULL, the RID of the |
| 2909 | ** resulting manifest is written to *pRid. |
| 2910 | ** |
| 2911 | ** ciminiFlags is a bitmask of optional flags from fossil_cimini_flags |
| 2912 | ** enum. See that enum for the docs for each flag. Pass 0 for no |
| 2913 | ** flags. |
| 2914 | */ |
| 2915 | static int checkin_mini( CheckinMiniInfo * pCI, int *pRid, |
| 2916 | int ciminiFlags, Blob * pErr ){ |
| 2917 | Blob mf = empty_blob; /* output manifest */ |
| 2918 | int rid = 0, frid = 0; /* various RIDs */ |
| 2919 | const int isPrivate = content_is_private(pCI->pParent->rid); |
| 2920 | ManifestFile * zFile; /* file from pCI->pParent */; |
| 2921 | const char * zFilePrevUuid = 0; /* UUID of previous version of |
| @@ -2927,23 +2933,19 @@ | |
| 2933 | ** no reason we can't do that via the generated manifest, |
| 2934 | ** but the commit command does not offer that option, so |
| 2935 | ** we won't, either. |
| 2936 | */ |
| 2937 | } |
| 2938 | if(!(CIMINI_ALLOW_FORK & ciminiFlags) |
| 2939 | && !is_a_leaf(pCI->pParent->rid)){ |
| 2940 | ci_err((pErr,"Parent [%S] is not a leaf and forking is disabled.", |
| 2941 | pCI->zParentUuid)); |
| 2942 | } |
| 2943 | if(!(CIMINI_ALLOW_MERGE_MARKER & ciminiFlags) |
| 2944 | && contains_merge_marker(&pCI->fileContent)){ |
| 2945 | ci_err((pErr,"Content appears to contain a merge conflict marker.")); |
| 2946 | } |
| 2947 | /* Potential TODOs include: |
| 2948 | ** |
| 2949 | ** - Commit allows an empty checkin only with a flag, but we |
| 2950 | ** currently disallow it entirely. Conform with commit? |
| 2951 | ** |
| @@ -2955,11 +2957,13 @@ | |
| 2957 | ** Confirm that pCI->zFilename can be found in pCI->pParent. If |
| 2958 | ** not, fail. This is admittedly an artificial limitation, not |
| 2959 | ** strictly necessary. We do it to hopefully reduce the chance of an |
| 2960 | ** "oops" where file X/Y/z gets committed as X/Y/Z due to a typo or |
| 2961 | ** case-sensitivity mismatch between the user/repo/filesystem, or |
| 2962 | ** some such. That said, the remainder of this function is written |
| 2963 | ** as if this check did not exist, so enabling it "should" just be a |
| 2964 | ** matter of removing this check or guarding it with a flag. |
| 2965 | */ |
| 2966 | manifest_file_rewind(pCI->pParent); |
| 2967 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2968 | if(!zFile){ |
| 2969 | ci_err((pErr,"File [%s] not found in manifest [%S]. " |
| @@ -2971,46 +2975,48 @@ | |
| 2975 | if(0==fossil_strcmp(zFile->zUuid, blob_str(&pCI->fileHash))){ |
| 2976 | ci_err((pErr,"File is unchanged. Not saving.")); |
| 2977 | } |
| 2978 | zFilePrevUuid = zFile->zUuid; |
| 2979 | } |
| 2980 | if(blob_size(&pCI->fileHash)==0){ |
| 2981 | hname_hash(&pCI->fileContent, 0, &pCI->fileHash); |
| 2982 | assert(blob_size(&pCI->fileHash)>0); |
| 2983 | } |
| 2984 | /* Create the manifest... */ |
| 2985 | if(create_manifest_mini(&mf, pCI, pErr)==0){ |
| 2986 | return 0; |
| 2987 | } |
| 2988 | /* Save and deltify the file content... */ |
| 2989 | frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash), |
| 2990 | 0, 0, isPrivate); |
| 2991 | if(zFilePrevUuid!=0){ |
| 2992 | int prevFRid = fast_uuid_to_rid(zFilePrevUuid); |
| 2993 | assert(prevFRid>0); |
| 2994 | content_deltify(frid, &prevFRid, 1, 0); |
| 2995 | } |
| 2996 | /* Save, deltify, and crosslink the manifest... */ |
| 2997 | rid = content_put_ex(&mf, 0, 0, 0, isPrivate); |
| 2998 | content_deltify(rid, &pCI->pParent->rid, 1, 0); |
| 2999 | if(pRid!=0){ |
| 3000 | *pRid = rid; |
| 3001 | } |
| 3002 | if(ciminiFlags & CIMINI_DUMP_MANIFEST){ |
| 3003 | fossil_print("Manifest: %z\n%b", rid_to_uuid(rid), &mf); |
| 3004 | } |
| 3005 | manifest_crosslink(rid, &mf, 0); |
| 3006 | blob_reset(&mf); |
| 3007 | db_end_transaction((CIMINI_DRY_RUN & ciminiFlags) ? 1 : 0); |
| 3008 | return 1; |
| 3009 | ci_error: |
| 3010 | assert(db_transaction_nesting_depth()>0); |
| 3011 | db_end_transaction(1); |
| 3012 | return 0; |
| 3013 | #undef ci_err |
| 3014 | } |
| 3015 | |
| 3016 | /* |
| 3017 | ** COMMAND: test-ci-mini |
| 3018 | ** |
| 3019 | ** This is an on-going experiment, subject to change or removal at |
| 3020 | ** any time. |
| 3021 | ** |
| 3022 | ** Usage: %fossil ?OPTIONS? FILENAME |
| @@ -3027,55 +3033,55 @@ | |
| 3033 | ** --comment|-m COMMENT Required checkin comment. |
| 3034 | ** --comment-file|-M FILE Reads checkin comment from the given file. |
| 3035 | ** --revision|-r VERSION Commit from this version. Default is |
| 3036 | ** the checkout version (if available) or |
| 3037 | ** trunk (if used without a checkout). |
| 3038 | ** --allow-fork Allows the commit to be made against a |
| 3039 | ** non-leaf parent. Note that no autosync |
| 3040 | ** is performed beforehand. |
| 3041 | ** --allow-merge-conflict Allows checkin of a file even if it appears |
| 3042 | ** to contain a fossil merge conflict marker. |
| 3043 | ** --user-override USER USER to use instead of the current default. |
| 3044 | ** --date-override DATETIME DATE to use instead of 'now'. |
| 3045 | ** --dump-manifest|-d Dumps the generated manifest to stdout. |
| 3046 | ** --wet-run Disables the default dry-run mode. |
| 3047 | ** |
| 3048 | ** Example: |
| 3049 | ** |
| 3050 | ** %fossil test-ci-mini -R REPO -m ... -r foo --as src/myfile.c myfile.c |
| 3051 | ** |
| 3052 | */ |
| 3053 | void test_ci_mini_cmd(){ |
| 3054 | CheckinMiniInfo cinf; /* checkin state */ |
| 3055 | int newRid = 0; /* RID of new version */ |
| 3056 | const char * zFilename; /* argv[2] */ |
| 3057 | const char * zComment; /* -m comment */ |
| 3058 | const char * zCommentFile; /* -M FILE */ |
| 3059 | const char * zAsFilename; /* --as filename */ |
| 3060 | const char * zRevision; /* --revision|-r [=trunk|checkout] */ |
| 3061 | const char * zUser; /* --user-override */ |
| 3062 | const char * zDate; /* --date-override */ |
| 3063 | int ciminiFlags = 0; /* flags for checkin_mini(). */ |
| 3064 | |
| 3065 | CheckinMiniInfo_init(&cinf); |
| 3066 | zComment = find_option("comment","m",1); |
| 3067 | zCommentFile = find_option("comment-file","M",1); |
| 3068 | zAsFilename = find_option("as",0,1); |
| 3069 | zRevision = find_option("revision","r",1); |
| 3070 | zUser = find_option("user-override",0,1); |
| 3071 | zDate = find_option("date-override",0,1); |
| 3072 | if(find_option("wet-run",0,0)==0){ |
| 3073 | ciminiFlags |= CIMINI_DRY_RUN; |
| 3074 | } |
| 3075 | if(find_option("allow-fork",0,0)!=0){ |
| 3076 | ciminiFlags |= CIMINI_ALLOW_FORK; |
| 3077 | } |
| 3078 | if(find_option("dump-manifest","d",0)!=0){ |
| 3079 | ciminiFlags |= CIMINI_DUMP_MANIFEST; |
| 3080 | } |
| 3081 | if(find_option("allow-merge-conflict",0,0)!=0){ |
| 3082 | ciminiFlags |= CIMINI_ALLOW_MERGE_MARKER; |
| 3083 | } |
| 3084 | |
| 3085 | db_find_and_open_repository(0, 0); |
| 3086 | verify_all_options(); |
| 3087 | user_select(); |
| @@ -3107,11 +3113,11 @@ | |
| 3113 | fossil_fatal("Non-empty checkin comment is required."); |
| 3114 | } |
| 3115 | } |
| 3116 | |
| 3117 | zFilename = g.argv[2]; |
| 3118 | cinf.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename); |
| 3119 | cinf.zUser = mprintf("%s", zUser ? zUser : login_name()); |
| 3120 | if(zDate){ |
| 3121 | cinf.zDate = mprintf("%s", zDate); |
| 3122 | } |
| 3123 | if(zRevision==0 || zRevision[0]==0){ |
| @@ -3129,21 +3135,21 @@ | |
| 3135 | assert(cinf.pParent!=0); |
| 3136 | blob_read_from_file(&cinf.fileContent, zFilename, |
| 3137 | ExtFILE/*may want to reconsider*/); |
| 3138 | { |
| 3139 | Blob errMsg = empty_blob; |
| 3140 | const int rc = checkin_mini(&cinf, &newRid, ciminiFlags, |
| 3141 | &errMsg); |
| 3142 | CheckinMiniInfo_cleanup(&cinf); |
| 3143 | if(rc){ |
| 3144 | assert(blob_size(&errMsg)==0); |
| 3145 | }else{ |
| 3146 | assert(blob_size(&errMsg)); |
| 3147 | fossil_fatal("%b", &errMsg); |
| 3148 | } |
| 3149 | } |
| 3150 | if(!(ciminiFlags & CIMINI_DRY_RUN) && newRid!=0 && g.localOpen!=0){ |
| 3151 | fossil_warning("The checkout state is now out of sync " |
| 3152 | "with regards to this commit. It needs to be " |
| 3153 | "'update'd or 'close'd and re-'open'ed."); |
| 3154 | } |
| 3155 | } |
| 3156 |