From 21183df2f28dbd36c06c20c4b160eefaa0493a2d Mon Sep 17 00:00:00 2001 From: Mike Dacre Date: Tue, 6 Mar 2018 08:23:41 -0800 Subject: [PATCH 1/2] BugFix: Volume trash improperly set on Mac --- careful_rm.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/careful_rm.py b/careful_rm.py index 091435f..ff1dd6d 100755 --- a/careful_rm.py +++ b/careful_rm.py @@ -376,7 +376,9 @@ def recycle_files(files, mv_flags, try_apple=True, verbose=False, dryrun=False): # Build final list of recycle bins trashes = {} to_delete = [] - v_trash = '.Trash' if SYSTEM == 'Darwin' else '.Trash-{0}'.format(UID) + v_trash_mac = os.path.join('.Trashes', UID) + v_trash_lin = '.Trash-{0}'.format(UID) + v_trash = v_trash_mac if SYSTEM == 'Darwin' else v_trash_lin for mount, file_list in bins.items(): if mount == HOME_TRASH or mount == RECYCLE_BIN: r_trash = mount @@ -386,7 +388,7 @@ def recycle_files(files, mv_flags, try_apple=True, verbose=False, dryrun=False): trashes[r_trash] = file_list else: ans = get_ans( - ('Mount {0} has no {1}.\n' + + ('Mount {0} has no trash at {1}.\n' + 'Skip, create, use (root) {2}, or delete files?') .format(mount, v_trash, RECYCLE_BIN), ['skip', 'create', 'root', 'del'] From b865c6940098e2e8c0b5d415516c19d75733a14a Mon Sep 17 00:00:00 2001 From: Mike Dacre Date: Tue, 6 Mar 2018 11:23:01 -0800 Subject: [PATCH 2/2] Add ZSH specific stuff, increment to beta-6 On ZSH, the plugin now sets the `$TRASH` variable and a `trsh` alias --- README.md | 30 ++++++++++++++++-------- careful_rm.alias.sh | 30 +++++++++++++++++------- careful_rm.plugin.zsh | 23 ++++++++++++++++++- careful_rm.py | 53 +++++++++++++++++++++++++++++-------------- 4 files changed, 100 insertions(+), 36 deletions(-) mode change 100755 => 100644 careful_rm.alias.sh mode change 120000 => 100644 careful_rm.plugin.zsh diff --git a/README.md b/README.md index a37377d..bcd264c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Careful rm -Version: 1.0-beta5 +Version: 1.0-beta6 A wrapper for rm that adds more useful warnings and an optional recycle/trash mode @@ -54,7 +54,7 @@ options have any meaning in recycle mode, which uses `mv`. Argument order does not matter. ``` -## Installation +## Install Script Only To use this `rm` wrapper, the best way to go is to install the repo as a ZSH or Bash plugin (see below). However, you can just put it into your `$PATH` and use @@ -63,14 +63,18 @@ it directly. e.g.: 1. `cd /usr/local/bin` 2. `wget https://raw.githubusercontent.com/MikeDacre/careful_rm/master/careful_rm.py` -Ideally it should be *aliased to rm*. To facilitate that, you can use the -`careful_rm.alias.sh` file or just add this to your config (e.g. `.bashrc`): +Ideally it should be *aliased to rm*. To facilitate that, you can download this +repo and source the `careful_rm.alias.sh` file or, if you put `careful_rm` into +your `PATH`, just add this to your config (e.g. `.bashrc`): - if hash careful_rm.py 2>/dev/null; then - alias rm="$(command -v careful_rm.py)" - else - alias rm="rm -I" - fi +```shell +if hash careful_rm.py 2>/dev/null; then + alias rm="$(command -v careful_rm.py)" +else + alias rm="rm -I" +fi +``` +## Install as a plugin ### Requirements @@ -91,7 +95,13 @@ With any `sh` like shell (`sh`, `bash`, `fish`, `zsh`) ### ZSH -ZSH offers some great ways to install as a plugin and stay up to date. +The ZSH version of this plugin is provided by the `careful_rm.plugin.zsh` file. +In addition to aliasing `rm` to `careful_rm`, it also sets a `$TRASH` variable +that updates with every directory change and makes `~trash` a named directory +that points to `$TRASH`. + +ZSH offers some great ways to install as a plugin and stay up to date, my +favorite is antigen, but any of the following methods will work. #### [Antigen](github.com/zsh-users/antigen) diff --git a/careful_rm.alias.sh b/careful_rm.alias.sh old mode 100755 new mode 100644 index 1aac94a..5e33cd3 --- a/careful_rm.alias.sh +++ b/careful_rm.alias.sh @@ -4,24 +4,38 @@ # Get PATH to the python script SOURCE="$0" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink +# resolve $SOURCE until the file is no longer a symlink +while [ -h "$SOURCE" ]; do DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located + # if $SOURCE was a relative symlink, we need to resolve it relative to the + # path where the symlink file was located + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" done -DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" +CAREFUL_RM_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" -CAREFUL_RM="${DIR}/careful_rm.py" +CAREFUL_RM="${CAREFUL_RM_DIR}/careful_rm.py" # Only use our careful_rm if it exists, if not, try for a version on the # PATH, failing that, fall back to rm -I +if [ ! -x "${CAREFUL_RM}" ]; then + if hash careful_rm.py 2>/dev/null; then + CAREFUL_RM="$(command -v careful_rm.py)" + elif hash careful_rm 2>/dev/null; then + CAREFUL_RM="$(command -v careful_rm)" + else + CAREFUL_RM="" + fi +fi + +# Set the alias if [ -x "${CAREFUL_RM}" ]; then alias rm="${CAREFUL_RM}" alias careful_rm="${CAREFUL_RM}" -elif hash careful_rm.py 2>/dev/null; then - alias rm="$(command -v careful_rm.py)" -elif hash careful_rm 2>/dev/null; then - alias rm="$(command -v careful_rm)" + alias current_trash="${CAREFUL_RM} --get-trash \${PWD}" else + echo "careful_rm.py is not available, using regular rm" alias rm="rm -I" fi + +export CAREFUL_RM CAREFUL_RM_DIR diff --git a/careful_rm.plugin.zsh b/careful_rm.plugin.zsh deleted file mode 120000 index ecc8446..0000000 --- a/careful_rm.plugin.zsh +++ /dev/null @@ -1 +0,0 @@ -careful_rm.alias.sh \ No newline at end of file diff --git a/careful_rm.plugin.zsh b/careful_rm.plugin.zsh new file mode 100644 index 0000000..d999375 --- /dev/null +++ b/careful_rm.plugin.zsh @@ -0,0 +1,22 @@ +####################################################################### +# careful_rm for ZSH # +# Has some extra goodies # +####################################################################### + +# Get the alias +OURDIR="$(dirname $0:A)" +source "${OURDIR}/careful_rm.alias.sh" + +# Make a trash aliase that changes with directory +chpwd_trash() { + if [ -x "${CAREFUL_RM}" ]; then + TRASH=$(python ${CAREFUL_RM} --get-trash) + if [[ "$OSTYPE" == "linux-gnu" ]]; then + TRASH="${TRASH}/files" + fi + hash -d trash="${TRASH}" + fi +} +chpwd_functions=( ${chpwd_functions} chpwd_trash ) +chpwd_trash +alias trsh="cd \${TRASH}" diff --git a/careful_rm.py b/careful_rm.py index ff1dd6d..bbb94a1 100755 --- a/careful_rm.py +++ b/careful_rm.py @@ -69,7 +69,7 @@ # For old versions of python 2 input = raw_input -__version__ = '1.0b5' +__version__ = '1.0b6' # Don't ask if fewer than this number of files deleted CUTOFF = 3 @@ -294,13 +294,31 @@ def get_mount(fl): return '/' +def get_trash(fl): + """Return the trash can for the file/dir fl.""" + v_trash_mac = os.path.join('.Trashes', str(UID)) + v_trash_lin = '.Trash-{0}'.format(UID) + v_trash = v_trash_mac if SYSTEM == 'Darwin' else v_trash_lin + + fl = os.path.abspath(fl) + mnt = get_mount(fl) + if mnt == '/': + if HAS_HOME and fl.startswith(HOME): + trash = HOME_TRASH + else: + trash = RECYCLE_BIN + elif mnt == HOME: + trash = HOME_TRASH + else: + trash = os.path.join(mnt, v_trash) + + return trash ############################################################################### # Deletion Helpers # ############################################################################### - def recycle_files(files, mv_flags, try_apple=True, verbose=False, dryrun=False): """Identify best recycle bins for files and then try to recycle them. @@ -363,34 +381,21 @@ def recycle_files(files, mv_flags, try_apple=True, verbose=False, dryrun=False): break else: mnt = get_mount(fl) - if mnt == '/': - if HAS_HOME and fl.startswith(HOME): - mnt = HOME_TRASH - else: - mnt = RECYCLE_BIN - elif mnt == HOME: - mnt = HOME_TRASH bins[mnt].append(fl) gotn += (mnt,) # Build final list of recycle bins trashes = {} to_delete = [] - v_trash_mac = os.path.join('.Trashes', UID) - v_trash_lin = '.Trash-{0}'.format(UID) - v_trash = v_trash_mac if SYSTEM == 'Darwin' else v_trash_lin for mount, file_list in bins.items(): - if mount == HOME_TRASH or mount == RECYCLE_BIN: - r_trash = mount - else: - r_trash = os.path.join(mount, v_trash) + r_trash = get_trash(mount) if os.path.isdir(r_trash): trashes[r_trash] = file_list else: ans = get_ans( ('Mount {0} has no trash at {1}.\n' + 'Skip, create, use (root) {2}, or delete files?') - .format(mount, v_trash, RECYCLE_BIN), + .format(mount, r_trash, RECYCLE_BIN), ['skip', 'create', 'root', 'del'] ) if ans == 'create': @@ -406,6 +411,7 @@ def recycle_files(files, mv_flags, try_apple=True, verbose=False, dryrun=False): elif ans == 'del': to_delete += file_list elif ans == 'skip': + # Just don't add the files to the trashes dict pass else: raise Exception('Invalid response {0}'.format(ans)) @@ -548,6 +554,12 @@ def main(argv=None): elif arg == '--dryrun': dryrun = True sys.stderr.write('Dry Run. Not actually removing files.\n\n') + elif arg == '--get-trash': + # Print trash for next arg and immediately exit + tindex = argv.index(arg)+1 + tpath = argv[tindex] if len(argv) > tindex else os.curdir + sys.stdout.write(get_trash(tpath)) + return 0 elif arg == '--': # Everything after this is a file file_sep = '--' @@ -556,6 +568,13 @@ def main(argv=None): for i in l ] break + elif arg == '-': + # Read files in from STDIN + all_files += [ + i for l in \ + [glob(n) for n in sys.stdin.read().strip().split()] \ + for i in l + ] elif arg.startswith('-'): if 'r' in arg or 'R' in arg: recursive = True