From 5e507af74795ffbe43f1523695a5205eedd0ef23 Mon Sep 17 00:00:00 2001 From: Jacob Lukas Date: Wed, 9 Nov 2011 12:45:38 -0800 Subject: [PATCH] Fix add/remove with spaces/special characters --- lib/git/fallback/status_shortcuts_shell.sh | 7 +-- lib/git/repo_index.sh | 8 ++- lib/git/status_shortcuts.rb | 6 ++- lib/git/status_shortcuts.sh | 58 +++++++++++++++------- test/lib/git/repo_index_test.sh | 8 +-- test/lib/git/status_shortcuts_test.sh | 10 ++-- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/lib/git/fallback/status_shortcuts_shell.sh b/lib/git/fallback/status_shortcuts_shell.sh index 6eb7c3f..8a84fe1 100644 --- a/lib/git/fallback/status_shortcuts_shell.sh +++ b/lib/git/fallback/status_shortcuts_shell.sh @@ -120,7 +120,7 @@ _gs_output_file_group() { for i in ${stat_grp[$1]}; do # Print colored hashes & files based on modification groups local c_group="\e[0;$(eval echo -e \$c_grp_$1)" - + # Deduce relative path based on current working directory if [ -z "$project_root" ]; then relative="${stat_file[$i]}" @@ -128,13 +128,14 @@ _gs_output_file_group() { dest="$project_root/${stat_file[$i]}" relative="$(_gs_relative_path "$PWD" "$dest" )" fi - + if [[ $f -gt 10 && $e -lt 10 ]]; then local pad=" "; else local pad=""; fi # (padding) echo -e "$c_hash#$c_rst ${stat_col[$i]}${stat_msg[$i]}:\ $pad$c_dark [$c_rst$e$c_dark] $c_group$relative$c_rst" # Export numbered variables in the order they are displayed. # (Exports full path, but displays relative path) - export $git_env_char$e="$project_root/${stat_file[$i]}" + local filename=$(eval echo $(echo ${stat_file[$i]} | egrep -o '^"([^\\"]*(\\.[^"]*)*)"|^[^ ]+')) + export $git_env_char$e="$project_root/$filename" let e++ done echo -e "$c_hash#$c_rst" diff --git a/lib/git/repo_index.sh b/lib/git/repo_index.sh index 08349fa..78e2639 100644 --- a/lib/git/repo_index.sh +++ b/lib/git/repo_index.sh @@ -91,7 +91,11 @@ function git_index() { # Go to our base path if [ -n "$base_path" ]; then unset IFS - eval cd \"$base_path\" # eval turns ~ into $HOME + # evaluate ~ if necessary + if [[ "$base_path" == "~"* ]]; then + base_path=$(eval echo ${base_path%%/*})/${base_path#*/} + fi + cd "$base_path" # Run git callback (either update or show changes), if we are in the root directory if [ -z "${sub_path%/}" ]; then _git_index_update_or_status; fi else @@ -128,7 +132,7 @@ function _rebuild_git_index() { if [ "$1" != "--silent" ]; then echo -e "== Scanning $GIT_REPO_DIR for git repos & submodules..."; fi # Get repos from src dir and custom dirs, then sort by basename local IFS=$'\n' - for repo in $(echo -e "$(_find_git_repos)\n$(echo $GIT_REPOS | sed "s/:/\n/g")"); do + for repo in $(echo -e "$(_find_git_repos)\n$(echo $GIT_REPOS | sed "s/:/\\\\n/g")"); do echo $(basename $repo | sed "s/ /_/g") $repo done | sort | cut -d " " -f2- > "$GIT_REPO_DIR/.git_index" diff --git a/lib/git/status_shortcuts.rb b/lib/git/status_shortcuts.rb index 314bc49..558babb 100644 --- a/lib/git/status_shortcuts.rb +++ b/lib/git/status_shortcuts.rb @@ -131,7 +131,11 @@ def output_file_group(group) puts "#{c_group}##{@c[:rst]} #{@c[h[:col]]}#{h[:msg]}:\ #{padding}#{@c[:dark]} [#{@c[:rst]}#{@e}#{@c[:dark]}] #{c_group}#{rel_file}#{@c[:rst]}" # Save the ordered list of output files - @output_files << h[:file] + @output_files << if h[:file] =~ /^"([^\\"]*(\\.[^"]*)*)"/ + $1.gsub(/\\(.)/,'\1') + else + h[:file].match(/^[^ ]*/)[0] + end end puts "#{c_group}##{@c[:rst]}" # Extra '#' diff --git a/lib/git/status_shortcuts.sh b/lib/git/status_shortcuts.sh index 5f94bdc..89bb5be 100644 --- a/lib/git/status_shortcuts.sh +++ b/lib/git/status_shortcuts.sh @@ -74,17 +74,21 @@ git_add_shortcuts() { # Does nothing if no args are given. git_silent_add_shortcuts() { if [ -n "$1" ]; then - # Expand args and process resulting set of files. - for file in $(git_expand_args "$@"); do + + function process { + file=$1 # Use 'git rm' if file doesn't exist and 'ga_auto_remove' is enabled. - if [[ $ga_auto_remove == "yes" ]] && ! [ -e $file ]; then + if [[ $ga_auto_remove == "yes" ]] && ! [ -e "$file" ]; then echo -n "# " - git rm $file + git rm "$file" else - git add $file + git add "$file" echo -e "# add '$file'" fi - done + } + + # Expand args and process resulting set of files. + eval for file in $(git_expand_args "$@")\; do process "\$file"\; done echo "#" fi } @@ -109,9 +113,10 @@ git_add_patch_shortcuts() { git_silent_add_patch_shortcuts() { if [ -n "$1" ]; then # Expand args and process resulting set of files. - for file in $(git_expand_args "$@"); do - git add -p $file - echo -e "# add '$file'" + local IFS=$'\n' + eval for file in $(git_expand_args "$@")\; do\ + git add -p "\$file"\;\ + echo -e "# add '\$file'"\;\ done echo "#" fi @@ -136,21 +141,36 @@ git_show_affected_files(){ # * git_status_shortcuts() - git status implementation # * git_show_affected_files() - shows files affected by a given SHA1, etc. git_expand_args() { - files="" + first=1 for arg in "$@"; do if [[ "$arg" =~ ^[0-9]+$ ]] ; then # Substitute $e{*} variables for any integers - files="$files $(eval echo \$$git_env_char$arg)" - elif [[ $arg =~ ^[0-9]+\.\.[0-9]+$ ]]; then # Expand ranges into $e{*} variables - files="$files $(eval echo \$$git_env_char{$arg})" + if [ "$first" -eq 1 ]; then + first=0 + else + echo -n " " + fi + eval printf '%q' "\$$git_env_char$arg" + elif [[ "$arg" =~ ^[0-9]+\.\.[0-9]+$ ]]; then # Expand ranges into $e{*} variables + for i in $(eval echo {$arg}); do + if [ "$first" -eq 1 ]; then + first=0 + else + echo -n " " + fi + eval printf '%q' "\$$git_env_char$i" + done else # Otherwise, treat $arg as a normal string. - # If arg contains any spaces, (re)wrap it in double quotes - if echo $arg | grep -q " "; then arg="\"$arg\""; fi - files="$files $arg" + if [ "$first" -eq 1 ]; then + first=0 + else + echo -n " " + fi + printf '%q' "$arg" fi done - echo $files } # Execute a command with expanded args, e.g. Delete files 6 to 12: $ ge rm 6..12 +# Fails if command is a number or range (probably not worth fixing) exec_git_expand_args() { $(git_expand_args "$@"); } # Clear numbered env variables @@ -164,8 +184,8 @@ git_clear_vars() { # Shortcuts for resolving merge conflicts. -ours(){ local files=$(git_expand_args "$@"); git checkout --ours $files; git add $files; } -theirs(){ local files=$(git_expand_args "$@"); git checkout --theirs $files; git add $files; } +ours(){ local files=$(git_expand_args "$@"); git checkout --ours "$files"; git add "$files"; } +theirs(){ local files=$(git_expand_args "$@"); git checkout --theirs "$files"; git add "$files"; } # Git commit prompts diff --git a/test/lib/git/repo_index_test.sh b/test/lib/git/repo_index_test.sh index 005ca56..e4ea2be 100755 --- a/test/lib/git/repo_index_test.sh +++ b/test/lib/git/repo_index_test.sh @@ -23,14 +23,16 @@ if [ -n "${ZSH_VERSION:-}" ]; then shell="zsh"; SHUNIT_PARENT=$0; setopt shwords # Setup and tear down #----------------------------------------------------------------------------- oneTimeSetUp() { - GIT_REPO_DIR=$(mktemp -d) + GIT_REPO_DIR=$(mktemp -d -t scm_breeze.XXXXXXXXXX) GIT_REPOS="/tmp/test_repo_1:/tmp/test_repo_11" git_status_command="git status" git_index_file="$GIT_REPO_DIR/.git_index" silentGitCommands - + + echo "Using repo dir $GIT_REPO_DIR" + cd $GIT_REPO_DIR # Setup test repos in temp repo dir for repo in github bitbucket source_forge; do @@ -91,7 +93,7 @@ index_no_newlines() { test_repo_index_command() { git_index --rebuild > /dev/null - + # Test that all repos are detected, and sorted alphabetically assertIncludes "$(index_no_newlines)" "bitbucket.*\ blue_submodule.*\ diff --git a/test/lib/git/status_shortcuts_test.sh b/test/lib/git/status_shortcuts_test.sh index 1776a17..7d35973 100755 --- a/test/lib/git/status_shortcuts_test.sh +++ b/test/lib/git/status_shortcuts_test.sh @@ -28,7 +28,7 @@ oneTimeSetUp() { export gs_max_changes="20" export ga_auto_remove="yes" - testRepo=$(mktemp -d) + testRepo=$(mktemp -d -t scm_breeze.XXXXXXXXXX) } oneTimeTearDown() { @@ -55,8 +55,8 @@ test_git_expand_args() { assertEquals "$error" "seven two three four five one" "$(git_expand_args seven 2..5 1)" # Test that any args with spaces remain quoted - assertEquals "$error" "-m \"Test Commit Message\" one" "$(git_expand_args -m \"Test Commit Message\" 1)" - assertEquals "$error" "-ma \"Test Commit Message\" Unquoted"\ + assertEquals "$error" "-m Test\ Commit\ Message one" "$(git_expand_args -m "Test Commit Message" 1)" + assertEquals "$error" "-ma Test\ Commit\ Message Unquoted"\ "$(git_expand_args -ma "Test Commit Message" "Unquoted")" } @@ -95,7 +95,7 @@ test_git_status_shortcuts() { assertNotIncludes "$git_status3" "Untracked files" # Run command in shell, load output from temp file into variable - temp_file=$(mktemp) + temp_file=$(mktemp -t scm_breeze.XXXXXXXXXX) git_status_shortcuts > $temp_file git_status=$(cat $temp_file | strip_colors) @@ -232,7 +232,7 @@ test_git_commit_prompt() { commit_msg="\"Nathan's git commit prompt function!\"" dbl_escaped_msg="\\\\\"Nathan's git commit prompt function\"'"'!'"'\"\\\\\"" # Create temporary history file - HISTFILE=$(mktemp) + HISTFILE=$(mktemp -t scm_breeze.XXXXXXXXXX) HISTFILESIZE=1000 HISTSIZE=1000