| | @@ -644,11 +644,12 @@ |
| 644 | 644 | ** Files and subdirectories whose names begin with "." are automatically |
| 645 | 645 | ** ignored unless the --dotfiles option is used. |
| 646 | 646 | ** |
| 647 | 647 | ** The --verily option ignores the keep-glob and ignore-glob settings |
| 648 | 648 | ** and turns on --force, --dotfiles, and --emptydirs. Use the --verily |
| 649 | | -** option when you really want to clean up everything. |
| 649 | +** option when you really want to clean up everything. Extreme care |
| 650 | +** should be exercised when using the --verily option. |
| 650 | 651 | ** |
| 651 | 652 | ** Options: |
| 652 | 653 | ** --allckouts Check for empty directories within any checkouts |
| 653 | 654 | ** that may be nested within the current one. This |
| 654 | 655 | ** option should be used with great care because the |
| | @@ -657,51 +658,70 @@ |
| 657 | 658 | ** not be checked. |
| 658 | 659 | ** --case-sensitive <BOOL> override case-sensitive setting |
| 659 | 660 | ** --dirsonly Only remove empty directories. No files will |
| 660 | 661 | ** be removed. Using this option will automatically |
| 661 | 662 | ** enable the --emptydirs option as well. |
| 663 | +** --disable-undo WARNING: This option disables use of the undo |
| 664 | +** mechanism for this clean operation and should be |
| 665 | +** used with extreme caution. |
| 662 | 666 | ** --dotfiles Include files beginning with a dot ("."). |
| 663 | 667 | ** --emptydirs Remove any empty directories that are not |
| 664 | 668 | ** explicitly exempted via the empty-dirs setting |
| 665 | 669 | ** or another applicable setting or command line |
| 666 | 670 | ** argument. Matching files, if any, are removed |
| 667 | 671 | ** prior to checking for any empty directories; |
| 668 | 672 | ** therefore, directories that contain only files |
| 669 | 673 | ** that were removed will be removed as well. |
| 670 | 674 | ** -f|--force Remove files without prompting. |
| 671 | | -** -x|--verily Remove everything that is not a managed file or |
| 672 | | -** the repository itself. Implies -f --emptydirs |
| 673 | | -** --dotfiles. Disregard keep-glob and ignore-glob. |
| 674 | | -** --clean <CSG> Never prompt for files matching this |
| 675 | | -** comma separated list of glob patterns. |
| 675 | +** -x|--verily WARNING: Removes everything that is not a managed |
| 676 | +** file or the repository itself. This option |
| 677 | +** implies the --force, --emptydirs, --dotfiles, and |
| 678 | +** --disable-undo options. Furthermore, it completely |
| 679 | +** disregards the keep-glob and ignore-glob settings. |
| 680 | +** However, it does honor the --ignore and --keep |
| 681 | +** options. |
| 682 | +** --clean <CSG> WARNING: Never prompt to delete any files matching |
| 683 | +** this comma separated list of glob patterns. Also, |
| 684 | +** deletions of any files matching this pattern list |
| 685 | +** cannot be undone. |
| 676 | 686 | ** --ignore <CSG> Ignore files matching patterns from the |
| 677 | 687 | ** comma separated list of glob patterns. |
| 678 | 688 | ** --keep <CSG> Keep files matching this comma separated |
| 679 | 689 | ** list of glob patterns. |
| 680 | 690 | ** -n|--dry-run Delete nothing, but display what would have been |
| 681 | 691 | ** deleted. |
| 692 | +** --no-prompt This option disables prompting the user for input |
| 693 | +** and assumes an answer of 'No' for every question. |
| 682 | 694 | ** --temp Remove only Fossil-generated temporary files. |
| 683 | 695 | ** -v|--verbose Show all files as they are removed. |
| 684 | 696 | ** |
| 685 | 697 | ** See also: addremove, extras, status |
| 686 | 698 | */ |
| 687 | 699 | void clean_cmd(void){ |
| 688 | 700 | int allFileFlag, allDirFlag, dryRunFlag, verboseFlag; |
| 689 | 701 | int emptyDirsFlag, dirsOnlyFlag; |
| 702 | + int disableUndo, noPrompt; |
| 690 | 703 | unsigned scanFlags = 0; |
| 691 | 704 | int verilyFlag = 0; |
| 692 | 705 | const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag; |
| 693 | 706 | Glob *pIgnore, *pKeep, *pClean; |
| 694 | 707 | int nRoot; |
| 695 | 708 | |
| 709 | +#ifndef UNDO_SIZE_LIMIT /* TODO: Setting? */ |
| 710 | +#define UNDO_SIZE_LIMIT (10*1024*1024) /* 10MiB */ |
| 711 | +#endif |
| 712 | + |
| 713 | + undo_capture_command_line(); |
| 696 | 714 | dryRunFlag = find_option("dry-run","n",0)!=0; |
| 697 | 715 | if( !dryRunFlag ){ |
| 698 | 716 | dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ |
| 699 | 717 | } |
| 700 | 718 | if( !dryRunFlag ){ |
| 701 | 719 | dryRunFlag = find_option("whatif",0,0)!=0; |
| 702 | 720 | } |
| 721 | + disableUndo = find_option("disable-undo",0,0)!=0; |
| 722 | + noPrompt = find_option("no-prompt",0,0)!=0; |
| 703 | 723 | allFileFlag = allDirFlag = find_option("force","f",0)!=0; |
| 704 | 724 | dirsOnlyFlag = find_option("dirsonly",0,0)!=0; |
| 705 | 725 | emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag; |
| 706 | 726 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| 707 | 727 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| | @@ -712,10 +732,11 @@ |
| 712 | 732 | zCleanFlag = find_option("clean",0,1); |
| 713 | 733 | db_must_be_within_tree(); |
| 714 | 734 | if( find_option("verily","x",0)!=0 ){ |
| 715 | 735 | verilyFlag = allFileFlag = allDirFlag = 1; |
| 716 | 736 | emptyDirsFlag = 1; |
| 737 | + disableUndo = 1; |
| 717 | 738 | scanFlags |= SCAN_ALL; |
| 718 | 739 | zCleanFlag = 0; |
| 719 | 740 | } |
| 720 | 741 | if( zIgnoreFlag==0 && !verilyFlag ){ |
| 721 | 742 | zIgnoreFlag = db_get("ignore-glob", 0); |
| | @@ -734,10 +755,11 @@ |
| 734 | 755 | nRoot = (int)strlen(g.zLocalRoot); |
| 735 | 756 | g.allowSymlinks = 1; /* Find symlinks too */ |
| 736 | 757 | if( !dirsOnlyFlag ){ |
| 737 | 758 | Stmt q; |
| 738 | 759 | Blob repo; |
| 760 | + if( !dryRunFlag && !disableUndo ) undo_begin(); |
| 739 | 761 | locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0); |
| 740 | 762 | db_prepare(&q, |
| 741 | 763 | "SELECT %Q || x FROM sfile" |
| 742 | 764 | " WHERE x NOT IN (%s)" |
| 743 | 765 | " ORDER BY 1", |
| | @@ -754,24 +776,38 @@ |
| 754 | 776 | fossil_print("KEPT file \"%s\" not removed (due to --keep" |
| 755 | 777 | " or \"keep-glob\")\n", zName+nRoot); |
| 756 | 778 | } |
| 757 | 779 | continue; |
| 758 | 780 | } |
| 759 | | - if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){ |
| 760 | | - Blob ans; |
| 761 | | - char cReply; |
| 762 | | - char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ", |
| 763 | | - zName+nRoot); |
| 764 | | - prompt_user(prompt, &ans); |
| 765 | | - cReply = blob_str(&ans)[0]; |
| 766 | | - if( cReply=='a' || cReply=='A' ){ |
| 767 | | - allFileFlag = 1; |
| 768 | | - }else if( cReply!='y' && cReply!='Y' ){ |
| 769 | | - blob_reset(&ans); |
| 770 | | - continue; |
| 771 | | - } |
| 772 | | - blob_reset(&ans); |
| 781 | + if( !dryRunFlag && !glob_match(pClean, zName+nRoot) ){ |
| 782 | + int undoRc = UNDO_NONE; |
| 783 | + if( !disableUndo ){ |
| 784 | + undoRc = undo_maybe_save(zName+nRoot, UNDO_SIZE_LIMIT); |
| 785 | + } |
| 786 | + if( undoRc!=UNDO_SAVED_OK ){ |
| 787 | + char cReply; |
| 788 | + if( allFileFlag ){ |
| 789 | + cReply = 'Y'; |
| 790 | + }else if( !noPrompt ){ |
| 791 | + Blob ans; |
| 792 | + char *prompt = mprintf("\nWARNING: Deletion of this file will " |
| 793 | + "not be undoable via the 'undo'\n" |
| 794 | + " command because %s.\n\n" |
| 795 | + "Remove unmanaged file \"%s\" (a=all/y/N)? ", |
| 796 | + undo_save_message(undoRc), zName+nRoot); |
| 797 | + prompt_user(prompt, &ans); |
| 798 | + cReply = blob_str(&ans)[0]; |
| 799 | + blob_reset(&ans); |
| 800 | + }else{ |
| 801 | + cReply = 'N'; |
| 802 | + } |
| 803 | + if( cReply=='a' || cReply=='A' ){ |
| 804 | + allFileFlag = 1; |
| 805 | + }else if( cReply!='y' && cReply!='Y' ){ |
| 806 | + continue; |
| 807 | + } |
| 808 | + } |
| 773 | 809 | } |
| 774 | 810 | if( dryRunFlag || file_delete(zName)==0 ){ |
| 775 | 811 | if( verboseFlag || dryRunFlag ){ |
| 776 | 812 | fossil_print("Removed unmanaged file: %s\n", zName+nRoot); |
| 777 | 813 | } |
| | @@ -778,10 +814,11 @@ |
| 778 | 814 | }else if( verboseFlag ){ |
| 779 | 815 | fossil_print("Could not remove file: %s\n", zName+nRoot); |
| 780 | 816 | } |
| 781 | 817 | } |
| 782 | 818 | db_finalize(&q); |
| 819 | + if( !dryRunFlag && !disableUndo ) undo_finish(); |
| 783 | 820 | } |
| 784 | 821 | if( emptyDirsFlag ){ |
| 785 | 822 | Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0)); |
| 786 | 823 | Stmt q; |
| 787 | 824 | Blob root; |
| | @@ -803,23 +840,26 @@ |
| 803 | 840 | " or \"keep-glob\")\n", zName+nRoot); |
| 804 | 841 | } |
| 805 | 842 | continue; |
| 806 | 843 | } |
| 807 | 844 | if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){ |
| 808 | | - Blob ans; |
| 809 | 845 | char cReply; |
| 810 | | - char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ", |
| 811 | | - zName+nRoot); |
| 812 | | - prompt_user(prompt, &ans); |
| 813 | | - cReply = blob_str(&ans)[0]; |
| 846 | + if( !noPrompt ){ |
| 847 | + Blob ans; |
| 848 | + char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ", |
| 849 | + zName+nRoot); |
| 850 | + prompt_user(prompt, &ans); |
| 851 | + cReply = blob_str(&ans)[0]; |
| 852 | + blob_reset(&ans); |
| 853 | + }else{ |
| 854 | + cReply = 'N'; |
| 855 | + } |
| 814 | 856 | if( cReply=='a' || cReply=='A' ){ |
| 815 | 857 | allDirFlag = 1; |
| 816 | 858 | }else if( cReply!='y' && cReply!='Y' ){ |
| 817 | | - blob_reset(&ans); |
| 818 | 859 | continue; |
| 819 | 860 | } |
| 820 | | - blob_reset(&ans); |
| 821 | 861 | } |
| 822 | 862 | if( dryRunFlag || file_rmdir(zName)==0 ){ |
| 823 | 863 | if( verboseFlag || dryRunFlag ){ |
| 824 | 864 | fossil_print("Removed unmanaged directory: %s\n", zName+nRoot); |
| 825 | 865 | } |
| 826 | 866 | |