| | @@ -328,10 +328,41 @@ |
| 328 | 328 | glob_free(pIgnore); |
| 329 | 329 | glob_free(pClean); |
| 330 | 330 | |
| 331 | 331 | add_files_in_sfile(vid); |
| 332 | 332 | db_end_transaction(0); |
| 333 | + |
| 334 | +} |
| 335 | + |
| 336 | +static void init_files_to_remove(){ |
| 337 | + db_multi_exec("CREATE TEMP TABLE fremove(x TEXT PRIMARY KEY %s)", |
| 338 | + filename_collation()); |
| 339 | +} |
| 340 | + |
| 341 | +static void add_file_to_remove( |
| 342 | + const char *zOldName /* The old name of the file on disk. */ |
| 343 | +){ |
| 344 | + Blob fullOldName; |
| 345 | + file_canonical_name(zOldName, &fullOldName, 0); |
| 346 | + db_multi_exec("INSERT INTO fremove VALUES('%q');", blob_str(&fullOldName)); |
| 347 | + blob_reset(&fullOldName); |
| 348 | +} |
| 349 | + |
| 350 | +static void process_files_to_remove( |
| 351 | + int dryRunFlag /* Non-zero to actually operate on the file-system. */ |
| 352 | +){ |
| 353 | + Stmt remove; |
| 354 | + db_prepare(&remove, "SELECT x FROM fremove ORDER BY x;"); |
| 355 | + while( db_step(&remove)==SQLITE_ROW ){ |
| 356 | + const char *zOldName = db_column_text(&remove, 0); |
| 357 | + fossil_print("REMOVED %s\n", zOldName); |
| 358 | + if( !dryRunFlag ){ |
| 359 | + file_delete(zOldName); |
| 360 | + } |
| 361 | + } |
| 362 | + db_finalize(&remove); |
| 363 | + db_multi_exec("DROP TABLE fremove;"); |
| 333 | 364 | } |
| 334 | 365 | |
| 335 | 366 | /* |
| 336 | 367 | ** COMMAND: rm |
| 337 | 368 | ** COMMAND: delete* |
| | @@ -350,17 +381,23 @@ |
| 350 | 381 | ** |
| 351 | 382 | ** See also: addremove, add |
| 352 | 383 | */ |
| 353 | 384 | void delete_cmd(void){ |
| 354 | 385 | int i; |
| 386 | + int removeFiles; |
| 387 | + int dryRunFlag; |
| 355 | 388 | Stmt loop; |
| 389 | + |
| 390 | + dryRunFlag = find_option("dry-run","n",0)!=0; |
| 356 | 391 | |
| 357 | 392 | /* We should be done with options.. */ |
| 358 | 393 | verify_all_options(); |
| 359 | 394 | |
| 360 | 395 | db_must_be_within_tree(); |
| 361 | 396 | db_begin_transaction(); |
| 397 | + removeFiles = db_get_boolean("remove-files",0); |
| 398 | + if( removeFiles ) init_files_to_remove(); |
| 362 | 399 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 363 | 400 | filename_collation()); |
| 364 | 401 | for(i=2; i<g.argc; i++){ |
| 365 | 402 | Blob treeName; |
| 366 | 403 | char *zTreeName; |
| | @@ -380,17 +417,21 @@ |
| 380 | 417 | } |
| 381 | 418 | |
| 382 | 419 | db_prepare(&loop, "SELECT x FROM sfile"); |
| 383 | 420 | while( db_step(&loop)==SQLITE_ROW ){ |
| 384 | 421 | fossil_print("DELETED %s\n", db_column_text(&loop, 0)); |
| 422 | + if( removeFiles ) add_file_to_remove(db_column_text(&loop, 0)); |
| 385 | 423 | } |
| 386 | 424 | db_finalize(&loop); |
| 387 | | - db_multi_exec( |
| 388 | | - "UPDATE vfile SET deleted=1 WHERE pathname IN sfile;" |
| 389 | | - "DELETE FROM vfile WHERE rid=0 AND deleted;" |
| 390 | | - ); |
| 425 | + if( !dryRunFlag ){ |
| 426 | + db_multi_exec( |
| 427 | + "UPDATE vfile SET deleted=1 WHERE pathname IN sfile;" |
| 428 | + "DELETE FROM vfile WHERE rid=0 AND deleted;" |
| 429 | + ); |
| 430 | + } |
| 391 | 431 | db_end_transaction(0); |
| 432 | + if( removeFiles ) process_files_to_remove(dryRunFlag); |
| 392 | 433 | } |
| 393 | 434 | |
| 394 | 435 | /* |
| 395 | 436 | ** Capture the command-line --case-sensitive option. |
| 396 | 437 | */ |
| | @@ -586,11 +627,16 @@ |
| 586 | 627 | /* |
| 587 | 628 | ** Rename a single file. |
| 588 | 629 | ** |
| 589 | 630 | ** The original name of the file is zOrig. The new filename is zNew. |
| 590 | 631 | */ |
| 591 | | -static void mv_one_file(int vid, const char *zOrig, const char *zNew){ |
| 632 | +static void mv_one_file( |
| 633 | + int vid, |
| 634 | + const char *zOrig, |
| 635 | + const char *zNew, |
| 636 | + int dryRunFlag |
| 637 | +){ |
| 592 | 638 | int x = db_int(-1, "SELECT deleted FROM vfile WHERE pathname=%Q %s", |
| 593 | 639 | zNew, filename_collation()); |
| 594 | 640 | if( x>=0 ){ |
| 595 | 641 | if( x==0 ){ |
| 596 | 642 | fossil_fatal("cannot rename '%s' to '%s' since another file named '%s'" |
| | @@ -599,14 +645,58 @@ |
| 599 | 645 | fossil_fatal("cannot rename '%s' to '%s' since the delete of '%s' has " |
| 600 | 646 | "not yet been committed", zOrig, zNew, zNew); |
| 601 | 647 | } |
| 602 | 648 | } |
| 603 | 649 | fossil_print("RENAME %s %s\n", zOrig, zNew); |
| 604 | | - db_multi_exec( |
| 605 | | - "UPDATE vfile SET pathname='%q' WHERE pathname='%q' %s AND vid=%d", |
| 606 | | - zNew, zOrig, filename_collation(), vid |
| 607 | | - ); |
| 650 | + if( !dryRunFlag ){ |
| 651 | + db_multi_exec( |
| 652 | + "UPDATE vfile SET pathname='%q' WHERE pathname='%q' %s AND vid=%d", |
| 653 | + zNew, zOrig, filename_collation(), vid |
| 654 | + ); |
| 655 | + } |
| 656 | +} |
| 657 | + |
| 658 | +static void init_files_to_move(){ |
| 659 | + db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS " |
| 660 | + "fmove(x TEXT PRIMARY KEY %s, y TEXT %s)", |
| 661 | + filename_collation(), filename_collation()); |
| 662 | +} |
| 663 | + |
| 664 | +static void add_file_to_move( |
| 665 | + const char *zOldName, /* The old name of the file on disk. */ |
| 666 | + const char *zNewName /* The new name of the file on disk. */ |
| 667 | +){ |
| 668 | + Blob fullOldName; |
| 669 | + Blob fullNewName; |
| 670 | + file_canonical_name(zOldName, &fullOldName, 0); |
| 671 | + file_canonical_name(zNewName, &fullNewName, 0); |
| 672 | + db_multi_exec("INSERT INTO fmove VALUES('%q','%q');", |
| 673 | + blob_str(&fullOldName), blob_str(&fullNewName)); |
| 674 | + blob_reset(&fullNewName); |
| 675 | + blob_reset(&fullOldName); |
| 676 | +} |
| 677 | + |
| 678 | +static void process_files_to_move( |
| 679 | + int dryRunFlag /* Non-zero to actually operate on the file-system. */ |
| 680 | +){ |
| 681 | + Stmt move; |
| 682 | + db_prepare(&move, "SELECT x, y FROM fmove ORDER BY x;"); |
| 683 | + while( db_step(&move)==SQLITE_ROW ){ |
| 684 | + const char *zOldName = db_column_text(&move, 0); |
| 685 | + const char *zNewName = db_column_text(&move, 1); |
| 686 | + fossil_print("MOVED %s %s\n", zOldName, zNewName); |
| 687 | + if( !dryRunFlag ){ |
| 688 | + if( file_wd_islink(zOldName) ){ |
| 689 | + symlink_copy(zOldName, zNewName); |
| 690 | + }else{ |
| 691 | + file_copy(zOldName, zNewName); |
| 692 | + } |
| 693 | + file_delete(zOldName); |
| 694 | + } |
| 695 | + } |
| 696 | + db_finalize(&move); |
| 697 | + db_multi_exec("DROP TABLE fmove;"); |
| 608 | 698 | } |
| 609 | 699 | |
| 610 | 700 | /* |
| 611 | 701 | ** COMMAND: mv |
| 612 | 702 | ** COMMAND: rename* |
| | @@ -627,15 +717,18 @@ |
| 627 | 717 | ** See also: changes, status |
| 628 | 718 | */ |
| 629 | 719 | void mv_cmd(void){ |
| 630 | 720 | int i; |
| 631 | 721 | int vid; |
| 722 | + int moveFiles; |
| 723 | + int dryRunFlag; |
| 632 | 724 | char *zDest; |
| 633 | 725 | Blob dest; |
| 634 | 726 | Stmt q; |
| 635 | 727 | |
| 636 | 728 | db_must_be_within_tree(); |
| 729 | + dryRunFlag = find_option("dry-run","n",0)!=0; |
| 637 | 730 | |
| 638 | 731 | /* We should be done with options.. */ |
| 639 | 732 | verify_all_options(); |
| 640 | 733 | |
| 641 | 734 | vid = db_lget_int("checkout", 0); |
| | @@ -645,10 +738,12 @@ |
| 645 | 738 | if( g.argc<4 ){ |
| 646 | 739 | usage("OLDNAME NEWNAME"); |
| 647 | 740 | } |
| 648 | 741 | zDest = g.argv[g.argc-1]; |
| 649 | 742 | db_begin_transaction(); |
| 743 | + moveFiles = db_get_boolean("move-files",0); |
| 744 | + if( moveFiles ) init_files_to_move(); |
| 650 | 745 | file_tree_name(zDest, &dest, 1); |
| 651 | 746 | db_multi_exec( |
| 652 | 747 | "UPDATE vfile SET origname=pathname WHERE origname IS NULL;" |
| 653 | 748 | ); |
| 654 | 749 | db_multi_exec( |
| | @@ -703,18 +798,20 @@ |
| 703 | 798 | } |
| 704 | 799 | db_prepare(&q, "SELECT f, t FROM mv ORDER BY f"); |
| 705 | 800 | while( db_step(&q)==SQLITE_ROW ){ |
| 706 | 801 | const char *zFrom = db_column_text(&q, 0); |
| 707 | 802 | const char *zTo = db_column_text(&q, 1); |
| 708 | | - mv_one_file(vid, zFrom, zTo); |
| 803 | + mv_one_file(vid, zFrom, zTo, dryRunFlag); |
| 804 | + if( moveFiles ) add_file_to_move(zFrom, zTo); |
| 709 | 805 | } |
| 710 | 806 | db_finalize(&q); |
| 711 | 807 | db_end_transaction(0); |
| 808 | + if( moveFiles ) process_files_to_move(dryRunFlag); |
| 712 | 809 | } |
| 713 | 810 | |
| 714 | 811 | /* |
| 715 | 812 | ** Function for stash_apply to be able to restore a file and indicate |
| 716 | 813 | ** newly ADDED state. |
| 717 | 814 | */ |
| 718 | 815 | int stash_add_files_in_sfile(int vid){ |
| 719 | 816 | return add_files_in_sfile(vid); |
| 720 | 817 | } |
| 721 | 818 | |