Fossil SCM
Add new command to edit a check-in from the command line similar to editing a check-in from the web UI.
Commit
b9e0d72e7e6da002fb0da5e4c8bd0657101edcf7
Parent
e5dbe8b331e534b…
1 file changed
+234
-78
+234
-78
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -2276,10 +2276,125 @@ | ||
| 2276 | 2276 | } |
| 2277 | 2277 | while( fossil_isspace(zB[0]) ) zB++; |
| 2278 | 2278 | while( fossil_isspace(zA[0]) ) zA++; |
| 2279 | 2279 | return zA[0]==0 && zB[0]==0; |
| 2280 | 2280 | } |
| 2281 | + | |
| 2282 | +/* | |
| 2283 | +** The following methods operate on the newtags temporary table | |
| 2284 | +** that is used to collect various changes to be added to a control | |
| 2285 | +** artifact for a check-in edit. | |
| 2286 | +*/ | |
| 2287 | +static void init_newtags(void){ | |
| 2288 | + db_multi_exec("CREATE TEMP TABLE newtags(tag UNIQUE, prefix, value)"); | |
| 2289 | +} | |
| 2290 | + | |
| 2291 | +static void change_special( | |
| 2292 | + const char *zName, /* Name of the special tag */ | |
| 2293 | + const char *zOp, /* Operation prefix (e.g. +,-,*) */ | |
| 2294 | + const char *zValue /* Value of the tag */ | |
| 2295 | +){ | |
| 2296 | + db_multi_exec("REPLACE INTO newtags VALUES(%Q,'%q',%Q)", zName, zOp, zValue); | |
| 2297 | +} | |
| 2298 | + | |
| 2299 | +static void change_sym_tag(const char *zTag, const char *zOp){ | |
| 2300 | + db_multi_exec("REPLACE INTO newtags VALUES('sym-%q',%Q,NULL)", zTag, zOp); | |
| 2301 | +} | |
| 2302 | + | |
| 2303 | +static void cancel_special(const char *zTag){ | |
| 2304 | + change_special(zTag,"-",0); | |
| 2305 | +} | |
| 2306 | + | |
| 2307 | +static void add_color(const char *zNewColor, int fPropagateColor){ | |
| 2308 | + change_special("bgcolor",fPropagateColor ? "*" : "+", zNewColor); | |
| 2309 | +} | |
| 2310 | + | |
| 2311 | +static void cancel_color(void){ | |
| 2312 | + change_special("color","-",0); | |
| 2313 | +} | |
| 2314 | + | |
| 2315 | +static void add_comment(const char *zNewComment){ | |
| 2316 | + change_special("comment","+",zNewComment); | |
| 2317 | +} | |
| 2318 | + | |
| 2319 | +static void add_date(const char *zNewDate){ | |
| 2320 | + change_special("date","+",zNewDate); | |
| 2321 | +} | |
| 2322 | + | |
| 2323 | +static void add_user(const char *zNewUser){ | |
| 2324 | + change_special("user","+",zNewUser); | |
| 2325 | +} | |
| 2326 | + | |
| 2327 | +static void add_tag(const char *zNewTag){ | |
| 2328 | + change_sym_tag(zNewTag,"+"); | |
| 2329 | +} | |
| 2330 | + | |
| 2331 | +static void cancel_tag(int rid, const char *zCancelTag){ | |
| 2332 | + if( db_exists("SELECT 1 FROM tagxref, tag" | |
| 2333 | + " WHERE tagxref.rid=%d AND tagtype>0" | |
| 2334 | + " AND tagxref.tagid=tag.tagid AND tagname='sym-%q'", | |
| 2335 | + rid, zCancelTag) | |
| 2336 | + ) change_sym_tag(zCancelTag,"-"); | |
| 2337 | +} | |
| 2338 | + | |
| 2339 | +static void hide_branch(void){ | |
| 2340 | + change_special("hidden","*",0); | |
| 2341 | +} | |
| 2342 | + | |
| 2343 | +static void close_leaf(int rid){ | |
| 2344 | + change_special("closed",is_a_leaf(rid)?"+":"*",0); | |
| 2345 | +} | |
| 2346 | + | |
| 2347 | +static void change_branch(int rid, const char *zNewBranch){ | |
| 2348 | + db_multi_exec( | |
| 2349 | + "REPLACE INTO newtags " | |
| 2350 | + " SELECT tagname, '-', NULL FROM tagxref, tag" | |
| 2351 | + " WHERE tagxref.rid=%d AND tagtype==2" | |
| 2352 | + " AND tagname GLOB 'sym-*'" | |
| 2353 | + " AND tag.tagid=tagxref.tagid", | |
| 2354 | + rid | |
| 2355 | + ); | |
| 2356 | + change_special("branch","*",zNewBranch); | |
| 2357 | + change_sym_tag(zNewBranch,"*"); | |
| 2358 | +} | |
| 2359 | + | |
| 2360 | +/* | |
| 2361 | +** The apply_newtags method is called after all newtags have been added | |
| 2362 | +** and the control artifact is completed and then written to the DB. | |
| 2363 | +*/ | |
| 2364 | +static void apply_newtags(Blob *ctrl, int rid, const char *zUuid){ | |
| 2365 | + Stmt q; | |
| 2366 | + int nChng = 0; | |
| 2367 | + | |
| 2368 | + db_prepare(&q, "SELECT tag, prefix, value FROM newtags" | |
| 2369 | + " ORDER BY prefix || tag"); | |
| 2370 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 2371 | + const char *zTag = db_column_text(&q, 0); | |
| 2372 | + const char *zPrefix = db_column_text(&q, 1); | |
| 2373 | + const char *zValue = db_column_text(&q, 2); | |
| 2374 | + nChng++; | |
| 2375 | + if( zValue ){ | |
| 2376 | + blob_appendf(ctrl, "T %s%F %s %F\n", zPrefix, zTag, zUuid, zValue); | |
| 2377 | + }else{ | |
| 2378 | + blob_appendf(ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); | |
| 2379 | + } | |
| 2380 | + } | |
| 2381 | + db_finalize(&q); | |
| 2382 | + if( nChng>0 ){ | |
| 2383 | + int nrid; | |
| 2384 | + Blob cksum; | |
| 2385 | + blob_appendf(ctrl, "U %F\n", login_name()); | |
| 2386 | + md5sum_blob(ctrl, &cksum); | |
| 2387 | + blob_appendf(ctrl, "Z %b\n", &cksum); | |
| 2388 | + db_begin_transaction(); | |
| 2389 | + g.markPrivate = content_is_private(rid); | |
| 2390 | + nrid = content_put(ctrl); | |
| 2391 | + manifest_crosslink(nrid, ctrl, MC_PERMIT_HOOKS); | |
| 2392 | + assert( blob_is_reset(ctrl) ); | |
| 2393 | + db_end_transaction(0); | |
| 2394 | + } | |
| 2395 | +} | |
| 2281 | 2396 | |
| 2282 | 2397 | /* |
| 2283 | 2398 | ** WEBPAGE: ci_edit |
| 2284 | 2399 | ** URL: /ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER |
| 2285 | 2400 | ** |
| @@ -2360,36 +2475,19 @@ | ||
| 2360 | 2475 | |
| 2361 | 2476 | login_verify_csrf_secret(); |
| 2362 | 2477 | blob_zero(&ctrl); |
| 2363 | 2478 | zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); |
| 2364 | 2479 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 2365 | - db_multi_exec("CREATE TEMP TABLE newtags(tag UNIQUE, prefix, value)"); | |
| 2480 | + init_newtags(); | |
| 2366 | 2481 | if( zNewColor[0] |
| 2367 | 2482 | && (fPropagateColor!=fNewPropagateColor |
| 2368 | 2483 | || fossil_strcmp(zColor,zNewColor)!=0) |
| 2369 | - ){ | |
| 2370 | - char *zPrefix = "+"; | |
| 2371 | - if( fNewPropagateColor ){ | |
| 2372 | - zPrefix = "*"; | |
| 2373 | - } | |
| 2374 | - db_multi_exec("REPLACE INTO newtags VALUES('bgcolor',%Q,%Q)", | |
| 2375 | - zPrefix, zNewColor); | |
| 2376 | - } | |
| 2377 | - if( zNewColor[0]==0 && zColor[0]!=0 ){ | |
| 2378 | - db_multi_exec("REPLACE INTO newtags VALUES('bgcolor','-',NULL)"); | |
| 2379 | - } | |
| 2380 | - if( comment_compare(zComment,zNewComment)==0 ){ | |
| 2381 | - db_multi_exec("REPLACE INTO newtags VALUES('comment','+',%Q)", | |
| 2382 | - zNewComment); | |
| 2383 | - } | |
| 2384 | - if( fossil_strcmp(zDate,zNewDate)!=0 ){ | |
| 2385 | - db_multi_exec("REPLACE INTO newtags VALUES('date','+',%Q)", | |
| 2386 | - zNewDate); | |
| 2387 | - } | |
| 2388 | - if( fossil_strcmp(zUser,zNewUser)!=0 ){ | |
| 2389 | - db_multi_exec("REPLACE INTO newtags VALUES('user','+',%Q)", zNewUser); | |
| 2390 | - } | |
| 2484 | + ) add_color(zNewColor,fNewPropagateColor); | |
| 2485 | + if( zNewColor[0]==0 && zColor[0]!=0 ) cancel_color(); | |
| 2486 | + if( comment_compare(zComment,zNewComment)==0 ) add_comment(zNewComment); | |
| 2487 | + if( fossil_strcmp(zDate,zNewDate)!=0 ) add_date(zNewDate); | |
| 2488 | + if( fossil_strcmp(zUser,zNewUser)!=0 ) add_user(zNewUser); | |
| 2391 | 2489 | db_prepare(&q, |
| 2392 | 2490 | "SELECT tag.tagid, tagname FROM tagxref, tag" |
| 2393 | 2491 | " WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid", |
| 2394 | 2492 | rid |
| 2395 | 2493 | ); |
| @@ -2396,65 +2494,18 @@ | ||
| 2396 | 2494 | while( db_step(&q)==SQLITE_ROW ){ |
| 2397 | 2495 | int tagid = db_column_int(&q, 0); |
| 2398 | 2496 | const char *zTag = db_column_text(&q, 1); |
| 2399 | 2497 | char zLabel[30]; |
| 2400 | 2498 | sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid); |
| 2401 | - if( P(zLabel) ){ | |
| 2402 | - db_multi_exec("REPLACE INTO newtags VALUES(%Q,'-',NULL)", zTag); | |
| 2403 | - } | |
| 2404 | - } | |
| 2405 | - db_finalize(&q); | |
| 2406 | - if( zHideFlag[0] ){ | |
| 2407 | - db_multi_exec("REPLACE INTO newtags VALUES('hidden','*',NULL)"); | |
| 2408 | - } | |
| 2409 | - if( zCloseFlag[0] ){ | |
| 2410 | - db_multi_exec("REPLACE INTO newtags VALUES('closed','%s',NULL)", | |
| 2411 | - is_a_leaf(rid)?"+":"*"); | |
| 2412 | - } | |
| 2413 | - if( zNewTagFlag[0] && zNewTag[0] ){ | |
| 2414 | - db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag); | |
| 2415 | - } | |
| 2416 | - if( zNewBrFlag[0] && zNewBranch[0] ){ | |
| 2417 | - db_multi_exec( | |
| 2418 | - "REPLACE INTO newtags " | |
| 2419 | - " SELECT tagname, '-', NULL FROM tagxref, tag" | |
| 2420 | - " WHERE tagxref.rid=%d AND tagtype==2" | |
| 2421 | - " AND tagname GLOB 'sym-*'" | |
| 2422 | - " AND tag.tagid=tagxref.tagid", | |
| 2423 | - rid | |
| 2424 | - ); | |
| 2425 | - db_multi_exec("REPLACE INTO newtags VALUES('branch','*',%Q)", zNewBranch); | |
| 2426 | - db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','*',NULL)", | |
| 2427 | - zNewBranch); | |
| 2428 | - } | |
| 2429 | - db_prepare(&q, "SELECT tag, prefix, value FROM newtags" | |
| 2430 | - " ORDER BY prefix || tag"); | |
| 2431 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 2432 | - const char *zTag = db_column_text(&q, 0); | |
| 2433 | - const char *zPrefix = db_column_text(&q, 1); | |
| 2434 | - const char *zValue = db_column_text(&q, 2); | |
| 2435 | - nChng++; | |
| 2436 | - if( zValue ){ | |
| 2437 | - blob_appendf(&ctrl, "T %s%F %s %F\n", zPrefix, zTag, zUuid, zValue); | |
| 2438 | - }else{ | |
| 2439 | - blob_appendf(&ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); | |
| 2440 | - } | |
| 2441 | - } | |
| 2442 | - db_finalize(&q); | |
| 2443 | - if( nChng>0 ){ | |
| 2444 | - int nrid; | |
| 2445 | - Blob cksum; | |
| 2446 | - blob_appendf(&ctrl, "U %F\n", login_name()); | |
| 2447 | - md5sum_blob(&ctrl, &cksum); | |
| 2448 | - blob_appendf(&ctrl, "Z %b\n", &cksum); | |
| 2449 | - db_begin_transaction(); | |
| 2450 | - g.markPrivate = content_is_private(rid); | |
| 2451 | - nrid = content_put(&ctrl); | |
| 2452 | - manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS); | |
| 2453 | - assert( blob_is_reset(&ctrl) ); | |
| 2454 | - db_end_transaction(0); | |
| 2455 | - } | |
| 2499 | + if( P(zLabel) ) cancel_special(zTag); | |
| 2500 | + } | |
| 2501 | + db_finalize(&q); | |
| 2502 | + if( zHideFlag[0] ) hide_branch(); | |
| 2503 | + if( zCloseFlag[0] ) close_leaf(rid); | |
| 2504 | + if( zNewTagFlag[0] && zNewTag[0] ) add_tag(zNewTag); | |
| 2505 | + if( zNewBrFlag[0] && zNewBranch[0] ) change_branch(rid,zNewBranch); | |
| 2506 | + apply_newtags(&ctrl, rid, zUuid); | |
| 2456 | 2507 | cgi_redirectf("ci?name=%s", zUuid); |
| 2457 | 2508 | } |
| 2458 | 2509 | blob_zero(&comment); |
| 2459 | 2510 | blob_append(&comment, zNewComment, -1); |
| 2460 | 2511 | zUuid[10] = 0; |
| @@ -2652,5 +2703,110 @@ | ||
| 2652 | 2703 | @ </td></tr> |
| 2653 | 2704 | @ </table> |
| 2654 | 2705 | @ </div></form> |
| 2655 | 2706 | style_footer(); |
| 2656 | 2707 | } |
| 2708 | + | |
| 2709 | +/* | |
| 2710 | +** COMMAND: edit | |
| 2711 | +** | |
| 2712 | +** Usage: %fossil edit UUID ?OPTIONS? | |
| 2713 | +** | |
| 2714 | +** Options: | |
| 2715 | +** | |
| 2716 | +** --euser USER Make USER the check-in user | |
| 2717 | +** --comment COMMENT Make COMMENT the check-in comment | |
| 2718 | +** --date DATE Make DATE the check-in time | |
| 2719 | +** --bgcolor COLOR Apply COLOR to this check-in | |
| 2720 | +** --branchcolor COLOR Apply COLOR to the branch | |
| 2721 | +** --tag TAG Add new TAG to this check-in | |
| 2722 | +** --cancel TAG Cancel TAG from this check-in | |
| 2723 | +** --branch NAME Make this check-in the start of branch NAME | |
| 2724 | +** --hide Hide branch starting from this check-in | |
| 2725 | +** --close Mark this "leaf" as closed | |
| 2726 | +*/ | |
| 2727 | +void ci_edit_cmd(void){ | |
| 2728 | + int rid; | |
| 2729 | + const char *zComment; /* Current comment on the check-in */ | |
| 2730 | + const char *zNewComment; /* Revised check-in comment */ | |
| 2731 | + const char *zUser; /* Current user for the check-in */ | |
| 2732 | + const char *zNewUser; /* Revised user */ | |
| 2733 | + const char *zDate; /* Current date of the check-in */ | |
| 2734 | + const char *zNewDate; /* Revised check-in date */ | |
| 2735 | + const char *zColor; | |
| 2736 | + const char *zNewColor; | |
| 2737 | + const char *zNewBrColor; | |
| 2738 | + const char *zNewTag; | |
| 2739 | + const char *zNewBranch; | |
| 2740 | + const char *zCancelTag; | |
| 2741 | + int fClose; /* True if leaf should be closed */ | |
| 2742 | + int fHide; /* True if branch should be hidden */ | |
| 2743 | + int fPropagateColor; /* True if color propagates before edit */ | |
| 2744 | + int fNewPropagateColor = 0; /* True if color propagates after edit */ | |
| 2745 | + const char *zChngTime; /* The change time on the control artifact */ | |
| 2746 | + const char *zUuid; | |
| 2747 | + Blob ctrl; | |
| 2748 | + char *zNow; | |
| 2749 | + | |
| 2750 | + if( g.argc<3 ) usage("UUID ?OPTIONS?"); | |
| 2751 | + zNewComment = find_option("comment",0,1); | |
| 2752 | + zNewBranch = find_option("branch",0,1); | |
| 2753 | + zNewColor = find_option("bgcolor",0,1); | |
| 2754 | + zNewBrColor = find_option("branchcolor",0,1); | |
| 2755 | + if( zNewBrColor ){ | |
| 2756 | + zNewColor = zNewBrColor; | |
| 2757 | + fNewPropagateColor = 1; | |
| 2758 | + } | |
| 2759 | + zNewDate = find_option("date",0,1); | |
| 2760 | + zNewUser = find_option("euser",0,1); | |
| 2761 | + zNewTag = find_option("tag",0,1); | |
| 2762 | + zCancelTag = find_option("cancel",0,1); | |
| 2763 | + fClose = find_option("close",0,0)!=0; | |
| 2764 | + fHide = find_option("hide",0,0)!=0; | |
| 2765 | + zChngTime = find_option("chngtime",0,1); | |
| 2766 | + db_find_and_open_repository(0,0); | |
| 2767 | + user_select(); | |
| 2768 | + verify_all_options(); | |
| 2769 | + rid = name_to_typed_rid(g.argv[2], "ci"); | |
| 2770 | + zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 2771 | + zComment = db_text(0, "SELECT coalesce(ecomment,comment)" | |
| 2772 | + " FROM event WHERE objid=%d", rid); | |
| 2773 | + if( zComment==0 || zComment[0]==0 ) fossil_fatal("No comment on rid %d", rid); | |
| 2774 | + zUser = db_text(0, "SELECT coalesce(euser,user)" | |
| 2775 | + " FROM event WHERE objid=%d", rid); | |
| 2776 | + if( zUser==0 || zUser[0]==0 ) fossil_fatal("No user on rid %d", rid); | |
| 2777 | + zDate = db_text(0, "SELECT datetime(mtime)" | |
| 2778 | + " FROM event WHERE objid=%d", rid); | |
| 2779 | + if( zDate==0 || zDate[0]==0 ) fossil_fatal("No date on rid %d", rid); | |
| 2780 | + zColor = db_text("", "SELECT bgcolor" | |
| 2781 | + " FROM event WHERE objid=%d", rid); | |
| 2782 | + fPropagateColor = db_int(0, "SELECT tagtype FROM tagxref" | |
| 2783 | + " WHERE rid=%d AND tagid=%d", | |
| 2784 | + rid, TAG_BGCOLOR)==2; | |
| 2785 | + fNewPropagateColor = zNewColor && zNewColor[0] | |
| 2786 | + ? fNewPropagateColor : fPropagateColor; | |
| 2787 | + blob_zero(&ctrl); | |
| 2788 | + zNow = date_in_standard_format(zChngTime && zChngTime[0] ? zChngTime : "now"); | |
| 2789 | + blob_appendf(&ctrl, "D %s\n", zNow); | |
| 2790 | + init_newtags(); | |
| 2791 | + if( zNewColor && zNewColor[0] | |
| 2792 | + && (fPropagateColor!=fNewPropagateColor | |
| 2793 | + || fossil_strcmp(zColor,zNewColor)!=0) | |
| 2794 | + ) add_color(zNewColor,fNewPropagateColor); | |
| 2795 | + if( (zNewColor!=0 && zNewColor[0]==0) && (zColor && zColor[0] ) ){ | |
| 2796 | + cancel_color(); | |
| 2797 | + } | |
| 2798 | + if( zNewComment && zNewComment[0] | |
| 2799 | + && comment_compare(zComment,zNewComment)==0 ) add_comment(zNewComment); | |
| 2800 | + if( zNewDate && zNewDate[0] && fossil_strcmp(zDate,zNewDate)!=0 ){ | |
| 2801 | + add_date(zNewDate); | |
| 2802 | + } | |
| 2803 | + if( zNewUser && zNewUser[0] && fossil_strcmp(zUser,zNewUser)!=0 ){ | |
| 2804 | + add_user(zNewUser); | |
| 2805 | + } | |
| 2806 | + if( zNewTag && zNewTag[0] ) add_tag(zNewTag); | |
| 2807 | + if( zCancelTag && zCancelTag[0] ) cancel_tag(rid,zCancelTag); | |
| 2808 | + if( fHide ) hide_branch(); | |
| 2809 | + if( fClose ) close_leaf(rid); | |
| 2810 | + if( zNewBranch && zNewBranch[0] ) change_branch(rid,zNewBranch); | |
| 2811 | + apply_newtags(&ctrl, rid, zUuid); | |
| 2812 | +} | |
| 2657 | 2813 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2276,10 +2276,125 @@ | |
| 2276 | } |
| 2277 | while( fossil_isspace(zB[0]) ) zB++; |
| 2278 | while( fossil_isspace(zA[0]) ) zA++; |
| 2279 | return zA[0]==0 && zB[0]==0; |
| 2280 | } |
| 2281 | |
| 2282 | /* |
| 2283 | ** WEBPAGE: ci_edit |
| 2284 | ** URL: /ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER |
| 2285 | ** |
| @@ -2360,36 +2475,19 @@ | |
| 2360 | |
| 2361 | login_verify_csrf_secret(); |
| 2362 | blob_zero(&ctrl); |
| 2363 | zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); |
| 2364 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 2365 | db_multi_exec("CREATE TEMP TABLE newtags(tag UNIQUE, prefix, value)"); |
| 2366 | if( zNewColor[0] |
| 2367 | && (fPropagateColor!=fNewPropagateColor |
| 2368 | || fossil_strcmp(zColor,zNewColor)!=0) |
| 2369 | ){ |
| 2370 | char *zPrefix = "+"; |
| 2371 | if( fNewPropagateColor ){ |
| 2372 | zPrefix = "*"; |
| 2373 | } |
| 2374 | db_multi_exec("REPLACE INTO newtags VALUES('bgcolor',%Q,%Q)", |
| 2375 | zPrefix, zNewColor); |
| 2376 | } |
| 2377 | if( zNewColor[0]==0 && zColor[0]!=0 ){ |
| 2378 | db_multi_exec("REPLACE INTO newtags VALUES('bgcolor','-',NULL)"); |
| 2379 | } |
| 2380 | if( comment_compare(zComment,zNewComment)==0 ){ |
| 2381 | db_multi_exec("REPLACE INTO newtags VALUES('comment','+',%Q)", |
| 2382 | zNewComment); |
| 2383 | } |
| 2384 | if( fossil_strcmp(zDate,zNewDate)!=0 ){ |
| 2385 | db_multi_exec("REPLACE INTO newtags VALUES('date','+',%Q)", |
| 2386 | zNewDate); |
| 2387 | } |
| 2388 | if( fossil_strcmp(zUser,zNewUser)!=0 ){ |
| 2389 | db_multi_exec("REPLACE INTO newtags VALUES('user','+',%Q)", zNewUser); |
| 2390 | } |
| 2391 | db_prepare(&q, |
| 2392 | "SELECT tag.tagid, tagname FROM tagxref, tag" |
| 2393 | " WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid", |
| 2394 | rid |
| 2395 | ); |
| @@ -2396,65 +2494,18 @@ | |
| 2396 | while( db_step(&q)==SQLITE_ROW ){ |
| 2397 | int tagid = db_column_int(&q, 0); |
| 2398 | const char *zTag = db_column_text(&q, 1); |
| 2399 | char zLabel[30]; |
| 2400 | sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid); |
| 2401 | if( P(zLabel) ){ |
| 2402 | db_multi_exec("REPLACE INTO newtags VALUES(%Q,'-',NULL)", zTag); |
| 2403 | } |
| 2404 | } |
| 2405 | db_finalize(&q); |
| 2406 | if( zHideFlag[0] ){ |
| 2407 | db_multi_exec("REPLACE INTO newtags VALUES('hidden','*',NULL)"); |
| 2408 | } |
| 2409 | if( zCloseFlag[0] ){ |
| 2410 | db_multi_exec("REPLACE INTO newtags VALUES('closed','%s',NULL)", |
| 2411 | is_a_leaf(rid)?"+":"*"); |
| 2412 | } |
| 2413 | if( zNewTagFlag[0] && zNewTag[0] ){ |
| 2414 | db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag); |
| 2415 | } |
| 2416 | if( zNewBrFlag[0] && zNewBranch[0] ){ |
| 2417 | db_multi_exec( |
| 2418 | "REPLACE INTO newtags " |
| 2419 | " SELECT tagname, '-', NULL FROM tagxref, tag" |
| 2420 | " WHERE tagxref.rid=%d AND tagtype==2" |
| 2421 | " AND tagname GLOB 'sym-*'" |
| 2422 | " AND tag.tagid=tagxref.tagid", |
| 2423 | rid |
| 2424 | ); |
| 2425 | db_multi_exec("REPLACE INTO newtags VALUES('branch','*',%Q)", zNewBranch); |
| 2426 | db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','*',NULL)", |
| 2427 | zNewBranch); |
| 2428 | } |
| 2429 | db_prepare(&q, "SELECT tag, prefix, value FROM newtags" |
| 2430 | " ORDER BY prefix || tag"); |
| 2431 | while( db_step(&q)==SQLITE_ROW ){ |
| 2432 | const char *zTag = db_column_text(&q, 0); |
| 2433 | const char *zPrefix = db_column_text(&q, 1); |
| 2434 | const char *zValue = db_column_text(&q, 2); |
| 2435 | nChng++; |
| 2436 | if( zValue ){ |
| 2437 | blob_appendf(&ctrl, "T %s%F %s %F\n", zPrefix, zTag, zUuid, zValue); |
| 2438 | }else{ |
| 2439 | blob_appendf(&ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); |
| 2440 | } |
| 2441 | } |
| 2442 | db_finalize(&q); |
| 2443 | if( nChng>0 ){ |
| 2444 | int nrid; |
| 2445 | Blob cksum; |
| 2446 | blob_appendf(&ctrl, "U %F\n", login_name()); |
| 2447 | md5sum_blob(&ctrl, &cksum); |
| 2448 | blob_appendf(&ctrl, "Z %b\n", &cksum); |
| 2449 | db_begin_transaction(); |
| 2450 | g.markPrivate = content_is_private(rid); |
| 2451 | nrid = content_put(&ctrl); |
| 2452 | manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS); |
| 2453 | assert( blob_is_reset(&ctrl) ); |
| 2454 | db_end_transaction(0); |
| 2455 | } |
| 2456 | cgi_redirectf("ci?name=%s", zUuid); |
| 2457 | } |
| 2458 | blob_zero(&comment); |
| 2459 | blob_append(&comment, zNewComment, -1); |
| 2460 | zUuid[10] = 0; |
| @@ -2652,5 +2703,110 @@ | |
| 2652 | @ </td></tr> |
| 2653 | @ </table> |
| 2654 | @ </div></form> |
| 2655 | style_footer(); |
| 2656 | } |
| 2657 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2276,10 +2276,125 @@ | |
| 2276 | } |
| 2277 | while( fossil_isspace(zB[0]) ) zB++; |
| 2278 | while( fossil_isspace(zA[0]) ) zA++; |
| 2279 | return zA[0]==0 && zB[0]==0; |
| 2280 | } |
| 2281 | |
| 2282 | /* |
| 2283 | ** The following methods operate on the newtags temporary table |
| 2284 | ** that is used to collect various changes to be added to a control |
| 2285 | ** artifact for a check-in edit. |
| 2286 | */ |
| 2287 | static void init_newtags(void){ |
| 2288 | db_multi_exec("CREATE TEMP TABLE newtags(tag UNIQUE, prefix, value)"); |
| 2289 | } |
| 2290 | |
| 2291 | static void change_special( |
| 2292 | const char *zName, /* Name of the special tag */ |
| 2293 | const char *zOp, /* Operation prefix (e.g. +,-,*) */ |
| 2294 | const char *zValue /* Value of the tag */ |
| 2295 | ){ |
| 2296 | db_multi_exec("REPLACE INTO newtags VALUES(%Q,'%q',%Q)", zName, zOp, zValue); |
| 2297 | } |
| 2298 | |
| 2299 | static void change_sym_tag(const char *zTag, const char *zOp){ |
| 2300 | db_multi_exec("REPLACE INTO newtags VALUES('sym-%q',%Q,NULL)", zTag, zOp); |
| 2301 | } |
| 2302 | |
| 2303 | static void cancel_special(const char *zTag){ |
| 2304 | change_special(zTag,"-",0); |
| 2305 | } |
| 2306 | |
| 2307 | static void add_color(const char *zNewColor, int fPropagateColor){ |
| 2308 | change_special("bgcolor",fPropagateColor ? "*" : "+", zNewColor); |
| 2309 | } |
| 2310 | |
| 2311 | static void cancel_color(void){ |
| 2312 | change_special("color","-",0); |
| 2313 | } |
| 2314 | |
| 2315 | static void add_comment(const char *zNewComment){ |
| 2316 | change_special("comment","+",zNewComment); |
| 2317 | } |
| 2318 | |
| 2319 | static void add_date(const char *zNewDate){ |
| 2320 | change_special("date","+",zNewDate); |
| 2321 | } |
| 2322 | |
| 2323 | static void add_user(const char *zNewUser){ |
| 2324 | change_special("user","+",zNewUser); |
| 2325 | } |
| 2326 | |
| 2327 | static void add_tag(const char *zNewTag){ |
| 2328 | change_sym_tag(zNewTag,"+"); |
| 2329 | } |
| 2330 | |
| 2331 | static void cancel_tag(int rid, const char *zCancelTag){ |
| 2332 | if( db_exists("SELECT 1 FROM tagxref, tag" |
| 2333 | " WHERE tagxref.rid=%d AND tagtype>0" |
| 2334 | " AND tagxref.tagid=tag.tagid AND tagname='sym-%q'", |
| 2335 | rid, zCancelTag) |
| 2336 | ) change_sym_tag(zCancelTag,"-"); |
| 2337 | } |
| 2338 | |
| 2339 | static void hide_branch(void){ |
| 2340 | change_special("hidden","*",0); |
| 2341 | } |
| 2342 | |
| 2343 | static void close_leaf(int rid){ |
| 2344 | change_special("closed",is_a_leaf(rid)?"+":"*",0); |
| 2345 | } |
| 2346 | |
| 2347 | static void change_branch(int rid, const char *zNewBranch){ |
| 2348 | db_multi_exec( |
| 2349 | "REPLACE INTO newtags " |
| 2350 | " SELECT tagname, '-', NULL FROM tagxref, tag" |
| 2351 | " WHERE tagxref.rid=%d AND tagtype==2" |
| 2352 | " AND tagname GLOB 'sym-*'" |
| 2353 | " AND tag.tagid=tagxref.tagid", |
| 2354 | rid |
| 2355 | ); |
| 2356 | change_special("branch","*",zNewBranch); |
| 2357 | change_sym_tag(zNewBranch,"*"); |
| 2358 | } |
| 2359 | |
| 2360 | /* |
| 2361 | ** The apply_newtags method is called after all newtags have been added |
| 2362 | ** and the control artifact is completed and then written to the DB. |
| 2363 | */ |
| 2364 | static void apply_newtags(Blob *ctrl, int rid, const char *zUuid){ |
| 2365 | Stmt q; |
| 2366 | int nChng = 0; |
| 2367 | |
| 2368 | db_prepare(&q, "SELECT tag, prefix, value FROM newtags" |
| 2369 | " ORDER BY prefix || tag"); |
| 2370 | while( db_step(&q)==SQLITE_ROW ){ |
| 2371 | const char *zTag = db_column_text(&q, 0); |
| 2372 | const char *zPrefix = db_column_text(&q, 1); |
| 2373 | const char *zValue = db_column_text(&q, 2); |
| 2374 | nChng++; |
| 2375 | if( zValue ){ |
| 2376 | blob_appendf(ctrl, "T %s%F %s %F\n", zPrefix, zTag, zUuid, zValue); |
| 2377 | }else{ |
| 2378 | blob_appendf(ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); |
| 2379 | } |
| 2380 | } |
| 2381 | db_finalize(&q); |
| 2382 | if( nChng>0 ){ |
| 2383 | int nrid; |
| 2384 | Blob cksum; |
| 2385 | blob_appendf(ctrl, "U %F\n", login_name()); |
| 2386 | md5sum_blob(ctrl, &cksum); |
| 2387 | blob_appendf(ctrl, "Z %b\n", &cksum); |
| 2388 | db_begin_transaction(); |
| 2389 | g.markPrivate = content_is_private(rid); |
| 2390 | nrid = content_put(ctrl); |
| 2391 | manifest_crosslink(nrid, ctrl, MC_PERMIT_HOOKS); |
| 2392 | assert( blob_is_reset(ctrl) ); |
| 2393 | db_end_transaction(0); |
| 2394 | } |
| 2395 | } |
| 2396 | |
| 2397 | /* |
| 2398 | ** WEBPAGE: ci_edit |
| 2399 | ** URL: /ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER |
| 2400 | ** |
| @@ -2360,36 +2475,19 @@ | |
| 2475 | |
| 2476 | login_verify_csrf_secret(); |
| 2477 | blob_zero(&ctrl); |
| 2478 | zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); |
| 2479 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 2480 | init_newtags(); |
| 2481 | if( zNewColor[0] |
| 2482 | && (fPropagateColor!=fNewPropagateColor |
| 2483 | || fossil_strcmp(zColor,zNewColor)!=0) |
| 2484 | ) add_color(zNewColor,fNewPropagateColor); |
| 2485 | if( zNewColor[0]==0 && zColor[0]!=0 ) cancel_color(); |
| 2486 | if( comment_compare(zComment,zNewComment)==0 ) add_comment(zNewComment); |
| 2487 | if( fossil_strcmp(zDate,zNewDate)!=0 ) add_date(zNewDate); |
| 2488 | if( fossil_strcmp(zUser,zNewUser)!=0 ) add_user(zNewUser); |
| 2489 | db_prepare(&q, |
| 2490 | "SELECT tag.tagid, tagname FROM tagxref, tag" |
| 2491 | " WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid", |
| 2492 | rid |
| 2493 | ); |
| @@ -2396,65 +2494,18 @@ | |
| 2494 | while( db_step(&q)==SQLITE_ROW ){ |
| 2495 | int tagid = db_column_int(&q, 0); |
| 2496 | const char *zTag = db_column_text(&q, 1); |
| 2497 | char zLabel[30]; |
| 2498 | sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid); |
| 2499 | if( P(zLabel) ) cancel_special(zTag); |
| 2500 | } |
| 2501 | db_finalize(&q); |
| 2502 | if( zHideFlag[0] ) hide_branch(); |
| 2503 | if( zCloseFlag[0] ) close_leaf(rid); |
| 2504 | if( zNewTagFlag[0] && zNewTag[0] ) add_tag(zNewTag); |
| 2505 | if( zNewBrFlag[0] && zNewBranch[0] ) change_branch(rid,zNewBranch); |
| 2506 | apply_newtags(&ctrl, rid, zUuid); |
| 2507 | cgi_redirectf("ci?name=%s", zUuid); |
| 2508 | } |
| 2509 | blob_zero(&comment); |
| 2510 | blob_append(&comment, zNewComment, -1); |
| 2511 | zUuid[10] = 0; |
| @@ -2652,5 +2703,110 @@ | |
| 2703 | @ </td></tr> |
| 2704 | @ </table> |
| 2705 | @ </div></form> |
| 2706 | style_footer(); |
| 2707 | } |
| 2708 | |
| 2709 | /* |
| 2710 | ** COMMAND: edit |
| 2711 | ** |
| 2712 | ** Usage: %fossil edit UUID ?OPTIONS? |
| 2713 | ** |
| 2714 | ** Options: |
| 2715 | ** |
| 2716 | ** --euser USER Make USER the check-in user |
| 2717 | ** --comment COMMENT Make COMMENT the check-in comment |
| 2718 | ** --date DATE Make DATE the check-in time |
| 2719 | ** --bgcolor COLOR Apply COLOR to this check-in |
| 2720 | ** --branchcolor COLOR Apply COLOR to the branch |
| 2721 | ** --tag TAG Add new TAG to this check-in |
| 2722 | ** --cancel TAG Cancel TAG from this check-in |
| 2723 | ** --branch NAME Make this check-in the start of branch NAME |
| 2724 | ** --hide Hide branch starting from this check-in |
| 2725 | ** --close Mark this "leaf" as closed |
| 2726 | */ |
| 2727 | void ci_edit_cmd(void){ |
| 2728 | int rid; |
| 2729 | const char *zComment; /* Current comment on the check-in */ |
| 2730 | const char *zNewComment; /* Revised check-in comment */ |
| 2731 | const char *zUser; /* Current user for the check-in */ |
| 2732 | const char *zNewUser; /* Revised user */ |
| 2733 | const char *zDate; /* Current date of the check-in */ |
| 2734 | const char *zNewDate; /* Revised check-in date */ |
| 2735 | const char *zColor; |
| 2736 | const char *zNewColor; |
| 2737 | const char *zNewBrColor; |
| 2738 | const char *zNewTag; |
| 2739 | const char *zNewBranch; |
| 2740 | const char *zCancelTag; |
| 2741 | int fClose; /* True if leaf should be closed */ |
| 2742 | int fHide; /* True if branch should be hidden */ |
| 2743 | int fPropagateColor; /* True if color propagates before edit */ |
| 2744 | int fNewPropagateColor = 0; /* True if color propagates after edit */ |
| 2745 | const char *zChngTime; /* The change time on the control artifact */ |
| 2746 | const char *zUuid; |
| 2747 | Blob ctrl; |
| 2748 | char *zNow; |
| 2749 | |
| 2750 | if( g.argc<3 ) usage("UUID ?OPTIONS?"); |
| 2751 | zNewComment = find_option("comment",0,1); |
| 2752 | zNewBranch = find_option("branch",0,1); |
| 2753 | zNewColor = find_option("bgcolor",0,1); |
| 2754 | zNewBrColor = find_option("branchcolor",0,1); |
| 2755 | if( zNewBrColor ){ |
| 2756 | zNewColor = zNewBrColor; |
| 2757 | fNewPropagateColor = 1; |
| 2758 | } |
| 2759 | zNewDate = find_option("date",0,1); |
| 2760 | zNewUser = find_option("euser",0,1); |
| 2761 | zNewTag = find_option("tag",0,1); |
| 2762 | zCancelTag = find_option("cancel",0,1); |
| 2763 | fClose = find_option("close",0,0)!=0; |
| 2764 | fHide = find_option("hide",0,0)!=0; |
| 2765 | zChngTime = find_option("chngtime",0,1); |
| 2766 | db_find_and_open_repository(0,0); |
| 2767 | user_select(); |
| 2768 | verify_all_options(); |
| 2769 | rid = name_to_typed_rid(g.argv[2], "ci"); |
| 2770 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 2771 | zComment = db_text(0, "SELECT coalesce(ecomment,comment)" |
| 2772 | " FROM event WHERE objid=%d", rid); |
| 2773 | if( zComment==0 || zComment[0]==0 ) fossil_fatal("No comment on rid %d", rid); |
| 2774 | zUser = db_text(0, "SELECT coalesce(euser,user)" |
| 2775 | " FROM event WHERE objid=%d", rid); |
| 2776 | if( zUser==0 || zUser[0]==0 ) fossil_fatal("No user on rid %d", rid); |
| 2777 | zDate = db_text(0, "SELECT datetime(mtime)" |
| 2778 | " FROM event WHERE objid=%d", rid); |
| 2779 | if( zDate==0 || zDate[0]==0 ) fossil_fatal("No date on rid %d", rid); |
| 2780 | zColor = db_text("", "SELECT bgcolor" |
| 2781 | " FROM event WHERE objid=%d", rid); |
| 2782 | fPropagateColor = db_int(0, "SELECT tagtype FROM tagxref" |
| 2783 | " WHERE rid=%d AND tagid=%d", |
| 2784 | rid, TAG_BGCOLOR)==2; |
| 2785 | fNewPropagateColor = zNewColor && zNewColor[0] |
| 2786 | ? fNewPropagateColor : fPropagateColor; |
| 2787 | blob_zero(&ctrl); |
| 2788 | zNow = date_in_standard_format(zChngTime && zChngTime[0] ? zChngTime : "now"); |
| 2789 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 2790 | init_newtags(); |
| 2791 | if( zNewColor && zNewColor[0] |
| 2792 | && (fPropagateColor!=fNewPropagateColor |
| 2793 | || fossil_strcmp(zColor,zNewColor)!=0) |
| 2794 | ) add_color(zNewColor,fNewPropagateColor); |
| 2795 | if( (zNewColor!=0 && zNewColor[0]==0) && (zColor && zColor[0] ) ){ |
| 2796 | cancel_color(); |
| 2797 | } |
| 2798 | if( zNewComment && zNewComment[0] |
| 2799 | && comment_compare(zComment,zNewComment)==0 ) add_comment(zNewComment); |
| 2800 | if( zNewDate && zNewDate[0] && fossil_strcmp(zDate,zNewDate)!=0 ){ |
| 2801 | add_date(zNewDate); |
| 2802 | } |
| 2803 | if( zNewUser && zNewUser[0] && fossil_strcmp(zUser,zNewUser)!=0 ){ |
| 2804 | add_user(zNewUser); |
| 2805 | } |
| 2806 | if( zNewTag && zNewTag[0] ) add_tag(zNewTag); |
| 2807 | if( zCancelTag && zCancelTag[0] ) cancel_tag(rid,zCancelTag); |
| 2808 | if( fHide ) hide_branch(); |
| 2809 | if( fClose ) close_leaf(rid); |
| 2810 | if( zNewBranch && zNewBranch[0] ) change_branch(rid,zNewBranch); |
| 2811 | apply_newtags(&ctrl, rid, zUuid); |
| 2812 | } |
| 2813 |