From 658fe0ac863a4d1c62b3c64d2ed9c92981274bd4 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 17 Apr 2014 14:30:05 +0200 Subject: mv: Add pass mv/rename support Based-on-work-by: Matthieu Weber Signed-off-by: Jason A. Donenfeld --- man/pass.1 | 6 ++++ src/completion/pass.bash-completion | 4 +++ src/completion/pass.fish-completion | 4 +++ src/completion/pass.zsh-completion | 7 +++++ src/password-store.sh | 60 +++++++++++++++++++++++++++++++++++-- 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/man/pass.1 b/man/pass.1 index 9890111..3039143 100644 --- a/man/pass.1 +++ b/man/pass.1 @@ -126,6 +126,12 @@ alternatively named \fBremove\fP or \fBdelete\fP. If \fI--recursive\fP or \fI-r\ is specified, delete pass-name recursively if it is a directory. If \fI--force\fP or \fI-f\fP is specified, do not interactively prompt before removal. .TP +\fBmv\fP [ \fI--force\fP, \fI-f\fP ] \fIold-path\fP \fInew-path\fP +Renames the password or directory named \fIold-path\fP to \fInew-path\fP. This +command is alternatively named \fBrename\fP. If \fI--force\fP is specified, +silently overwrite \fInew-path\fP if it exists. If \fInew-path\fP ends in a +trailing \fI/\fP, it is always treated as a directory. +.TP \fBgit\fP \fIgit-command-args\fP... If the password store is a git repository, pass \fIgit-command-args\fP as arguments to .BR git (1) diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion index 1f20f51..08378f7 100644 --- a/src/completion/pass.bash-completion +++ b/src/completion/pass.bash-completion @@ -84,6 +84,10 @@ _pass() COMPREPLY+=($(compgen -W "-n --no-symbols -c --clip -f --force" -- ${cur})) _pass_complete_entries ;; + mv|rename) + COMPREPLY+=($(compgen -W "-f --force" -- ${cur})) + _pass_complete_entries + ;; rm|remove|delete) COMPREPLY+=($(compgen -W "-r --recursive -f --force" -- ${cur})) _pass_complete_entries diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion index 10c9488..2498be4 100644 --- a/src/completion/pass.fish-completion +++ b/src/completion/pass.fish-completion @@ -81,6 +81,10 @@ complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s c -l clip -d ' complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s f -l force -d 'Do not prompt before overwritting' complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -a "(__fish_pass_print_entry_dirs)" +complete -c $PROG -f -A -n '__fish_pass_needs_command' -a mv -d 'Command: rename existing password' +complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -s f -l force -d 'Force rename' +complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -a "(__fish_pass_print_entries_and_dirs)" + complete -c $PROG -f -A -n '__fish_pass_needs_command' -a rm -d 'Command: remove existing password' complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s r -l recursive -d 'Remove password groups recursively' complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s f -l force -d 'Force removal' diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion index 90045f0..b451fbf 100644 --- a/src/completion/pass.zsh-completion +++ b/src/completion/pass.zsh-completion @@ -48,6 +48,12 @@ _pass () { "--clip[copy password to the clipboard]" _pass_complete_entries_with_subdirs ;; + mv|rename) + _arguments : \ + "-f[force rename]" \ + "--force[force rename]" \ + _pass_complete_entries_with_subdirs + ;; rm) _arguments : \ "-f[force deletion]" \ @@ -83,6 +89,7 @@ _pass () { "insert:Insert a new password" "generate:Generate a new password using pwgen" "edit:Edit a password with \$EDITOR" + "mv:Rename the password" "rm:Remove the password" "git:Call git on the password store" "version:Output version information" diff --git a/src/password-store.sh b/src/password-store.sh index 082501d..5b2293a 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -26,8 +26,13 @@ git_add_file() { [[ -d $GIT_DIR ]] || return git add "$1" || return [[ -n $(git status --porcelain "$1") ]] || return + git_commit "$2" +} +git_commit() { + local sign + [[ -d $GIT_DIR ]] || return [[ $(git config --bool --get pass.signcommits) == "true" ]] && sign="-S" || sign="" - git commit $sign -m "$2" + git commit $sign -m "$1" } yesno() { local response @@ -185,6 +190,8 @@ cmd_usage() { Prompt before overwriting existing password unless forced. $PROGRAM rm [--recursive,-r] [--force,-f] pass-name Remove existing password or directory, optionally forcefully. + $PROGRAM mv [--force,-f] old-path new-path + Renames or moves old-path to new-path, optionally forcefully. $PROGRAM git git-command-args... If the password store is a git repository, execute a git command specified by git-command-args. @@ -482,7 +489,7 @@ cmd_delete() { if [[ ! -d $passfile ]]; then passfile="$PREFIX/$path.gpg" if [[ ! -f $passfile ]]; then - echo "$path is not in the password store." + echo "Error: $path is not in the password store." exit 1 fi fi @@ -492,10 +499,56 @@ cmd_delete() { rm $recursive -f -v "$passfile" if [[ -d $GIT_DIR && ! -e $passfile ]]; then git rm -qr "$passfile" - git commit -m "Removed $path from store." + git_commit "Removed $path from store." fi } +cmd_rename() { + local force=0 + + local opts + opts="$($GETOPT -o f -l force -n "$PROGRAM" -- "$@")" + local err=$? + eval set -- "$opts" + while true; do case $1 in + -f|--force) force=1; shift ;; + --) shift; break ;; + esac done + if [[ $# -ne 2 ]]; then + echo "Usage: $PROGRAM $COMMAND [--force,-f] old-path new-path" + exit 1 + fi + local old_path="$PREFIX/${1%/}" + local new_path="$PREFIX/$2" + local old_dir="$old_path" + + if [[ ! -d $old_path ]]; then + old_dir="${old_path%/*}" + old_path="${old_path}.gpg" + if [[ ! -f $old_path ]]; then + echo "Error: $1 is not in the password store." + exit 1 + fi + fi + + mkdir -p -v "${new_path%/*}" + [[ -d $old_path || -d $new_path || $new_path =~ /$ ]] || new_path="${new_path}.gpg" + + local interactive="-i" + [[ $force -eq 1 ]] && interactive="-f" + + mv $interactive -v "$old_path" "$new_path" || exit 1 + + if [[ -d $GIT_DIR && ! -e $old_path ]]; then + git rm -qr "$old_path" + git_add_file "$new_path" "Renamed ${1} to ${2}." + fi + + while rmdir "$old_dir" &>/dev/null; do + old_dir="${old_dir%/*}" + done +} + cmd_git() { if [[ $1 == "init" ]]; then git "$@" || exit 1 @@ -526,6 +579,7 @@ case "$1" in edit) shift; cmd_edit "$@"; ;; generate) shift; cmd_generate "$@"; ;; delete|rm|remove) shift; cmd_delete "$@"; ;; + rename|mv) shift; cmd_rename "$@"; ;; git) shift; cmd_git "$@"; ;; *) COMMAND="show"; cmd_show "$@"; ;; esac -- cgit v1.2.3-59-g8ed1b