Fossil SCM
Initial impl of (branch close) subcommand.
Commit
0bdb19f3d333268866bab9a30e221b6489df70fedc5d38be909bdd56c9a61660
Parent
8a231a7990198d2…
1 file changed
+101
-1
+101
-1
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -344,10 +344,92 @@ | ||
| 344 | 344 | " AND ox.rid=ix.rid)", |
| 345 | 345 | TAG_BRANCH, zBrName, TAG_CLOSED |
| 346 | 346 | ); |
| 347 | 347 | } |
| 348 | 348 | |
| 349 | +/* | |
| 350 | +** Implementation of (branch close) subcommand. nStartAtArg is the | |
| 351 | +** g.argv index to start reading branch names. If fDryRun is true then | |
| 352 | +** the change is run in dry-run mode. Fails fatally on error. | |
| 353 | +*/ | |
| 354 | +static void branch_cmd_close(int nStartAtArg, int fVerbose, int fDryRun){ | |
| 355 | + int argPos = nStartAtArg; | |
| 356 | + Blob manifest = empty_blob; /* Control artifact */ | |
| 357 | + Stmt q = empty_Stmt; | |
| 358 | + int nQueued = 0; /* # of branches queued for closing */ | |
| 359 | + char * zUuid = 0; | |
| 360 | + int doRollback = fDryRun!=0; | |
| 361 | + db_begin_transaction(); | |
| 362 | + db_multi_exec("create temp table brclose(" | |
| 363 | + "rid INTEGER UNIQUE ON CONFLICT IGNORE" | |
| 364 | + ")"); | |
| 365 | + db_prepare(&q, "INSERT INTO brclose(rid) " | |
| 366 | + "VALUES(:rid)"); | |
| 367 | + for( ; argPos < g.argc; fossil_free(zUuid), ++argPos ){ | |
| 368 | + const char * zBranch = g.argv[argPos]; | |
| 369 | + const int rid = name_to_uuid2(zBranch, "ci", &zUuid); | |
| 370 | + if(0==rid){ | |
| 371 | + fossil_fatal("Cannot resolve branch name: %s", zBranch); | |
| 372 | + }else if(rid<0){ | |
| 373 | + fossil_fatal("Ambiguous branch name: %s", zBranch); | |
| 374 | + }else if(!is_a_leaf(rid)){ | |
| 375 | + fossil_warning("Skipping non-leaf [%s] %s", zBranch, zUuid); | |
| 376 | + continue; | |
| 377 | + }else if(leaf_is_closed(rid)){ | |
| 378 | + fossil_warning("Skipping closed [%s] %s", zBranch, zUuid); | |
| 379 | + continue; | |
| 380 | + } | |
| 381 | + ++nQueued; | |
| 382 | + db_bind_int(&q, ":rid", rid); | |
| 383 | + db_step(&q); | |
| 384 | + db_reset(&q); | |
| 385 | + if(fVerbose!=0){ | |
| 386 | + fossil_print("Closing branch [%s] %s\n", zBranch, zUuid); | |
| 387 | + } | |
| 388 | + } | |
| 389 | + db_finalize(&q); | |
| 390 | + if(!nQueued){ | |
| 391 | + fossil_warning("No branches queued for closing. Nothing to do."); | |
| 392 | + doRollback = 1; | |
| 393 | + goto br_close_end; | |
| 394 | + } | |
| 395 | + blob_appendf(&manifest, "D %z\n", date_in_standard_format("now")); | |
| 396 | + db_prepare(&q, "SELECT b.uuid " | |
| 397 | + "FROM brclose c, blob b " | |
| 398 | + "WHERE c.rid=b.rid " | |
| 399 | + "ORDER BY b.uuid"); | |
| 400 | + while(SQLITE_ROW==db_step(&q)){ | |
| 401 | + const char * zHash = db_column_text(&q, 0); | |
| 402 | + blob_appendf(&manifest, "T +closed %s\n", zHash); | |
| 403 | + } | |
| 404 | + user_select(); | |
| 405 | + blob_appendf(&manifest, "U %F\n", login_name()); | |
| 406 | + db_finalize(&q); | |
| 407 | + { | |
| 408 | + Blob cksum = empty_blob; | |
| 409 | + md5sum_blob(&manifest, &cksum); | |
| 410 | + blob_appendf(&manifest, "Z %b\n", &cksum); | |
| 411 | + blob_reset(&cksum); | |
| 412 | + } | |
| 413 | + if(fDryRun){ | |
| 414 | + fossil_print("Dry-run mode. Not saving control artifact:\n%b", | |
| 415 | + &manifest); | |
| 416 | + }else{ | |
| 417 | + const int newRid = content_put(&manifest); | |
| 418 | + if(0==newRid){ | |
| 419 | + fossil_fatal("Problem saving new manifest: %s\n%b", | |
| 420 | + g.zErrMsg, &manifest); | |
| 421 | + }else if(manifest_crosslink(newRid, &manifest, 0)==0){ | |
| 422 | + fossil_fatal("Crosslinking error: %s", g.zErrMsg); | |
| 423 | + } | |
| 424 | + fossil_print("Saved new control artifact (RID %d)\n", newRid); | |
| 425 | + } | |
| 426 | + blob_reset(&manifest); | |
| 427 | + br_close_end: | |
| 428 | + db_multi_exec("DROP TABLE brclose"); | |
| 429 | + db_end_transaction(doRollback); | |
| 430 | +} | |
| 349 | 431 | |
| 350 | 432 | /* |
| 351 | 433 | ** COMMAND: branch |
| 352 | 434 | ** |
| 353 | 435 | ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? |
| @@ -390,10 +472,20 @@ | ||
| 390 | 472 | ** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in |
| 391 | 473 | ** year-month-day form, it may be truncated, the "T" may be |
| 392 | 474 | ** replaced by a space, and it may also name a timezone offset |
| 393 | 475 | ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). |
| 394 | 476 | ** Either no timezone suffix or "Z" means UTC. |
| 477 | +** | |
| 478 | +** > fossil branch close ?OPTIONS? BRANCH-NAME ?...BRANCH-NAMES? | |
| 479 | +** | |
| 480 | +** Close one or more branches by adding the "closed" tag | |
| 481 | +** to them. It accepts arbitrary unambiguous symbolic names but | |
| 482 | +** will only resolve checkin names and skips any which resolve | |
| 483 | +** to non-leaf or closed checkins. Options: | |
| 484 | +** -n|--dry-run do not commit changes and dump artifact | |
| 485 | +** to stdout | |
| 486 | +** -v|--verbose output more information | |
| 395 | 487 | ** |
| 396 | 488 | ** Options valid for all subcommands: |
| 397 | 489 | ** |
| 398 | 490 | ** -R|--repository REPO Run commands on repository REPO |
| 399 | 491 | */ |
| @@ -452,13 +544,21 @@ | ||
| 452 | 544 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 453 | 545 | } |
| 454 | 546 | db_finalize(&q); |
| 455 | 547 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 456 | 548 | branch_new(); |
| 549 | + }else if( strncmp(zCmd,"close",5)==0 ){ | |
| 550 | + const int fDryRun = find_option("dry-run","n",0)!=0; | |
| 551 | + const int fVerbose = find_option("verbose","v",0)!=0; | |
| 552 | + verify_all_options(); | |
| 553 | + if(g.argc<4){ | |
| 554 | + usage("branch close branch-name(s)..."); | |
| 555 | + } | |
| 556 | + branch_cmd_close(3, fVerbose, fDryRun); | |
| 457 | 557 | }else{ |
| 458 | 558 | fossil_fatal("branch subcommand should be one of: " |
| 459 | - "current info list ls new"); | |
| 559 | + "close current info list ls new"); | |
| 460 | 560 | } |
| 461 | 561 | } |
| 462 | 562 | |
| 463 | 563 | /* |
| 464 | 564 | ** This is the new-style branch-list page that shows the branch names |
| 465 | 565 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -344,10 +344,92 @@ | |
| 344 | " AND ox.rid=ix.rid)", |
| 345 | TAG_BRANCH, zBrName, TAG_CLOSED |
| 346 | ); |
| 347 | } |
| 348 | |
| 349 | |
| 350 | /* |
| 351 | ** COMMAND: branch |
| 352 | ** |
| 353 | ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? |
| @@ -390,10 +472,20 @@ | |
| 390 | ** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in |
| 391 | ** year-month-day form, it may be truncated, the "T" may be |
| 392 | ** replaced by a space, and it may also name a timezone offset |
| 393 | ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). |
| 394 | ** Either no timezone suffix or "Z" means UTC. |
| 395 | ** |
| 396 | ** Options valid for all subcommands: |
| 397 | ** |
| 398 | ** -R|--repository REPO Run commands on repository REPO |
| 399 | */ |
| @@ -452,13 +544,21 @@ | |
| 452 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 453 | } |
| 454 | db_finalize(&q); |
| 455 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 456 | branch_new(); |
| 457 | }else{ |
| 458 | fossil_fatal("branch subcommand should be one of: " |
| 459 | "current info list ls new"); |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | /* |
| 464 | ** This is the new-style branch-list page that shows the branch names |
| 465 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -344,10 +344,92 @@ | |
| 344 | " AND ox.rid=ix.rid)", |
| 345 | TAG_BRANCH, zBrName, TAG_CLOSED |
| 346 | ); |
| 347 | } |
| 348 | |
| 349 | /* |
| 350 | ** Implementation of (branch close) subcommand. nStartAtArg is the |
| 351 | ** g.argv index to start reading branch names. If fDryRun is true then |
| 352 | ** the change is run in dry-run mode. Fails fatally on error. |
| 353 | */ |
| 354 | static void branch_cmd_close(int nStartAtArg, int fVerbose, int fDryRun){ |
| 355 | int argPos = nStartAtArg; |
| 356 | Blob manifest = empty_blob; /* Control artifact */ |
| 357 | Stmt q = empty_Stmt; |
| 358 | int nQueued = 0; /* # of branches queued for closing */ |
| 359 | char * zUuid = 0; |
| 360 | int doRollback = fDryRun!=0; |
| 361 | db_begin_transaction(); |
| 362 | db_multi_exec("create temp table brclose(" |
| 363 | "rid INTEGER UNIQUE ON CONFLICT IGNORE" |
| 364 | ")"); |
| 365 | db_prepare(&q, "INSERT INTO brclose(rid) " |
| 366 | "VALUES(:rid)"); |
| 367 | for( ; argPos < g.argc; fossil_free(zUuid), ++argPos ){ |
| 368 | const char * zBranch = g.argv[argPos]; |
| 369 | const int rid = name_to_uuid2(zBranch, "ci", &zUuid); |
| 370 | if(0==rid){ |
| 371 | fossil_fatal("Cannot resolve branch name: %s", zBranch); |
| 372 | }else if(rid<0){ |
| 373 | fossil_fatal("Ambiguous branch name: %s", zBranch); |
| 374 | }else if(!is_a_leaf(rid)){ |
| 375 | fossil_warning("Skipping non-leaf [%s] %s", zBranch, zUuid); |
| 376 | continue; |
| 377 | }else if(leaf_is_closed(rid)){ |
| 378 | fossil_warning("Skipping closed [%s] %s", zBranch, zUuid); |
| 379 | continue; |
| 380 | } |
| 381 | ++nQueued; |
| 382 | db_bind_int(&q, ":rid", rid); |
| 383 | db_step(&q); |
| 384 | db_reset(&q); |
| 385 | if(fVerbose!=0){ |
| 386 | fossil_print("Closing branch [%s] %s\n", zBranch, zUuid); |
| 387 | } |
| 388 | } |
| 389 | db_finalize(&q); |
| 390 | if(!nQueued){ |
| 391 | fossil_warning("No branches queued for closing. Nothing to do."); |
| 392 | doRollback = 1; |
| 393 | goto br_close_end; |
| 394 | } |
| 395 | blob_appendf(&manifest, "D %z\n", date_in_standard_format("now")); |
| 396 | db_prepare(&q, "SELECT b.uuid " |
| 397 | "FROM brclose c, blob b " |
| 398 | "WHERE c.rid=b.rid " |
| 399 | "ORDER BY b.uuid"); |
| 400 | while(SQLITE_ROW==db_step(&q)){ |
| 401 | const char * zHash = db_column_text(&q, 0); |
| 402 | blob_appendf(&manifest, "T +closed %s\n", zHash); |
| 403 | } |
| 404 | user_select(); |
| 405 | blob_appendf(&manifest, "U %F\n", login_name()); |
| 406 | db_finalize(&q); |
| 407 | { |
| 408 | Blob cksum = empty_blob; |
| 409 | md5sum_blob(&manifest, &cksum); |
| 410 | blob_appendf(&manifest, "Z %b\n", &cksum); |
| 411 | blob_reset(&cksum); |
| 412 | } |
| 413 | if(fDryRun){ |
| 414 | fossil_print("Dry-run mode. Not saving control artifact:\n%b", |
| 415 | &manifest); |
| 416 | }else{ |
| 417 | const int newRid = content_put(&manifest); |
| 418 | if(0==newRid){ |
| 419 | fossil_fatal("Problem saving new manifest: %s\n%b", |
| 420 | g.zErrMsg, &manifest); |
| 421 | }else if(manifest_crosslink(newRid, &manifest, 0)==0){ |
| 422 | fossil_fatal("Crosslinking error: %s", g.zErrMsg); |
| 423 | } |
| 424 | fossil_print("Saved new control artifact (RID %d)\n", newRid); |
| 425 | } |
| 426 | blob_reset(&manifest); |
| 427 | br_close_end: |
| 428 | db_multi_exec("DROP TABLE brclose"); |
| 429 | db_end_transaction(doRollback); |
| 430 | } |
| 431 | |
| 432 | /* |
| 433 | ** COMMAND: branch |
| 434 | ** |
| 435 | ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? |
| @@ -390,10 +472,20 @@ | |
| 472 | ** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in |
| 473 | ** year-month-day form, it may be truncated, the "T" may be |
| 474 | ** replaced by a space, and it may also name a timezone offset |
| 475 | ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). |
| 476 | ** Either no timezone suffix or "Z" means UTC. |
| 477 | ** |
| 478 | ** > fossil branch close ?OPTIONS? BRANCH-NAME ?...BRANCH-NAMES? |
| 479 | ** |
| 480 | ** Close one or more branches by adding the "closed" tag |
| 481 | ** to them. It accepts arbitrary unambiguous symbolic names but |
| 482 | ** will only resolve checkin names and skips any which resolve |
| 483 | ** to non-leaf or closed checkins. Options: |
| 484 | ** -n|--dry-run do not commit changes and dump artifact |
| 485 | ** to stdout |
| 486 | ** -v|--verbose output more information |
| 487 | ** |
| 488 | ** Options valid for all subcommands: |
| 489 | ** |
| 490 | ** -R|--repository REPO Run commands on repository REPO |
| 491 | */ |
| @@ -452,13 +544,21 @@ | |
| 544 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 545 | } |
| 546 | db_finalize(&q); |
| 547 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 548 | branch_new(); |
| 549 | }else if( strncmp(zCmd,"close",5)==0 ){ |
| 550 | const int fDryRun = find_option("dry-run","n",0)!=0; |
| 551 | const int fVerbose = find_option("verbose","v",0)!=0; |
| 552 | verify_all_options(); |
| 553 | if(g.argc<4){ |
| 554 | usage("branch close branch-name(s)..."); |
| 555 | } |
| 556 | branch_cmd_close(3, fVerbose, fDryRun); |
| 557 | }else{ |
| 558 | fossil_fatal("branch subcommand should be one of: " |
| 559 | "close current info list ls new"); |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | /* |
| 564 | ** This is the new-style branch-list page that shows the branch names |
| 565 |