Fossil SCM
Improvements to verify-comments: (1) the verify-comments setting is now text that can take four different values for different levels of verification. (2) Recent changes work better with -M and -m. (3) Improved user interaction.
Commit
798b232ce729f9ce1b7e9f27f278f32167d7a8d24e770d0dbd6d65edfea5af1a
Parent
777d962ce5f037c…
1 file changed
+152
-91
+152
-91
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -2283,97 +2283,139 @@ | ||
| 2283 | 2283 | char **pB = (char**)b; |
| 2284 | 2284 | return fossil_strcmp(pA[0], pB[0]); |
| 2285 | 2285 | } |
| 2286 | 2286 | |
| 2287 | 2287 | /* |
| 2288 | -** SETTING: verify-comments boolean default=on show-only-if-changed | |
| 2288 | +** SETTING: verify-comments width=8 default=on show-only-if-changed | |
| 2289 | +** | |
| 2290 | +** This setting determines much sanity checking, if any, the | |
| 2291 | +** "fossil commit" and "fossil amend" commands do against check-in | |
| 2292 | +** comments. Recognized values: | |
| 2293 | +** | |
| 2294 | +** on (Default) Check for bad syntax in check-in comments | |
| 2295 | +** and offer the user a chance to continue editing for | |
| 2296 | +** interactive sessions, or simply abort the commit if | |
| 2297 | +** commit was entered using using -m or -M | |
| 2298 | +** | |
| 2299 | +** off Do not syntax checking of any kind | |
| 2300 | +** | |
| 2301 | +** links Similar to "on", except only check for bad hyperlinks | |
| 2289 | 2302 | ** |
| 2290 | -** If enabled (the default) then the "fossil commit" command does sanity | |
| 2291 | -** checking on the checkin comment. The sanity checks can be overridden | |
| 2292 | -** on a case by case basis using the --allow-suspect-comment option to | |
| 2293 | -** the "fossil commit" command. If disabled, this setting makes every | |
| 2294 | -** "fossil commit" behave as if the --allow-suspect-comment option were | |
| 2295 | -** provided. | |
| 2303 | +** preview Do all the same checks as "on" but also preview the | |
| 2304 | +** checkin comment to the user during interactive sessions | |
| 2305 | +** and provide an opportunity to accept or re-edit | |
| 2296 | 2306 | */ |
| 2297 | 2307 | |
| 2308 | +#if INTERFACE | |
| 2309 | +#define COMCK_LINKS 0x01 /* Check for back hyperlinks */ | |
| 2310 | +#define COMCK_MARKUP 0x02 /* Check markup */ | |
| 2311 | +#define COMCK_PREVIEW 0x04 /* Always preview even if no issues found */ | |
| 2312 | +#define COMCK_NOPREVIEW 0x08 /* Never preview, even for other errors */ | |
| 2313 | +#endif /* INTERFACE */ | |
| 2314 | + | |
| 2298 | 2315 | /* |
| 2299 | 2316 | ** Check for possible formatting errors in the comment string pComment. |
| 2300 | -** If found, write a description of the problem(s) into pSus and return | |
| 2301 | -** true. If everything looks ok, return false. | |
| 2317 | +** | |
| 2318 | +** If concerns are found, write a description of the problem(s) to | |
| 2319 | +** stdout return non-zero. The return value is some combination of | |
| 2320 | +** of the COMCK_* flags depending on what went wrong. | |
| 2321 | +** | |
| 2322 | +** If no issues are seen, do not output anything and return zero. | |
| 2302 | 2323 | */ |
| 2303 | -static int suspicious_comment(Blob *pComment, Blob *pSus){ | |
| 2324 | +static int suspicious_comment(Blob *pComment, int mFlags){ | |
| 2304 | 2325 | char *zStart = blob_str(pComment); |
| 2305 | 2326 | char *z; |
| 2306 | 2327 | char *zEnd, *zEnd2; |
| 2307 | 2328 | char *zSep; |
| 2308 | 2329 | char cSave1; |
| 2309 | 2330 | int nIssue = 0; |
| 2331 | + int rc = mFlags & COMCK_PREVIEW; | |
| 2332 | + Blob out; | |
| 2310 | 2333 | static const char zSpecial[] = "\\&<*_`["; |
| 2311 | 2334 | |
| 2312 | - if( !db_get_boolean("verify-comments",1) ) return 0; | |
| 2335 | + if( mFlags==0 ) return 0; | |
| 2313 | 2336 | z = zStart; |
| 2314 | - blob_init(pSus, 0, 0); | |
| 2315 | - while( (z = strchr(z,'['))!=0 ){ | |
| 2316 | - zEnd = strchr(z,']'); | |
| 2317 | - if( zEnd==0 ){ | |
| 2318 | - blob_appendf(pSus,"\n (%d) ", ++nIssue); | |
| 2319 | - blob_appendf(pSus, "Unterminated hyperlink \"%.12s...\"", z); | |
| 2320 | - break; | |
| 2321 | - } | |
| 2322 | - if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){ | |
| 2323 | - blob_appendf(pSus,"\n (%d) ", ++nIssue); | |
| 2324 | - blob_appendf(pSus, "Markdown hyperlink syntax: %.*s", | |
| 2325 | - (int)(zEnd2+1-z), z); | |
| 2326 | - z = zEnd2; | |
| 2327 | - continue; | |
| 2328 | - } | |
| 2329 | - zSep = strchr(z+1,'|'); | |
| 2330 | - if( zSep==0 || zSep>zEnd ) zSep = zEnd; | |
| 2331 | - while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--; | |
| 2332 | - cSave1 = zSep[0]; | |
| 2333 | - zSep[0] = 0; | |
| 2334 | - if( !wiki_valid_link_target(z+1) ){ | |
| 2335 | - blob_appendf(pSus,"\n (%d) ", ++nIssue); | |
| 2336 | - blob_appendf(pSus, "Broken hyperlink: [%s]", z+1); | |
| 2337 | - } | |
| 2338 | - zSep[0] = cSave1; | |
| 2339 | - z = zEnd; | |
| 2340 | - } | |
| 2341 | - if( nIssue ){ | |
| 2342 | - Blob tmp = *pSus; | |
| 2343 | - blob_init(pSus, 0, 0); | |
| 2344 | - blob_appendf(pSus, | |
| 2345 | - "Possible comment formatting error%s:%b\n", | |
| 2346 | - nIssue>1 ? "s" : "", &tmp); | |
| 2347 | - blob_reset(&tmp); | |
| 2348 | - return 1; | |
| 2349 | - }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){ | |
| 2350 | - Blob in, html, txt; | |
| 2337 | + blob_init(&out, 0, 0); | |
| 2338 | + if( mFlags & COMCK_LINKS ){ | |
| 2339 | + while( (z = strchr(z,'['))!=0 ){ | |
| 2340 | + zEnd = strchr(z,']'); | |
| 2341 | + if( zEnd==0 ){ | |
| 2342 | + blob_appendf(&out,"\n (%d) ", ++nIssue); | |
| 2343 | + blob_appendf(&out, "Unterminated hyperlink \"%.12s...\"", z); | |
| 2344 | + break; | |
| 2345 | + } | |
| 2346 | + if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){ | |
| 2347 | + blob_appendf(&out,"\n (%d) ", ++nIssue); | |
| 2348 | + blob_appendf(&out, "Markdown hyperlink syntax: %.*s", | |
| 2349 | + (int)(zEnd2+1-z), z); | |
| 2350 | + z = zEnd2; | |
| 2351 | + continue; | |
| 2352 | + } | |
| 2353 | + zSep = strchr(z+1,'|'); | |
| 2354 | + if( zSep==0 || zSep>zEnd ) zSep = zEnd; | |
| 2355 | + while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--; | |
| 2356 | + cSave1 = zSep[0]; | |
| 2357 | + zSep[0] = 0; | |
| 2358 | + if( !wiki_valid_link_target(z+1) ){ | |
| 2359 | + blob_appendf(&out,"\n (%d) ", ++nIssue); | |
| 2360 | + blob_appendf(&out, "Broken hyperlink: [%s]", z+1); | |
| 2361 | + } | |
| 2362 | + zSep[0] = cSave1; | |
| 2363 | + z = zEnd; | |
| 2364 | + } | |
| 2365 | + } | |
| 2366 | + | |
| 2367 | + if( nIssue>0 | |
| 2368 | + || (mFlags & COMCK_PREVIEW)!=0 | |
| 2369 | + || ((mFlags & COMCK_MARKUP)!=0 && strcspn(zStart,zSpecial)<strlen(zStart)) | |
| 2370 | + ){ | |
| 2351 | 2371 | char zGot[16]; |
| 2352 | 2372 | int nGot = 0; |
| 2353 | 2373 | int i; |
| 2354 | - for(i=0; zSpecial[i]; i++){ | |
| 2355 | - if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i]; | |
| 2374 | + if( (mFlags & COMCK_MARKUP)!=0 ){ | |
| 2375 | + for(i=0; zSpecial[i]; i++){ | |
| 2376 | + if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i]; | |
| 2377 | + } | |
| 2356 | 2378 | } |
| 2357 | 2379 | zGot[nGot] = 0; |
| 2358 | - blob_init(&in, blob_str(pComment), -1); | |
| 2359 | - blob_init(&html, 0, 0); | |
| 2360 | - wiki_convert(&in, &html, WIKI_INLINE); | |
| 2361 | - blob_reset(&in); | |
| 2362 | - blob_init(&txt, 0, 0); | |
| 2363 | - html_to_plaintext(blob_str(&html), &txt); | |
| 2364 | - blob_reset(&html); | |
| 2365 | - fossil_print("The comment uses special character%s \"%s\". " | |
| 2366 | - "Does it render as you expect?\n\n ", | |
| 2367 | - nGot>1 ? "s" : "", zGot); | |
| 2368 | - comment_print(blob_str(&txt), 0, 3, -1, get_comment_format()); | |
| 2369 | - blob_init(pSus, 0, 0); | |
| 2370 | - blob_appendf(pSus, "\n"); | |
| 2371 | - return 1; | |
| 2372 | - }else{ | |
| 2373 | - return 0; | |
| 2374 | - } | |
| 2380 | + if( nGot>0 ) rc |= COMCK_MARKUP; | |
| 2381 | + if( nGot>0 && nIssue>0 ){ | |
| 2382 | + blob_appendf(&out,"\n (%d) Comment uses special character%s \"%s\"", | |
| 2383 | + ++nIssue, (nGot>1 ? "s" : ""), zGot); | |
| 2384 | + nGot = 0; | |
| 2385 | + } | |
| 2386 | + if( nIssue ){ | |
| 2387 | + rc |= COMCK_LINKS; | |
| 2388 | + fossil_print( | |
| 2389 | + "Possible comment formatting error%s:%b\n", | |
| 2390 | + nIssue>1 ? "s" : "", &out | |
| 2391 | + ); | |
| 2392 | + } | |
| 2393 | + if( (mFlags & COMCK_NOPREVIEW)==0 ){ | |
| 2394 | + Blob in, html, txt; | |
| 2395 | + blob_init(&in, blob_str(pComment), -1); | |
| 2396 | + blob_init(&html, 0, 0); | |
| 2397 | + blob_init(&txt, 0, 0); | |
| 2398 | + wiki_convert(&in, &html, WIKI_INLINE); | |
| 2399 | + html_to_plaintext(blob_str(&html), &txt); | |
| 2400 | + if( nGot>0 ){ | |
| 2401 | + fossil_print( | |
| 2402 | + "The comment uses special character%s \"%s\". " | |
| 2403 | + "Does it render as you expect?\n\n ", | |
| 2404 | + (nGot>1 ? "s" : ""), zGot | |
| 2405 | + ); | |
| 2406 | + }else{ | |
| 2407 | + fossil_print("Preview of the check-in comment:\n\n "); | |
| 2408 | + } | |
| 2409 | + comment_print(blob_str(&txt), 0, 3, -1, get_comment_format()); | |
| 2410 | + blob_reset(&in); | |
| 2411 | + blob_reset(&html); | |
| 2412 | + blob_reset(&txt); | |
| 2413 | + } | |
| 2414 | + } | |
| 2415 | + blob_reset(&out); | |
| 2416 | + return rc; | |
| 2375 | 2417 | } |
| 2376 | 2418 | |
| 2377 | 2419 | /* |
| 2378 | 2420 | ** COMMAND: ci# |
| 2379 | 2421 | ** COMMAND: commit |
| @@ -2389,11 +2431,11 @@ | ||
| 2389 | 2431 | ** You will be prompted to enter a check-in comment unless the comment |
| 2390 | 2432 | ** has been specified on the command-line using "-m" or "-M". The |
| 2391 | 2433 | ** text editor used is determined by the "editor" setting, or by the |
| 2392 | 2434 | ** "VISUAL" or "EDITOR" environment variables. Commit message text is |
| 2393 | 2435 | ** interpreted as fossil-wiki format. Potentially misformatted check-in |
| 2394 | -** comment text is detected and reported unless the --allow-suspect-comment | |
| 2436 | +** comment text is detected and reported unless the --no-verify-comment | |
| 2395 | 2437 | ** option is used. |
| 2396 | 2438 | ** |
| 2397 | 2439 | ** The --branch option followed by a branch name causes the new |
| 2398 | 2440 | ** check-in to be placed in a newly-created branch with name specified. |
| 2399 | 2441 | ** |
| @@ -2421,11 +2463,10 @@ | ||
| 2421 | 2463 | ** Options: |
| 2422 | 2464 | ** --allow-conflict Allow unresolved merge conflicts |
| 2423 | 2465 | ** --allow-empty Allow a commit with no changes |
| 2424 | 2466 | ** --allow-fork Allow the commit to fork |
| 2425 | 2467 | ** --allow-older Allow a commit older than its ancestor |
| 2426 | -** --allow-suspect-comment Allow check-in comments that might be misformed | |
| 2427 | 2468 | ** --baseline Use a baseline manifest in the commit process |
| 2428 | 2469 | ** --branch NEW-BRANCH-NAME Check in to this new branch |
| 2429 | 2470 | ** --close Close the branch being committed |
| 2430 | 2471 | ** --date-override DATETIME Make DATETIME the time of the check-in. |
| 2431 | 2472 | ** Useful when importing historical check-ins |
| @@ -2449,10 +2490,11 @@ | ||
| 2449 | 2490 | ** --no-prompt This option disables prompting the user for |
| 2450 | 2491 | ** input and assumes an answer of 'No' for every |
| 2451 | 2492 | ** question. |
| 2452 | 2493 | ** --no-warnings Omit all warnings about file contents |
| 2453 | 2494 | ** --no-verify Do not run before-commit hooks |
| 2495 | +** --no-verify-comment Do not validate the check-in comment | |
| 2454 | 2496 | ** --nosign Do not attempt to sign this commit with gpg |
| 2455 | 2497 | ** --nosync Do not auto-sync prior to committing |
| 2456 | 2498 | ** --override-lock Allow a check-in even though parent is locked |
| 2457 | 2499 | ** --private Never sync the resulting check-in and make |
| 2458 | 2500 | ** all descendants private too. |
| @@ -2488,11 +2530,11 @@ | ||
| 2488 | 2530 | int allowConflict = 0; /* Allow unresolve merge conflicts */ |
| 2489 | 2531 | int allowEmpty = 0; /* Allow a commit with no changes */ |
| 2490 | 2532 | int onlyIfChanges = 0; /* No-op if there are no changes */ |
| 2491 | 2533 | int allowFork = 0; /* Allow the commit to fork */ |
| 2492 | 2534 | int allowOlder = 0; /* Allow a commit older than its ancestor */ |
| 2493 | - int allowSusCom = 0; /* Allow suspicious check-in comments */ | |
| 2535 | + int noVerifyCom = 0; /* Allow suspicious check-in comments */ | |
| 2494 | 2536 | char *zManifestFile; /* Name of the manifest file */ |
| 2495 | 2537 | int useCksum; /* True if checksums should be computed and verified */ |
| 2496 | 2538 | int outputManifest; /* True to output "manifest" and "manifest.uuid" */ |
| 2497 | 2539 | int dryRunFlag; /* True for a test run. Debugging only */ |
| 2498 | 2540 | CheckinInfo sCiInfo; /* Information about this check-in */ |
| @@ -2514,10 +2556,11 @@ | ||
| 2514 | 2556 | int bRecheck = 0; /* Repeat fork and closed-branch checks*/ |
| 2515 | 2557 | int bIgnoreSkew = 0; /* --ignore-clock-skew flag */ |
| 2516 | 2558 | int mxSize; |
| 2517 | 2559 | char *zCurBranch = 0; /* The current branch name of checkout */ |
| 2518 | 2560 | char *zNewBranch = 0; /* The branch name after update */ |
| 2561 | + int ckComFlgs; /* Flags passed to suspicious_comment() */ | |
| 2519 | 2562 | |
| 2520 | 2563 | memset(&sCiInfo, 0, sizeof(sCiInfo)); |
| 2521 | 2564 | url_proxy_options(); |
| 2522 | 2565 | /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */ |
| 2523 | 2566 | useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0; |
| @@ -2544,11 +2587,11 @@ | ||
| 2544 | 2587 | } |
| 2545 | 2588 | zComment = find_option("comment","m",1); |
| 2546 | 2589 | forceFlag = find_option("force", "f", 0)!=0; |
| 2547 | 2590 | allowConflict = find_option("allow-conflict",0,0)!=0; |
| 2548 | 2591 | allowEmpty = find_option("allow-empty",0,0)!=0; |
| 2549 | - allowSusCom = find_option("allow-suspect-comment",0,0)!=0; | |
| 2592 | + noVerifyCom = find_option("no-verify-comment",0,0)!=0; | |
| 2550 | 2593 | onlyIfChanges = find_option("if-changes",0,0)!=0; |
| 2551 | 2594 | allowFork = find_option("allow-fork",0,0)!=0; |
| 2552 | 2595 | if( find_option("override-lock",0,0)!=0 ) allowFork = 1; |
| 2553 | 2596 | allowOlder = find_option("allow-older",0,0)!=0; |
| 2554 | 2597 | noPrompt = find_option("no-prompt", 0, 0)!=0; |
| @@ -2585,13 +2628,13 @@ | ||
| 2585 | 2628 | mxSize = db_large_file_size(); |
| 2586 | 2629 | if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0; |
| 2587 | 2630 | verify_all_options(); |
| 2588 | 2631 | |
| 2589 | 2632 | /* The --no-warnings flag and the --force flag each imply |
| 2590 | - ** the --allow-suspect-comment flag */ | |
| 2633 | + ** the --no-verify-comment flag */ | |
| 2591 | 2634 | if( noWarningFlag || forceFlag ){ |
| 2592 | - allowSusCom = 1; | |
| 2635 | + noVerifyCom = 1; | |
| 2593 | 2636 | } |
| 2594 | 2637 | |
| 2595 | 2638 | /* Get the ID of the parent manifest artifact */ |
| 2596 | 2639 | vid = db_lget_int("checkout", 0); |
| 2597 | 2640 | if( vid==0 ){ |
| @@ -2876,52 +2919,70 @@ | ||
| 2876 | 2919 | fossil_free(zNewBranch); |
| 2877 | 2920 | |
| 2878 | 2921 | /* Always exit the loop on the second pass */ |
| 2879 | 2922 | if( bRecheck ) break; |
| 2880 | 2923 | |
| 2924 | + | |
| 2925 | + /* Figure out how much comment verification is requested */ | |
| 2926 | + if( noVerifyCom ){ | |
| 2927 | + ckComFlgs = 0; | |
| 2928 | + }else{ | |
| 2929 | + const char *zVerComs = db_get("verify-comments","on"); | |
| 2930 | + if( is_false(zVerComs) ){ | |
| 2931 | + ckComFlgs = 0; | |
| 2932 | + }else if( strcmp(zVerComs,"preview")==0 ){ | |
| 2933 | + ckComFlgs = COMCK_PREVIEW | COMCK_LINKS | COMCK_MARKUP; | |
| 2934 | + }else if( strcmp(zVerComs,"links")==0 ){ | |
| 2935 | + ckComFlgs = COMCK_LINKS; | |
| 2936 | + }else{ | |
| 2937 | + ckComFlgs = COMCK_LINKS | COMCK_MARKUP; | |
| 2938 | + } | |
| 2939 | + } | |
| 2881 | 2940 | |
| 2882 | 2941 | /* Get the check-in comment. This might involve prompting the |
| 2883 | 2942 | ** user for the check-in comment, in which case we should resync |
| 2884 | 2943 | ** to renew the check-in lock and repeat the checks for conflicts. |
| 2885 | 2944 | */ |
| 2886 | 2945 | if( zComment ){ |
| 2887 | - Blob sus; | |
| 2888 | 2946 | blob_zero(&comment); |
| 2889 | 2947 | blob_append(&comment, zComment, -1); |
| 2890 | - if( !allowSusCom && suspicious_comment(&comment, &sus) ){ | |
| 2891 | - fossil_fatal("%bCommit aborted; " | |
| 2892 | - "use --allow-suspect-comment to override", &sus); | |
| 2948 | + ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP); | |
| 2949 | + ckComFlgs |= COMCK_NOPREVIEW; | |
| 2950 | + if( suspicious_comment(&comment, ckComFlgs) ){ | |
| 2951 | + fossil_fatal("Commit aborted; " | |
| 2952 | + "use --no-verify-comment to override"); | |
| 2893 | 2953 | } |
| 2894 | 2954 | }else if( zComFile ){ |
| 2895 | - Blob sus; | |
| 2896 | 2955 | blob_zero(&comment); |
| 2897 | 2956 | blob_read_from_file(&comment, zComFile, ExtFILE); |
| 2898 | 2957 | blob_to_utf8_no_bom(&comment, 1); |
| 2899 | - if( !allowSusCom && suspicious_comment(&comment, &sus) ){ | |
| 2900 | - fossil_fatal("%bCommit aborted; " | |
| 2901 | - "use --allow-suspect-comment to override", &sus); | |
| 2958 | + ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP); | |
| 2959 | + ckComFlgs |= COMCK_NOPREVIEW; | |
| 2960 | + if( suspicious_comment(&comment, ckComFlgs) ){ | |
| 2961 | + fossil_fatal("Commit aborted; " | |
| 2962 | + "use --no-verify-comment to override"); | |
| 2902 | 2963 | } |
| 2903 | 2964 | }else if( !noPrompt ){ |
| 2904 | 2965 | while( 1/*exit-by-break*/ ){ |
| 2966 | + int rc; | |
| 2905 | 2967 | char *zInit; |
| 2906 | - Blob sus; | |
| 2907 | - | |
| 2908 | 2968 | zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'"); |
| 2909 | 2969 | prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag); |
| 2910 | 2970 | db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment); |
| 2911 | - if( !allowSusCom && suspicious_comment(&comment,&sus) ){ | |
| 2912 | - blob_appendf(&sus, "Continue (y/n/E=edit)? "); | |
| 2913 | - prompt_user(blob_str(&sus), &ans); | |
| 2971 | + if( (rc = suspicious_comment(&comment, ckComFlgs))!=0 ){ | |
| 2972 | + if( rc==COMCK_PREVIEW ){ | |
| 2973 | + prompt_user("\nContinue (Y/n/e=edit)? ", &ans); | |
| 2974 | + }else{ | |
| 2975 | + prompt_user("\nContinue (y/n/E=edit)? ", &ans); | |
| 2976 | + } | |
| 2914 | 2977 | cReply = blob_str(&ans)[0]; |
| 2978 | + cReply = fossil_tolower(cReply); | |
| 2915 | 2979 | blob_reset(&ans); |
| 2916 | - blob_reset(&sus); | |
| 2917 | - if( cReply=='n' || cReply=='N' ){ | |
| 2980 | + if( cReply=='n' ){ | |
| 2918 | 2981 | fossil_fatal("Commit aborted."); |
| 2919 | 2982 | } |
| 2920 | - if( cReply!='y' && cReply!='Y' ){ | |
| 2921 | - /* "Edit" is the default in case the user enters anything that | |
| 2922 | - ** does not start with Y or N - including just hitting return. */ | |
| 2983 | + if( cReply=='e' || (cReply!='y' && rc!=COMCK_PREVIEW) ){ | |
| 2923 | 2984 | fossil_free(zInit); |
| 2924 | 2985 | continue; |
| 2925 | 2986 | } |
| 2926 | 2987 | } |
| 2927 | 2988 | if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){ |
| 2928 | 2989 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2283,97 +2283,139 @@ | |
| 2283 | char **pB = (char**)b; |
| 2284 | return fossil_strcmp(pA[0], pB[0]); |
| 2285 | } |
| 2286 | |
| 2287 | /* |
| 2288 | ** SETTING: verify-comments boolean default=on show-only-if-changed |
| 2289 | ** |
| 2290 | ** If enabled (the default) then the "fossil commit" command does sanity |
| 2291 | ** checking on the checkin comment. The sanity checks can be overridden |
| 2292 | ** on a case by case basis using the --allow-suspect-comment option to |
| 2293 | ** the "fossil commit" command. If disabled, this setting makes every |
| 2294 | ** "fossil commit" behave as if the --allow-suspect-comment option were |
| 2295 | ** provided. |
| 2296 | */ |
| 2297 | |
| 2298 | /* |
| 2299 | ** Check for possible formatting errors in the comment string pComment. |
| 2300 | ** If found, write a description of the problem(s) into pSus and return |
| 2301 | ** true. If everything looks ok, return false. |
| 2302 | */ |
| 2303 | static int suspicious_comment(Blob *pComment, Blob *pSus){ |
| 2304 | char *zStart = blob_str(pComment); |
| 2305 | char *z; |
| 2306 | char *zEnd, *zEnd2; |
| 2307 | char *zSep; |
| 2308 | char cSave1; |
| 2309 | int nIssue = 0; |
| 2310 | static const char zSpecial[] = "\\&<*_`["; |
| 2311 | |
| 2312 | if( !db_get_boolean("verify-comments",1) ) return 0; |
| 2313 | z = zStart; |
| 2314 | blob_init(pSus, 0, 0); |
| 2315 | while( (z = strchr(z,'['))!=0 ){ |
| 2316 | zEnd = strchr(z,']'); |
| 2317 | if( zEnd==0 ){ |
| 2318 | blob_appendf(pSus,"\n (%d) ", ++nIssue); |
| 2319 | blob_appendf(pSus, "Unterminated hyperlink \"%.12s...\"", z); |
| 2320 | break; |
| 2321 | } |
| 2322 | if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){ |
| 2323 | blob_appendf(pSus,"\n (%d) ", ++nIssue); |
| 2324 | blob_appendf(pSus, "Markdown hyperlink syntax: %.*s", |
| 2325 | (int)(zEnd2+1-z), z); |
| 2326 | z = zEnd2; |
| 2327 | continue; |
| 2328 | } |
| 2329 | zSep = strchr(z+1,'|'); |
| 2330 | if( zSep==0 || zSep>zEnd ) zSep = zEnd; |
| 2331 | while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--; |
| 2332 | cSave1 = zSep[0]; |
| 2333 | zSep[0] = 0; |
| 2334 | if( !wiki_valid_link_target(z+1) ){ |
| 2335 | blob_appendf(pSus,"\n (%d) ", ++nIssue); |
| 2336 | blob_appendf(pSus, "Broken hyperlink: [%s]", z+1); |
| 2337 | } |
| 2338 | zSep[0] = cSave1; |
| 2339 | z = zEnd; |
| 2340 | } |
| 2341 | if( nIssue ){ |
| 2342 | Blob tmp = *pSus; |
| 2343 | blob_init(pSus, 0, 0); |
| 2344 | blob_appendf(pSus, |
| 2345 | "Possible comment formatting error%s:%b\n", |
| 2346 | nIssue>1 ? "s" : "", &tmp); |
| 2347 | blob_reset(&tmp); |
| 2348 | return 1; |
| 2349 | }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){ |
| 2350 | Blob in, html, txt; |
| 2351 | char zGot[16]; |
| 2352 | int nGot = 0; |
| 2353 | int i; |
| 2354 | for(i=0; zSpecial[i]; i++){ |
| 2355 | if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i]; |
| 2356 | } |
| 2357 | zGot[nGot] = 0; |
| 2358 | blob_init(&in, blob_str(pComment), -1); |
| 2359 | blob_init(&html, 0, 0); |
| 2360 | wiki_convert(&in, &html, WIKI_INLINE); |
| 2361 | blob_reset(&in); |
| 2362 | blob_init(&txt, 0, 0); |
| 2363 | html_to_plaintext(blob_str(&html), &txt); |
| 2364 | blob_reset(&html); |
| 2365 | fossil_print("The comment uses special character%s \"%s\". " |
| 2366 | "Does it render as you expect?\n\n ", |
| 2367 | nGot>1 ? "s" : "", zGot); |
| 2368 | comment_print(blob_str(&txt), 0, 3, -1, get_comment_format()); |
| 2369 | blob_init(pSus, 0, 0); |
| 2370 | blob_appendf(pSus, "\n"); |
| 2371 | return 1; |
| 2372 | }else{ |
| 2373 | return 0; |
| 2374 | } |
| 2375 | } |
| 2376 | |
| 2377 | /* |
| 2378 | ** COMMAND: ci# |
| 2379 | ** COMMAND: commit |
| @@ -2389,11 +2431,11 @@ | |
| 2389 | ** You will be prompted to enter a check-in comment unless the comment |
| 2390 | ** has been specified on the command-line using "-m" or "-M". The |
| 2391 | ** text editor used is determined by the "editor" setting, or by the |
| 2392 | ** "VISUAL" or "EDITOR" environment variables. Commit message text is |
| 2393 | ** interpreted as fossil-wiki format. Potentially misformatted check-in |
| 2394 | ** comment text is detected and reported unless the --allow-suspect-comment |
| 2395 | ** option is used. |
| 2396 | ** |
| 2397 | ** The --branch option followed by a branch name causes the new |
| 2398 | ** check-in to be placed in a newly-created branch with name specified. |
| 2399 | ** |
| @@ -2421,11 +2463,10 @@ | |
| 2421 | ** Options: |
| 2422 | ** --allow-conflict Allow unresolved merge conflicts |
| 2423 | ** --allow-empty Allow a commit with no changes |
| 2424 | ** --allow-fork Allow the commit to fork |
| 2425 | ** --allow-older Allow a commit older than its ancestor |
| 2426 | ** --allow-suspect-comment Allow check-in comments that might be misformed |
| 2427 | ** --baseline Use a baseline manifest in the commit process |
| 2428 | ** --branch NEW-BRANCH-NAME Check in to this new branch |
| 2429 | ** --close Close the branch being committed |
| 2430 | ** --date-override DATETIME Make DATETIME the time of the check-in. |
| 2431 | ** Useful when importing historical check-ins |
| @@ -2449,10 +2490,11 @@ | |
| 2449 | ** --no-prompt This option disables prompting the user for |
| 2450 | ** input and assumes an answer of 'No' for every |
| 2451 | ** question. |
| 2452 | ** --no-warnings Omit all warnings about file contents |
| 2453 | ** --no-verify Do not run before-commit hooks |
| 2454 | ** --nosign Do not attempt to sign this commit with gpg |
| 2455 | ** --nosync Do not auto-sync prior to committing |
| 2456 | ** --override-lock Allow a check-in even though parent is locked |
| 2457 | ** --private Never sync the resulting check-in and make |
| 2458 | ** all descendants private too. |
| @@ -2488,11 +2530,11 @@ | |
| 2488 | int allowConflict = 0; /* Allow unresolve merge conflicts */ |
| 2489 | int allowEmpty = 0; /* Allow a commit with no changes */ |
| 2490 | int onlyIfChanges = 0; /* No-op if there are no changes */ |
| 2491 | int allowFork = 0; /* Allow the commit to fork */ |
| 2492 | int allowOlder = 0; /* Allow a commit older than its ancestor */ |
| 2493 | int allowSusCom = 0; /* Allow suspicious check-in comments */ |
| 2494 | char *zManifestFile; /* Name of the manifest file */ |
| 2495 | int useCksum; /* True if checksums should be computed and verified */ |
| 2496 | int outputManifest; /* True to output "manifest" and "manifest.uuid" */ |
| 2497 | int dryRunFlag; /* True for a test run. Debugging only */ |
| 2498 | CheckinInfo sCiInfo; /* Information about this check-in */ |
| @@ -2514,10 +2556,11 @@ | |
| 2514 | int bRecheck = 0; /* Repeat fork and closed-branch checks*/ |
| 2515 | int bIgnoreSkew = 0; /* --ignore-clock-skew flag */ |
| 2516 | int mxSize; |
| 2517 | char *zCurBranch = 0; /* The current branch name of checkout */ |
| 2518 | char *zNewBranch = 0; /* The branch name after update */ |
| 2519 | |
| 2520 | memset(&sCiInfo, 0, sizeof(sCiInfo)); |
| 2521 | url_proxy_options(); |
| 2522 | /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */ |
| 2523 | useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0; |
| @@ -2544,11 +2587,11 @@ | |
| 2544 | } |
| 2545 | zComment = find_option("comment","m",1); |
| 2546 | forceFlag = find_option("force", "f", 0)!=0; |
| 2547 | allowConflict = find_option("allow-conflict",0,0)!=0; |
| 2548 | allowEmpty = find_option("allow-empty",0,0)!=0; |
| 2549 | allowSusCom = find_option("allow-suspect-comment",0,0)!=0; |
| 2550 | onlyIfChanges = find_option("if-changes",0,0)!=0; |
| 2551 | allowFork = find_option("allow-fork",0,0)!=0; |
| 2552 | if( find_option("override-lock",0,0)!=0 ) allowFork = 1; |
| 2553 | allowOlder = find_option("allow-older",0,0)!=0; |
| 2554 | noPrompt = find_option("no-prompt", 0, 0)!=0; |
| @@ -2585,13 +2628,13 @@ | |
| 2585 | mxSize = db_large_file_size(); |
| 2586 | if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0; |
| 2587 | verify_all_options(); |
| 2588 | |
| 2589 | /* The --no-warnings flag and the --force flag each imply |
| 2590 | ** the --allow-suspect-comment flag */ |
| 2591 | if( noWarningFlag || forceFlag ){ |
| 2592 | allowSusCom = 1; |
| 2593 | } |
| 2594 | |
| 2595 | /* Get the ID of the parent manifest artifact */ |
| 2596 | vid = db_lget_int("checkout", 0); |
| 2597 | if( vid==0 ){ |
| @@ -2876,52 +2919,70 @@ | |
| 2876 | fossil_free(zNewBranch); |
| 2877 | |
| 2878 | /* Always exit the loop on the second pass */ |
| 2879 | if( bRecheck ) break; |
| 2880 | |
| 2881 | |
| 2882 | /* Get the check-in comment. This might involve prompting the |
| 2883 | ** user for the check-in comment, in which case we should resync |
| 2884 | ** to renew the check-in lock and repeat the checks for conflicts. |
| 2885 | */ |
| 2886 | if( zComment ){ |
| 2887 | Blob sus; |
| 2888 | blob_zero(&comment); |
| 2889 | blob_append(&comment, zComment, -1); |
| 2890 | if( !allowSusCom && suspicious_comment(&comment, &sus) ){ |
| 2891 | fossil_fatal("%bCommit aborted; " |
| 2892 | "use --allow-suspect-comment to override", &sus); |
| 2893 | } |
| 2894 | }else if( zComFile ){ |
| 2895 | Blob sus; |
| 2896 | blob_zero(&comment); |
| 2897 | blob_read_from_file(&comment, zComFile, ExtFILE); |
| 2898 | blob_to_utf8_no_bom(&comment, 1); |
| 2899 | if( !allowSusCom && suspicious_comment(&comment, &sus) ){ |
| 2900 | fossil_fatal("%bCommit aborted; " |
| 2901 | "use --allow-suspect-comment to override", &sus); |
| 2902 | } |
| 2903 | }else if( !noPrompt ){ |
| 2904 | while( 1/*exit-by-break*/ ){ |
| 2905 | char *zInit; |
| 2906 | Blob sus; |
| 2907 | |
| 2908 | zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'"); |
| 2909 | prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag); |
| 2910 | db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment); |
| 2911 | if( !allowSusCom && suspicious_comment(&comment,&sus) ){ |
| 2912 | blob_appendf(&sus, "Continue (y/n/E=edit)? "); |
| 2913 | prompt_user(blob_str(&sus), &ans); |
| 2914 | cReply = blob_str(&ans)[0]; |
| 2915 | blob_reset(&ans); |
| 2916 | blob_reset(&sus); |
| 2917 | if( cReply=='n' || cReply=='N' ){ |
| 2918 | fossil_fatal("Commit aborted."); |
| 2919 | } |
| 2920 | if( cReply!='y' && cReply!='Y' ){ |
| 2921 | /* "Edit" is the default in case the user enters anything that |
| 2922 | ** does not start with Y or N - including just hitting return. */ |
| 2923 | fossil_free(zInit); |
| 2924 | continue; |
| 2925 | } |
| 2926 | } |
| 2927 | if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){ |
| 2928 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2283,97 +2283,139 @@ | |
| 2283 | char **pB = (char**)b; |
| 2284 | return fossil_strcmp(pA[0], pB[0]); |
| 2285 | } |
| 2286 | |
| 2287 | /* |
| 2288 | ** SETTING: verify-comments width=8 default=on show-only-if-changed |
| 2289 | ** |
| 2290 | ** This setting determines much sanity checking, if any, the |
| 2291 | ** "fossil commit" and "fossil amend" commands do against check-in |
| 2292 | ** comments. Recognized values: |
| 2293 | ** |
| 2294 | ** on (Default) Check for bad syntax in check-in comments |
| 2295 | ** and offer the user a chance to continue editing for |
| 2296 | ** interactive sessions, or simply abort the commit if |
| 2297 | ** commit was entered using using -m or -M |
| 2298 | ** |
| 2299 | ** off Do not syntax checking of any kind |
| 2300 | ** |
| 2301 | ** links Similar to "on", except only check for bad hyperlinks |
| 2302 | ** |
| 2303 | ** preview Do all the same checks as "on" but also preview the |
| 2304 | ** checkin comment to the user during interactive sessions |
| 2305 | ** and provide an opportunity to accept or re-edit |
| 2306 | */ |
| 2307 | |
| 2308 | #if INTERFACE |
| 2309 | #define COMCK_LINKS 0x01 /* Check for back hyperlinks */ |
| 2310 | #define COMCK_MARKUP 0x02 /* Check markup */ |
| 2311 | #define COMCK_PREVIEW 0x04 /* Always preview even if no issues found */ |
| 2312 | #define COMCK_NOPREVIEW 0x08 /* Never preview, even for other errors */ |
| 2313 | #endif /* INTERFACE */ |
| 2314 | |
| 2315 | /* |
| 2316 | ** Check for possible formatting errors in the comment string pComment. |
| 2317 | ** |
| 2318 | ** If concerns are found, write a description of the problem(s) to |
| 2319 | ** stdout return non-zero. The return value is some combination of |
| 2320 | ** of the COMCK_* flags depending on what went wrong. |
| 2321 | ** |
| 2322 | ** If no issues are seen, do not output anything and return zero. |
| 2323 | */ |
| 2324 | static int suspicious_comment(Blob *pComment, int mFlags){ |
| 2325 | char *zStart = blob_str(pComment); |
| 2326 | char *z; |
| 2327 | char *zEnd, *zEnd2; |
| 2328 | char *zSep; |
| 2329 | char cSave1; |
| 2330 | int nIssue = 0; |
| 2331 | int rc = mFlags & COMCK_PREVIEW; |
| 2332 | Blob out; |
| 2333 | static const char zSpecial[] = "\\&<*_`["; |
| 2334 | |
| 2335 | if( mFlags==0 ) return 0; |
| 2336 | z = zStart; |
| 2337 | blob_init(&out, 0, 0); |
| 2338 | if( mFlags & COMCK_LINKS ){ |
| 2339 | while( (z = strchr(z,'['))!=0 ){ |
| 2340 | zEnd = strchr(z,']'); |
| 2341 | if( zEnd==0 ){ |
| 2342 | blob_appendf(&out,"\n (%d) ", ++nIssue); |
| 2343 | blob_appendf(&out, "Unterminated hyperlink \"%.12s...\"", z); |
| 2344 | break; |
| 2345 | } |
| 2346 | if( zEnd[1]=='(' && (zEnd2 = strchr(zEnd,')'))!=0 ){ |
| 2347 | blob_appendf(&out,"\n (%d) ", ++nIssue); |
| 2348 | blob_appendf(&out, "Markdown hyperlink syntax: %.*s", |
| 2349 | (int)(zEnd2+1-z), z); |
| 2350 | z = zEnd2; |
| 2351 | continue; |
| 2352 | } |
| 2353 | zSep = strchr(z+1,'|'); |
| 2354 | if( zSep==0 || zSep>zEnd ) zSep = zEnd; |
| 2355 | while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--; |
| 2356 | cSave1 = zSep[0]; |
| 2357 | zSep[0] = 0; |
| 2358 | if( !wiki_valid_link_target(z+1) ){ |
| 2359 | blob_appendf(&out,"\n (%d) ", ++nIssue); |
| 2360 | blob_appendf(&out, "Broken hyperlink: [%s]", z+1); |
| 2361 | } |
| 2362 | zSep[0] = cSave1; |
| 2363 | z = zEnd; |
| 2364 | } |
| 2365 | } |
| 2366 | |
| 2367 | if( nIssue>0 |
| 2368 | || (mFlags & COMCK_PREVIEW)!=0 |
| 2369 | || ((mFlags & COMCK_MARKUP)!=0 && strcspn(zStart,zSpecial)<strlen(zStart)) |
| 2370 | ){ |
| 2371 | char zGot[16]; |
| 2372 | int nGot = 0; |
| 2373 | int i; |
| 2374 | if( (mFlags & COMCK_MARKUP)!=0 ){ |
| 2375 | for(i=0; zSpecial[i]; i++){ |
| 2376 | if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i]; |
| 2377 | } |
| 2378 | } |
| 2379 | zGot[nGot] = 0; |
| 2380 | if( nGot>0 ) rc |= COMCK_MARKUP; |
| 2381 | if( nGot>0 && nIssue>0 ){ |
| 2382 | blob_appendf(&out,"\n (%d) Comment uses special character%s \"%s\"", |
| 2383 | ++nIssue, (nGot>1 ? "s" : ""), zGot); |
| 2384 | nGot = 0; |
| 2385 | } |
| 2386 | if( nIssue ){ |
| 2387 | rc |= COMCK_LINKS; |
| 2388 | fossil_print( |
| 2389 | "Possible comment formatting error%s:%b\n", |
| 2390 | nIssue>1 ? "s" : "", &out |
| 2391 | ); |
| 2392 | } |
| 2393 | if( (mFlags & COMCK_NOPREVIEW)==0 ){ |
| 2394 | Blob in, html, txt; |
| 2395 | blob_init(&in, blob_str(pComment), -1); |
| 2396 | blob_init(&html, 0, 0); |
| 2397 | blob_init(&txt, 0, 0); |
| 2398 | wiki_convert(&in, &html, WIKI_INLINE); |
| 2399 | html_to_plaintext(blob_str(&html), &txt); |
| 2400 | if( nGot>0 ){ |
| 2401 | fossil_print( |
| 2402 | "The comment uses special character%s \"%s\". " |
| 2403 | "Does it render as you expect?\n\n ", |
| 2404 | (nGot>1 ? "s" : ""), zGot |
| 2405 | ); |
| 2406 | }else{ |
| 2407 | fossil_print("Preview of the check-in comment:\n\n "); |
| 2408 | } |
| 2409 | comment_print(blob_str(&txt), 0, 3, -1, get_comment_format()); |
| 2410 | blob_reset(&in); |
| 2411 | blob_reset(&html); |
| 2412 | blob_reset(&txt); |
| 2413 | } |
| 2414 | } |
| 2415 | blob_reset(&out); |
| 2416 | return rc; |
| 2417 | } |
| 2418 | |
| 2419 | /* |
| 2420 | ** COMMAND: ci# |
| 2421 | ** COMMAND: commit |
| @@ -2389,11 +2431,11 @@ | |
| 2431 | ** You will be prompted to enter a check-in comment unless the comment |
| 2432 | ** has been specified on the command-line using "-m" or "-M". The |
| 2433 | ** text editor used is determined by the "editor" setting, or by the |
| 2434 | ** "VISUAL" or "EDITOR" environment variables. Commit message text is |
| 2435 | ** interpreted as fossil-wiki format. Potentially misformatted check-in |
| 2436 | ** comment text is detected and reported unless the --no-verify-comment |
| 2437 | ** option is used. |
| 2438 | ** |
| 2439 | ** The --branch option followed by a branch name causes the new |
| 2440 | ** check-in to be placed in a newly-created branch with name specified. |
| 2441 | ** |
| @@ -2421,11 +2463,10 @@ | |
| 2463 | ** Options: |
| 2464 | ** --allow-conflict Allow unresolved merge conflicts |
| 2465 | ** --allow-empty Allow a commit with no changes |
| 2466 | ** --allow-fork Allow the commit to fork |
| 2467 | ** --allow-older Allow a commit older than its ancestor |
| 2468 | ** --baseline Use a baseline manifest in the commit process |
| 2469 | ** --branch NEW-BRANCH-NAME Check in to this new branch |
| 2470 | ** --close Close the branch being committed |
| 2471 | ** --date-override DATETIME Make DATETIME the time of the check-in. |
| 2472 | ** Useful when importing historical check-ins |
| @@ -2449,10 +2490,11 @@ | |
| 2490 | ** --no-prompt This option disables prompting the user for |
| 2491 | ** input and assumes an answer of 'No' for every |
| 2492 | ** question. |
| 2493 | ** --no-warnings Omit all warnings about file contents |
| 2494 | ** --no-verify Do not run before-commit hooks |
| 2495 | ** --no-verify-comment Do not validate the check-in comment |
| 2496 | ** --nosign Do not attempt to sign this commit with gpg |
| 2497 | ** --nosync Do not auto-sync prior to committing |
| 2498 | ** --override-lock Allow a check-in even though parent is locked |
| 2499 | ** --private Never sync the resulting check-in and make |
| 2500 | ** all descendants private too. |
| @@ -2488,11 +2530,11 @@ | |
| 2530 | int allowConflict = 0; /* Allow unresolve merge conflicts */ |
| 2531 | int allowEmpty = 0; /* Allow a commit with no changes */ |
| 2532 | int onlyIfChanges = 0; /* No-op if there are no changes */ |
| 2533 | int allowFork = 0; /* Allow the commit to fork */ |
| 2534 | int allowOlder = 0; /* Allow a commit older than its ancestor */ |
| 2535 | int noVerifyCom = 0; /* Allow suspicious check-in comments */ |
| 2536 | char *zManifestFile; /* Name of the manifest file */ |
| 2537 | int useCksum; /* True if checksums should be computed and verified */ |
| 2538 | int outputManifest; /* True to output "manifest" and "manifest.uuid" */ |
| 2539 | int dryRunFlag; /* True for a test run. Debugging only */ |
| 2540 | CheckinInfo sCiInfo; /* Information about this check-in */ |
| @@ -2514,10 +2556,11 @@ | |
| 2556 | int bRecheck = 0; /* Repeat fork and closed-branch checks*/ |
| 2557 | int bIgnoreSkew = 0; /* --ignore-clock-skew flag */ |
| 2558 | int mxSize; |
| 2559 | char *zCurBranch = 0; /* The current branch name of checkout */ |
| 2560 | char *zNewBranch = 0; /* The branch name after update */ |
| 2561 | int ckComFlgs; /* Flags passed to suspicious_comment() */ |
| 2562 | |
| 2563 | memset(&sCiInfo, 0, sizeof(sCiInfo)); |
| 2564 | url_proxy_options(); |
| 2565 | /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */ |
| 2566 | useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0; |
| @@ -2544,11 +2587,11 @@ | |
| 2587 | } |
| 2588 | zComment = find_option("comment","m",1); |
| 2589 | forceFlag = find_option("force", "f", 0)!=0; |
| 2590 | allowConflict = find_option("allow-conflict",0,0)!=0; |
| 2591 | allowEmpty = find_option("allow-empty",0,0)!=0; |
| 2592 | noVerifyCom = find_option("no-verify-comment",0,0)!=0; |
| 2593 | onlyIfChanges = find_option("if-changes",0,0)!=0; |
| 2594 | allowFork = find_option("allow-fork",0,0)!=0; |
| 2595 | if( find_option("override-lock",0,0)!=0 ) allowFork = 1; |
| 2596 | allowOlder = find_option("allow-older",0,0)!=0; |
| 2597 | noPrompt = find_option("no-prompt", 0, 0)!=0; |
| @@ -2585,13 +2628,13 @@ | |
| 2628 | mxSize = db_large_file_size(); |
| 2629 | if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0; |
| 2630 | verify_all_options(); |
| 2631 | |
| 2632 | /* The --no-warnings flag and the --force flag each imply |
| 2633 | ** the --no-verify-comment flag */ |
| 2634 | if( noWarningFlag || forceFlag ){ |
| 2635 | noVerifyCom = 1; |
| 2636 | } |
| 2637 | |
| 2638 | /* Get the ID of the parent manifest artifact */ |
| 2639 | vid = db_lget_int("checkout", 0); |
| 2640 | if( vid==0 ){ |
| @@ -2876,52 +2919,70 @@ | |
| 2919 | fossil_free(zNewBranch); |
| 2920 | |
| 2921 | /* Always exit the loop on the second pass */ |
| 2922 | if( bRecheck ) break; |
| 2923 | |
| 2924 | |
| 2925 | /* Figure out how much comment verification is requested */ |
| 2926 | if( noVerifyCom ){ |
| 2927 | ckComFlgs = 0; |
| 2928 | }else{ |
| 2929 | const char *zVerComs = db_get("verify-comments","on"); |
| 2930 | if( is_false(zVerComs) ){ |
| 2931 | ckComFlgs = 0; |
| 2932 | }else if( strcmp(zVerComs,"preview")==0 ){ |
| 2933 | ckComFlgs = COMCK_PREVIEW | COMCK_LINKS | COMCK_MARKUP; |
| 2934 | }else if( strcmp(zVerComs,"links")==0 ){ |
| 2935 | ckComFlgs = COMCK_LINKS; |
| 2936 | }else{ |
| 2937 | ckComFlgs = COMCK_LINKS | COMCK_MARKUP; |
| 2938 | } |
| 2939 | } |
| 2940 | |
| 2941 | /* Get the check-in comment. This might involve prompting the |
| 2942 | ** user for the check-in comment, in which case we should resync |
| 2943 | ** to renew the check-in lock and repeat the checks for conflicts. |
| 2944 | */ |
| 2945 | if( zComment ){ |
| 2946 | blob_zero(&comment); |
| 2947 | blob_append(&comment, zComment, -1); |
| 2948 | ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP); |
| 2949 | ckComFlgs |= COMCK_NOPREVIEW; |
| 2950 | if( suspicious_comment(&comment, ckComFlgs) ){ |
| 2951 | fossil_fatal("Commit aborted; " |
| 2952 | "use --no-verify-comment to override"); |
| 2953 | } |
| 2954 | }else if( zComFile ){ |
| 2955 | blob_zero(&comment); |
| 2956 | blob_read_from_file(&comment, zComFile, ExtFILE); |
| 2957 | blob_to_utf8_no_bom(&comment, 1); |
| 2958 | ckComFlgs &= ~(COMCK_PREVIEW|COMCK_MARKUP); |
| 2959 | ckComFlgs |= COMCK_NOPREVIEW; |
| 2960 | if( suspicious_comment(&comment, ckComFlgs) ){ |
| 2961 | fossil_fatal("Commit aborted; " |
| 2962 | "use --no-verify-comment to override"); |
| 2963 | } |
| 2964 | }else if( !noPrompt ){ |
| 2965 | while( 1/*exit-by-break*/ ){ |
| 2966 | int rc; |
| 2967 | char *zInit; |
| 2968 | zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'"); |
| 2969 | prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag); |
| 2970 | db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment); |
| 2971 | if( (rc = suspicious_comment(&comment, ckComFlgs))!=0 ){ |
| 2972 | if( rc==COMCK_PREVIEW ){ |
| 2973 | prompt_user("\nContinue (Y/n/e=edit)? ", &ans); |
| 2974 | }else{ |
| 2975 | prompt_user("\nContinue (y/n/E=edit)? ", &ans); |
| 2976 | } |
| 2977 | cReply = blob_str(&ans)[0]; |
| 2978 | cReply = fossil_tolower(cReply); |
| 2979 | blob_reset(&ans); |
| 2980 | if( cReply=='n' ){ |
| 2981 | fossil_fatal("Commit aborted."); |
| 2982 | } |
| 2983 | if( cReply=='e' || (cReply!='y' && rc!=COMCK_PREVIEW) ){ |
| 2984 | fossil_free(zInit); |
| 2985 | continue; |
| 2986 | } |
| 2987 | } |
| 2988 | if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){ |
| 2989 |