From 09c2be9d6bec0d0d6b917203e3c222970ea8ebe2 Mon Sep 17 00:00:00 2001 From: Konstantin Gredeskoul Date: Fri, 23 Nov 2018 16:14:12 -0800 Subject: [PATCH] =?UTF-8?q?Refactor=20(extract=20utilities=20+=20add=20tes?= =?UTF-8?q?ts)=20&=20more=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extracting common utilities into utilities.bash * Adding new tests for utilities * Relocating the cache file to be under $BASH_IT * Removing cache cleanup deferral code for now * Wiping the cache in local_setup in tests. --- .gitignore | 1 + lib/helpers.bash | 9 ++- lib/search.bash | 142 ++++++++------------------------------- lib/utilities.bash | 144 ++++++++++++++++++++++++++++++++++++++++ test/lib/helpers.bats | 1 + test/lib/search.bats | 2 + test/lib/utilities.bats | 108 ++++++++++++++++++++++++++++++ 7 files changed, 289 insertions(+), 118 deletions(-) mode change 100644 => 100755 lib/search.bash create mode 100644 lib/utilities.bash create mode 100644 test/lib/utilities.bats diff --git a/.gitignore b/.gitignore index 2e6fb7c0..6fad6279 100755 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ bats *.sublime-workspace *.sublime-project enabled/* +tmp/ diff --git a/lib/helpers.bash b/lib/helpers.bash index cbcdd42d..bec603f1 100644 --- a/lib/helpers.bash +++ b/lib/helpers.bash @@ -70,7 +70,7 @@ bash-it () example '$ bash-it disable alias hg [tmux]...' example '$ bash-it migrate' example '$ bash-it update' - example '$ bash-it search [-|@]term1 [-|@]term2 ... [--enable | --disable | --help | --refresh | --no-color ]' + example '$ bash-it search [-|@]term1 [-|@]term2 ... [ -e/--enable ] [ -d/--disable ] [ -r/--refresh ] [ -c/--no-color ]' example '$ bash-it version' example '$ bash-it reload' typeset verb=${1:-} @@ -78,6 +78,7 @@ bash-it () typeset component=${1:-} shift typeset func + case $verb in show) func=_bash-it-$component;; @@ -393,8 +394,7 @@ _disable-thing () fi fi - local flag="DEFER_CACHE_CLEANUP_FOR_${file_type}" - [[ -z ${!flag} ]] && _bash_it_search_cache_clean "${file_type}" + _bash-it-clean-component-cache "${file_type}" if [ -n "$BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE" ]; then exec ${0/-/} @@ -491,8 +491,7 @@ _enable-thing () ln -s ../$subdirectory/available/$to_enable "${BASH_IT}/enabled/${use_load_priority}${BASH_IT_LOAD_PRIORITY_SEPARATOR}${to_enable}" fi - local flag="DEFER_CACHE_CLEANUP_FOR_${file_type}" - [[ -z ${!flag} ]] && _bash_it_search_cache_clean "${file_type}" + _bash-it-clean-component-cache "${file_type}" if [ -n "$BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE" ]; then exec ${0/-/} diff --git a/lib/search.bash b/lib/search.bash old mode 100644 new mode 100755 index a54971f5..1c487a3e --- a/lib/search.bash +++ b/lib/search.bash @@ -7,10 +7,11 @@ # # Usage: # ❯ bash-it search [-|@]term1 [-|@]term2 ... \ -# [ --enable | -e ] \ -# [ --disable | -d ] \ -# [ --refresh | -r ] -# [ --help | -h ] +# [ --enable | -e ] \ +# [ --disable | -d ] \ +# [ --no-color | -c ] \ +# [ --refresh | -r ] \ +# [ --help | -h ] # # Single dash, as in "-chruby", indicates a negative search term. # Double dash indicates a command that is to be applied to the search result. @@ -52,6 +53,8 @@ _bash-it-search() { _param '2: [ term2 ]...' _example '$ _bash-it-search @git ruby -rvm rake bundler' + [[ -z "$(type _bash-it-array-contains-element 2>/dev/null)" ]] && source "${BASH_IT}/lib/utilities.bash" + local component export BASH_IT_SEARCH_USE_COLOR=true export BASH_IT_GREP=${BASH_IT_GREP:-$(which egrep)} @@ -68,17 +71,19 @@ _bash-it-search() { _bash-it-search-help return 0 elif [[ ${word} == "--refresh" || ${word} == "-r" ]]; then - _bash_it_search_cache_clean - elif [[ ${word} == "--no-color" ]]; then + _bash-it-clean-component-cache + elif [[ ${word} == "--no-color" || ${word} == '-c' ]]; then export BASH_IT_SEARCH_USE_COLOR=false else args=(${args[@]} ${word}) fi done - for component in "${BASH_IT_COMPONENTS[@]}" ; do - _bash-it-search-component "${component}" "${args[@]}" - done + if [[ ${#args} -gt 0 ]]; then + for component in "${BASH_IT_COMPONENTS[@]}" ; do + _bash-it-search-component "${component}" "${args[@]}" + done + fi return 0 } @@ -88,7 +93,11 @@ _bash-it-search-help() { ${echo_underline_yellow}USAGE${echo_normal} bash-it search [-|@]term1 [-|@]term2 ... \\ - [ --enable | --disable | --help | --refresh | --no-color ] + [ --enable | -e ] \\ + [ --disable | -d ] \\ + [ --no-color | -c ] \\ + [ --refresh | -r ] \\ + [ --help | -h ] ${echo_underline_yellow}DESCRIPTION${echo_normal} @@ -110,11 +119,11 @@ ${echo_underline_yellow}DESCRIPTION${echo_normal} eg. '@git' would only match aliases, plugins and completions named 'git'. ${echo_underline_yellow}FLAGS${echo_normal} - --enable ${echo_purple}Enable all matching componenents.${echo_normal} - --disable ${echo_purple}Disable all matching componenents.${echo_normal} - --help ${echo_purple}Print this help.${echo_normal} - --refresh ${echo_purple}Force a refresh of the search cache.${echo_normal} - --no-color ${echo_purple}Disable color output and use monochrome text.${echo_normal} + --enable | -e ${echo_purple}Enable all matching componenents.${echo_normal} + --disable | -d ${echo_purple}Disable all matching componenents.${echo_normal} + --help | -h ${echo_purple}Print this help.${echo_normal} + --refresh | -r ${echo_purple}Force a refresh of the search cache.${echo_normal} + --no-color | -c ${echo_purple}Disable color output and use monochrome text.${echo_normal} ${echo_underline_yellow}EXAMPLES${echo_normal} @@ -156,46 +165,6 @@ ${echo_underline_yellow}SUMMARY${echo_normal} " } -_bash-it-cache-file() { - local component="${1}" - local file="/tmp/bash_it/${component}.status" - mkdir -p $(dirname ${file}) - printf ${file} -} - -_bash_it_search_cache_clean() { - local component="$1" - if [[ -z ${component} ]] ; then - for component in "${BASH_IT_COMPONENTS[@]}" ; do - _bash_it_search_cache_clean "${component}" - done - else - rm -f $(_bash-it-cache-file ${component}) - fi -} - -#——————————————————————————————————————————————————————————————————————————————— -# array=("something to search for" "a string" "test2000") -# _bash-it-array-contains-element "a string" "${array[@]}" -# ( prints "true" or "false" ) -_bash-it-array-contains-element () { - local e - local r=false - for e in "${@:2}"; do [[ "$e" == "$1" ]] && r=true; done - echo -n $r -} - -_bash-it-array-dedup() { - echo "$*" | tr ' ' '\n' | sort -u | tr '\n' ' ' -} - -_bash-it-grep() { - if [[ -z "${BASH_IT_GREP}" ]] ; then - export BASH_IT_GREP="$(which egrep || which grep || '/usr/bin/grep')" - fi - printf "%s " "${BASH_IT_GREP}" -} - _bash-it-is-partial-match() { local component="$1" local term="$2" @@ -212,51 +181,6 @@ _bash-it-component-term-matches-negation() { return 1 } -_bash-it-component-help() { - local component="$1" - local file=$(_bash-it-cache-file ${component}) - if [[ ! -s "${file}" || -z $(find "${file}" -mmin -2) ]] ; then - rm -f "${file}" 2>/dev/null - local func="_bash-it-${component}" - ${func} | $(_bash-it-grep) -E ' \[' | cat > ${file} - fi - cat "${file}" -} - -_bash-it-component-list() { - local component="$1" - _bash-it-component-help "${component}" | awk '{print $1}' | uniq | sort | tr '\n' ' ' -} - -_bash-it-component-list-matching() { - local component="$1"; shift - local term="$1" - _bash-it-component-help "${component}" | $(_bash-it-grep) -E -- "${term}" | awk '{print $1}' | sort | uniq -} - -_bash-it-component-list-enabled() { - local component="$1" - _bash-it-component-help "${component}" | $(_bash-it-grep) -E '\[x\]' | awk '{print $1}' | uniq | sort | tr '\n' ' ' -} - -_bash-it-component-list-disabled() { - local component="$1" - _bash-it-component-help "${component}" | $(_bash-it-grep) -E -v '\[x\]' | awk '{print $1}' | uniq | sort | tr '\n' ' ' -} - -_bash-it-component-item-is-enabled() { - local component="$1" - local item="$2" - _bash-it-component-help "${component}" | $(_bash-it-grep) -E '\[x\]' | $(_bash-it-grep) -E -q -- "^${item}\s" -} - -_bash-it-component-item-is-disabled() { - local component="$1" - local item="$2" - _bash-it-component-help "${component}" | $(_bash-it-grep) -E -v '\[x\]' | $(_bash-it-grep) -E -q -- "^${item}\s" -} - - _bash-it-search-component() { local component="$1" shift @@ -272,7 +196,7 @@ _bash-it-search-component() { local component_singular action action_func local -a search_commands=(enable disable) for search_command in "${search_commands[@]}"; do - if [[ $(_bash-it-array-contains-element "--${search_command}" "$@") == "true" ]]; then + if $(_bash-it-array-contains-element "--${search_command}" "$@"); then component_singular=${component} component_singular=${component_singular/es/} # aliases -> alias component_singular=${component_singular/ns/n} # plugins -> plugin @@ -304,7 +228,7 @@ _bash-it-search-component() { elif [[ "${term:0:1}" == "-" ]] ; then negative_terms=(${negative_terms[@]} "${search_term}") elif [[ "${term:0:1}" == "@" ]] ; then - if [[ $(_bash-it-array-contains-element "${search_term}" "${component_list[@]}") == "true" ]]; then + if $(_bash-it-array-contains-element "${search_term}" "${component_list[@]}"); then exact_terms=(${exact_terms[@]} "${search_term}") fi else @@ -358,9 +282,6 @@ _bash-it-search-result() { local match local modified=0 - local flag="DEFER_CACHE_CLEANUP_FOR_${component}" - eval "export ${flag}=true" - if [[ "${#matches[@]}" -gt 0 ]] ; then printf "${color_component}%13s${color_sep} ${color_off}" "${component}" @@ -384,14 +305,9 @@ _bash-it-search-result() { compatible_action="enable" } + local m="${match}${suffix}" local len - if ( ${BASH_IT_SEARCH_USE_COLOR} ); then - local m="${match_color}${match}${suffix}" - len=${#m} - else - local m="${match}${suffix}" - len=${#m} - fi + len=${#m} printf " ${match_color}${match}${suffix}" # print current state if [[ "${action}" == "${compatible_action}" ]]; then @@ -411,7 +327,7 @@ _bash-it-search-result() { printf "${color_off}" done - [[ ${modified} -gt 0 ]] && _bash_it_search_cache_clean ${component} + [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache ${component} printf "\n" fi } diff --git a/lib/utilities.bash b/lib/utilities.bash new file mode 100644 index 00000000..93e96606 --- /dev/null +++ b/lib/utilities.bash @@ -0,0 +1,144 @@ +#!/usr/bin/env bash +# +# A collection of reusable functions. + +########################################################################### +# Component-specific functions (component is either an alias, a plugin, or a +# completion). +########################################################################### + +_bash-it-component-help() { + local component=$(_bash-it-pluralize-component "${1}") + local file=$(_bash-it-component-cache-file ${component}) + if [[ ! -s "${file}" || -z $(find "${file}" -mmin -300) ]] ; then + rm -f "${file}" 2>/dev/null + local func="_bash-it-${component}" + ${func} | $(_bash-it-grep) -E ' \[' | cat > ${file} + fi + cat "${file}" +} + +_bash-it-component-cache-file() { + local component=$(_bash-it-pluralize-component "${1}") + local file="${BASH_IT}/tmp/cache/${component}" + [[ -f ${file} ]] || mkdir -p $(dirname ${file}) + printf "${file}" +} + +_bash-it-pluralize-component() { + local component="${1}" + local len=$(( ${#component} - 1 )) + # pluralize component name for consistency + [[ ${component:${len}:1} != 's' ]] && component="${component}s" + [[ ${component} == "alias" ]] && component="aliases" + printf ${component} +} + +_bash-it-clean-component-cache() { + local component="$1" + local cache + local -a BASH_IT_COMPONENTS=(aliases plugins completions) + if [[ -z ${component} ]] ; then + for component in "${BASH_IT_COMPONENTS[@]}" ; do + _bash-it-clean-component-cache "${component}" + done + else + cache="$(_bash-it-component-cache-file ${component})" + [[ -f "${cache}" ]] && rm -f "${cache}" + fi +} + +########################################################################### +# Generic utilies +########################################################################### + +# This function searches an array for an exact match against the term passed +# as the first argument to the function. This function exits as soon as +# a match is found. +# +# Returns: +# 0 when a match is found, otherwise 1. +# +# Examples: +# $ declare -a fruits=(apple orange pear mandarin) +# +# $ _bash-it-array-contains-element apple "@{fruits[@]}" && echo 'contains apple' +# contains apple +# +# $ if $(_bash-it-array-contains-element pear "${fruits[@]}"); then +# echo "contains pear!" +# fi +# contains pear! +# +# +_bash-it-array-contains-element() { + local e + for e in "${@:2}"; do + [[ "$e" == "$1" ]] && return 0 + done + return 1 +} + +# Dedupe a simple array of words without spaces. +_bash-it-array-dedup() { + echo "$*" | tr ' ' '\n' | sort -u | tr '\n' ' ' +} + +# Outputs a full path of the gre found on the filesystem +_bash-it-grep() { + if [[ -z "${BASH_IT_GREP}" ]] ; then + export BASH_IT_GREP="$(which egrep || which grep || '/usr/bin/grep')" + fi + printf "%s " "${BASH_IT_GREP}" +} + + +# Returns an array of items within each compoenent. +_bash-it-component-list() { + local component="$1" + _bash-it-component-help "${component}" | awk '{print $1}' | uniq | sort | tr '\n' ' ' +} + +_bash-it-component-list-matching() { + local component="$1"; shift + local term="$1" + _bash-it-component-help "${component}" | $(_bash-it-grep) -E -- "${term}" | awk '{print $1}' | sort | uniq +} + +_bash-it-component-list-enabled() { + local component="$1" + _bash-it-component-help "${component}" | $(_bash-it-grep) -E '\[x\]' | awk '{print $1}' | uniq | sort | tr '\n' ' ' +} + +_bash-it-component-list-disabled() { + local component="$1" + _bash-it-component-help "${component}" | $(_bash-it-grep) -E -v '\[x\]' | awk '{print $1}' | uniq | sort | tr '\n' ' ' +} + +# Checks if a given item is enabled for a particular component/file-type. +# Uses the component cache if available. +# +# Returns: +# 0 if an item of the component is enabled, 1 otherwise. +# +# Examples: +# _bash-it-component-item-is-enabled alias git && echo "git alias is enabled" +_bash-it-component-item-is-enabled() { + local component="$1" + local item="$2" + _bash-it-component-help "${component}" | $(_bash-it-grep) -E '\[x\]' | $(_bash-it-grep) -E -q -- "^${item}\s" +} + +# Checks if a given item is disabled for a particular component/file-type. +# Uses the component cache if available. +# +# Returns: +# 0 if an item of the component is enabled, 1 otherwise. +# +# Examples: +# _bash-it-component-item-is-disabled alias git && echo "git aliases are disabled" +_bash-it-component-item-is-disabled() { + local component="$1" + local item="$2" + _bash-it-component-help "${component}" | $(_bash-it-grep) -E -v '\[x\]' | $(_bash-it-grep) -E -q -- "^${item}\s" +} diff --git a/test/lib/helpers.bats b/test/lib/helpers.bats index 563bc380..6c4f706a 100644 --- a/test/lib/helpers.bats +++ b/test/lib/helpers.bats @@ -2,6 +2,7 @@ load ../test_helper load ../../lib/composure +load ../../lib/utilities load ../../lib/search load ../../plugins/available/base.plugin diff --git a/test/lib/search.bats b/test/lib/search.bats index 29e861d7..56cda073 100644 --- a/test/lib/search.bats +++ b/test/lib/search.bats @@ -3,6 +3,7 @@ load ../test_helper load ../../lib/composure load ../../lib/helpers +load ../../lib/utilities load ../../lib/search load ../../plugins/available/base.plugin load ../../aliases/available/git.aliases @@ -27,6 +28,7 @@ function local_setup { rm -rf "$BASH_IT"/aliases/enabled rm -rf "$BASH_IT"/completion/enabled rm -rf "$BASH_IT"/plugins/enabled + rm -rf "$BASH_IT"/tmp/cache mkdir -p "$BASH_IT"/enabled mkdir -p "$BASH_IT"/aliases/enabled diff --git a/test/lib/utilities.bats b/test/lib/utilities.bats new file mode 100644 index 00000000..be21fa40 --- /dev/null +++ b/test/lib/utilities.bats @@ -0,0 +1,108 @@ +#!/usr/bin/env bats + +load ../test_helper +load ../../lib/composure +load ../../lib/helpers +load ../../lib/utilities +load ../../lib/search + +cite _about _param _example _group _author _version + +function local_setup { + mkdir -p "$BASH_IT" + lib_directory="$(cd "$(dirname "$0")" && pwd)" + # Use rsync to copy Bash-it to the temp folder + # rsync is faster than cp, since we can exclude the large ".git" folder + rsync -qavrKL -d --delete-excluded --exclude=.git $lib_directory/../../.. "$BASH_IT" + + rm -rf "$BASH_IT"/enabled + rm -rf "$BASH_IT"/aliases/enabled + rm -rf "$BASH_IT"/completion/enabled + rm -rf "$BASH_IT"/plugins/enabled + rm -rf "$BASH_IT"/tmp/cache + + mkdir -p "$BASH_IT"/enabled + mkdir -p "$BASH_IT"/aliases/enabled + mkdir -p "$BASH_IT"/completion/enabled + mkdir -p "$BASH_IT"/plugins/enabled +} + +function has_match() { + $(_bash-it-array-contains-element ${@}) && echo "has" "$1" +} + +function item_enabled() { + $(_bash-it-component-item-is-enabled ${@}) && echo "$1" "$2" "is enabled" +} + +function item_disabled() { + $(_bash-it-component-item-is-disabled ${@}) && echo "$1" "$2" "is disabled" +} + +@test "_bash-it-component-item-is-enabled() - for a disabled item" { + run item_enabled aliases svn + assert_line -n 0 '' +} + +@test "_bash-it-component-item-is-enabled() - for an enabled/disabled item" { + run bash-it enable alias svn + assert_line -n 0 'svn enabled with priority 150.' + + run item_enabled alias svn + assert_line -n 0 'alias svn is enabled' + + run bash-it disable alias svn + assert_line -n 0 'svn disabled.' + + run item_enabled alias svn + assert_line -n 0 '' +} + +@test "_bash-it-component-item-is-disabled() - for a disabled item" { + run item_disabled alias svn + assert_line -n 0 'alias svn is disabled' +} + +@test "_bash-it-component-item-is-disabled() - for an enabled/disabled item" { + run bash-it enable alias svn + assert_line -n 0 'svn enabled with priority 150.' + + run item_disabled alias svn + assert_line -n 0 '' + + run bash-it disable alias svn + assert_line -n 0 'svn disabled.' + + run item_disabled alias svn + assert_line -n 0 'alias svn is disabled' +} + +@test "_bash-it-array-contains-element() - when match is found, and is the first" { + declare -a fruits=(apple pear orange mandarin) + run has_match apple "${fruits[@]}" + assert_line -n 0 'has apple' +} + +@test "_bash-it-array-contains-element() - when match is found, and is the last" { + declare -a fruits=(apple pear orange mandarin) + run has_match mandarin "${fruits[@]}" + assert_line -n 0 'has mandarin' +} + +@test "_bash-it-array-contains-element() - when match is found, and is in the middle" { + declare -a fruits=(apple pear orange mandarin) + run has_match pear "${fruits[@]}" + assert_line -n 0 'has pear' +} + +@test "_bash-it-array-contains-element() - when match is found, and it has spaces" { + declare -a fruits=(apple pear orange mandarin "yellow watermelon") + run has_match "yellow watermelon" "${fruits[@]}" + assert_line -n 0 'has yellow watermelon' +} + +@test "_bash-it-array-contains-element() - when match is not found" { + declare -a fruits=(apple pear orange mandarin) + run has_match xyz "${fruits[@]}" + assert_line -n 0 '' +}