From bef3016c793a3b2702ad6c83b50a96bce01d4318 Mon Sep 17 00:00:00 2001 From: Benjamin Lupton Date: Wed, 8 Jan 2025 11:02:50 +0800 Subject: [PATCH] rethink fs-* and sudo-helper escalations `--optional` and `--required` deprecated `--sudo='' is now translated to `--sudo=no` `--optional=13` is now `--sudo=13` --- commands/echo-if-directory | 30 +++++------ commands/echo-if-directory.bash | 18 ------- commands/echo-if-executable | 30 +++++------ commands/echo-if-executable.bash | 18 ------- commands/echo-if-file | 31 +++++------- commands/echo-if-file.bash | 18 ------- commands/echo-if-present | 30 +++++------ commands/echo-if-present.bash | 19 ------- commands/fs-absolute | 12 ++--- commands/fs-dequarantine | 15 ++++-- commands/fs-parents | 7 ++- commands/fs-realpath | 7 ++- commands/fs-rm | 8 ++- commands/fs-structure | 7 ++- commands/fs-trim | 7 ++- commands/get-flag-value | 18 +++++-- commands/is-accessible | 49 +++++++++--------- commands/is-broken-symlink | 75 +++------------------------ commands/is-directory | 87 +++----------------------------- commands/is-empty-directory | 12 ++--- commands/is-empty-file | 12 ++--- commands/is-executable | 12 ++--- commands/is-file | 12 ++--- commands/is-missing | 12 ++--- commands/is-nonempty-file | 12 ++--- commands/is-not-directory | 12 ++--- commands/is-not-symlink | 12 ++--- commands/is-present | 12 ++--- commands/is-readable | 12 ++--- commands/is-symlink | 12 ++--- commands/is-writable | 12 ++--- commands/sudo-helper | 43 ++++++++-------- sources/tests.bash | 6 +-- 33 files changed, 237 insertions(+), 442 deletions(-) delete mode 100755 commands/echo-if-directory.bash delete mode 100755 commands/echo-if-executable.bash delete mode 100755 commands/echo-if-file.bash delete mode 100755 commands/echo-if-present.bash diff --git a/commands/echo-if-directory b/commands/echo-if-directory index 5af5c2778..7e9b2296b 100755 --- a/commands/echo-if-directory +++ b/commands/echo-if-directory @@ -3,10 +3,11 @@ function echo_if_directory_test() ( source "$DOROTHY/sources/bash.bash" echo-style --h1="TEST: $0" - eval-tester --name='no args' --status=22 --ignore-stderr \ + + eval-tester --name='no args' \ -- echo-if-directory -- - eval-tester --name='empty args' --status=22 \ + eval-tester --name='empty args' \ -- echo-if-directory -- '' '' eval-tester --name='missing' \ @@ -24,12 +25,6 @@ function echo_if_directory_test() ( eval-tester --name='dir then missing then file' --stdout="$DOROTHY" \ -- echo-if-directory -- "$DOROTHY" "$DOROTHY/this-does-not-exist" "$DOROTHY/README.md" - eval-tester --name='dir then file then invalid' --stdout="$DOROTHY" --status=22 \ - -- echo-if-directory -- "$DOROTHY" "$DOROTHY/README.md" '' - - eval-tester --name='dir then invalid then file' --stdout="$DOROTHY" --status=22 \ - -- echo-if-directory -- "$DOROTHY" '' "$DOROTHY/README.md" - # test working symlinks local dir_target dir_symlink file_target file_symlink dir_target="$(fs-temp --directory='echo-if-directory' --directory='dir_target' --touch)" @@ -71,11 +66,10 @@ function echo_if_directory() ( echo-lines ... | echo-if-directory [...options] OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [is-directory]. $(stdinargs_options_help --) @@ -99,7 +93,7 @@ function echo_if_directory() ( } # process - local item option_args=() option_sudo='no' option_user='' option_group='' + local item option_args=() option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift @@ -123,13 +117,17 @@ function echo_if_directory() ( # ===================================== # Action - local inputs=() + local paths=() function on_input { - inputs+=("$1") + local path="$1" + if is-directory --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- "$path"; then + paths+=("$path") + fi } function on_finish { - sudo-helper --inherit --optional --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- echo-if-directory.bash -- "${inputs[@]}" - return + if [[ ${#paths[@]} -ne 0 ]]; then + __print_lines "${paths[@]}" + fi } stdinargs "${option_args[@]}" diff --git a/commands/echo-if-directory.bash b/commands/echo-if-directory.bash deleted file mode 100755 index a43fad0ce..000000000 --- a/commands/echo-if-directory.bash +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -if [[ $1 == '--' ]]; then - shift -fi -if [[ $# -eq 0 ]]; then - exit 22 # EINVAL 22 Invalid argument -fi -while [[ $# -ne 0 ]]; do - if [[ -z $1 ]]; then - exit 22 # EINVAL 22 Invalid argument - fi - if [[ -d $1 ]]; then - printf '%s\n' "$1" - fi - shift -done -exit 0 diff --git a/commands/echo-if-executable b/commands/echo-if-executable index 22df8df44..c59f07790 100755 --- a/commands/echo-if-executable +++ b/commands/echo-if-executable @@ -3,10 +3,11 @@ function echo_if_executable_test() ( source "$DOROTHY/sources/bash.bash" echo-style --h1="TEST: $0" - eval-tester --name='no args' --status=22 --ignore-stderr \ + + eval-tester --name='no args' \ -- echo-if-executable -- - eval-tester --name='empty args' --status=22 \ + eval-tester --name='empty args' \ -- echo-if-executable -- '' '' eval-tester --name='missing' \ @@ -24,12 +25,6 @@ function echo_if_executable_test() ( eval-tester --name='dir then missing then file' --stdout="$DOROTHY"$'\n'"$DOROTHY/commands/dorothy" \ -- echo-if-executable -- "$DOROTHY" "$DOROTHY/this-does-not-exist" "$DOROTHY/commands/dorothy" - eval-tester --name='dir then file then invalid' --stdout="$DOROTHY"$'\n'"$DOROTHY/commands/dorothy" --status=22 \ - -- echo-if-executable -- "$DOROTHY" "$DOROTHY/commands/dorothy" '' - - eval-tester --name='dir then invalid then file' --stdout="$DOROTHY" --status=22 \ - -- echo-if-executable -- "$DOROTHY" '' "$DOROTHY/commands/dorothy" - # test working symlinks local dir_target dir_symlink file_target file_symlink dir_target="$(fs-temp --directory='echo-if-executable' --directory='dir_target' --touch)" @@ -74,11 +69,10 @@ function echo_if_executable() ( echo-lines ... | echo-if-executable [...options] OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [is-executable]. $(stdinargs_options_help --) @@ -102,7 +96,7 @@ function echo_if_executable() ( } # process - local item option_args=() option_sudo='no' option_user='' option_group='' + local item option_args=() option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift @@ -126,13 +120,17 @@ function echo_if_executable() ( # ===================================== # Action - local inputs=() + local paths=() function on_input { - inputs+=("$1") + local path="$1" + if is-executable --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- "$path"; then + paths+=("$path") + fi } function on_finish { - sudo-helper --inherit --optional --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- echo-if-executable.bash -- "${inputs[@]}" - return + if [[ ${#paths[@]} -ne 0 ]]; then + __print_lines "${paths[@]}" + fi } stdinargs "${option_args[@]}" diff --git a/commands/echo-if-executable.bash b/commands/echo-if-executable.bash deleted file mode 100755 index 4599e6d80..000000000 --- a/commands/echo-if-executable.bash +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -if [[ $1 == '--' ]]; then - shift -fi -if [[ $# -eq 0 ]]; then - exit 22 # EINVAL 22 Invalid argument -fi -while [[ $# -ne 0 ]]; do - if [[ -z $1 ]]; then - exit 22 # EINVAL 22 Invalid argument - fi - if [[ -x $1 ]]; then - printf '%s\n' "$1" - fi - shift -done -exit 0 diff --git a/commands/echo-if-file b/commands/echo-if-file index 4620c8706..a47cb5700 100755 --- a/commands/echo-if-file +++ b/commands/echo-if-file @@ -3,10 +3,11 @@ function echo_if_file_test() ( source "$DOROTHY/sources/bash.bash" echo-style --h1="TEST: $0" - eval-tester --name='no args' --status=22 --ignore-stderr \ + + eval-tester --name='no args' \ -- echo-if-file -- - eval-tester --name='empty args' --status=22 \ + eval-tester --name='empty args' \ -- echo-if-file -- '' '' eval-tester --name='missing' \ @@ -24,12 +25,6 @@ function echo_if_file_test() ( eval-tester --name='dir then missing then file' --stdout="$DOROTHY/README.md" \ -- echo-if-file -- "$DOROTHY" "$DOROTHY/this-does-not-exist" "$DOROTHY/README.md" - eval-tester --name='dir then file then invalid' --stdout="$DOROTHY/README.md" --status=22 \ - -- echo-if-file -- "$DOROTHY" "$DOROTHY/README.md" '' - - eval-tester --name='dir then invalid then file' --status=22 \ - -- echo-if-file -- "$DOROTHY" '' "$DOROTHY/README.md" - # test working symlinks local dir_target dir_symlink file_target file_symlink dir_target="$(fs-temp --directory='echo-if-file' --directory='dir_target' --touch)" @@ -71,11 +66,10 @@ function echo_if_file() ( echo-lines ... | echo-if-file [...options] OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [is-file]. $(stdinargs_options_help --) @@ -99,7 +93,7 @@ function echo_if_file() ( } # process - local item option_args=() option_sudo='no' option_user='' option_group='' + local item option_args=() option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift @@ -123,15 +117,18 @@ function echo_if_file() ( # ===================================== # Action - local inputs=() + local paths=() function on_input { - inputs+=("$1") + local path="$1" + if is-file --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- "$path"; then + paths+=("$path") + fi } function on_finish { - sudo-helper --inherit --optional --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- echo-if-file.bash -- "${inputs[@]}" - return + if [[ ${#paths[@]} -ne 0 ]]; then + __print_lines "${paths[@]}" + fi } - stdinargs "${option_args[@]}" ) diff --git a/commands/echo-if-file.bash b/commands/echo-if-file.bash deleted file mode 100755 index 875d0f7eb..000000000 --- a/commands/echo-if-file.bash +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -if [[ $1 == '--' ]]; then - shift -fi -if [[ $# -eq 0 ]]; then - exit 22 # EINVAL 22 Invalid argument -fi -while [[ $# -ne 0 ]]; do - if [[ -z $1 ]]; then - exit 22 # EINVAL 22 Invalid argument - fi - if [[ -f $1 ]]; then - printf '%s\n' "$1" - fi - shift -done -exit 0 diff --git a/commands/echo-if-present b/commands/echo-if-present index 67c30a630..99723ff93 100755 --- a/commands/echo-if-present +++ b/commands/echo-if-present @@ -3,10 +3,11 @@ function echo_if_present_test() ( source "$DOROTHY/sources/bash.bash" echo-style --h1="TEST: $0" - eval-tester --name='no args' --status=22 --ignore-stderr \ + + eval-tester --name='no args' \ -- echo-if-present -- - eval-tester --name='empty args' --status=22 \ + eval-tester --name='empty args' \ -- echo-if-present -- '' '' eval-tester --name='missing' \ @@ -24,12 +25,6 @@ function echo_if_present_test() ( eval-tester --name='dir then missing then file' --stdout="$DOROTHY"$'\n'"$DOROTHY/README.md" \ -- echo-if-present -- "$DOROTHY" "$DOROTHY/this-does-not-exist" "$DOROTHY/README.md" - eval-tester --name='dir then file then invalid' --stdout="$DOROTHY"$'\n'"$DOROTHY/README.md" --status=22 \ - -- echo-if-present -- "$DOROTHY" "$DOROTHY/README.md" '' - - eval-tester --name='dir then invalid then file' --stdout="$DOROTHY" --status=22 \ - -- echo-if-present -- "$DOROTHY" '' "$DOROTHY/README.md" - # test working symlinks local dir_target dir_symlink file_target file_symlink dir_target="$(fs-temp --directory='echo-if-present' --directory='dir_target' --touch)" @@ -71,11 +66,10 @@ function echo_if_present() ( echo-lines ... | echo-if-present [...options] OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [is-present]. $(stdinargs_options_help --) @@ -99,7 +93,7 @@ function echo_if_present() ( } # process - local item option_args=() option_sudo='no' option_user='' option_group='' + local item option_args=() option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift @@ -123,13 +117,17 @@ function echo_if_present() ( # ===================================== # Action - local inputs=() + local paths=() function on_input { - inputs+=("$1") + local path="$1" + if is-present --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- "$path"; then + paths+=("$path") + fi } function on_finish { - sudo-helper --inherit --optional --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- echo-if-present.bash -- "${inputs[@]}" - return + if [[ ${#paths[@]} -ne 0 ]]; then + __print_lines "${paths[@]}" + fi } stdinargs "${option_args[@]}" diff --git a/commands/echo-if-present.bash b/commands/echo-if-present.bash deleted file mode 100755 index f06ee6bdd..000000000 --- a/commands/echo-if-present.bash +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -if [[ $1 == '--' ]]; then - shift -fi -if [[ $# -eq 0 ]]; then - exit 22 # EINVAL 22 Invalid argument -fi -while [[ $# -ne 0 ]]; do - if [[ -z $1 ]]; then - exit 22 # EINVAL 22 Invalid argument - fi - # just -e is faulty, as -e fails on broken symlinks - if [[ -e $1 || -L $1 ]]; then - printf '%s\n' "$1" - fi - shift -done -exit 0 diff --git a/commands/fs-absolute b/commands/fs-absolute index cf49828be..a8d6333b1 100755 --- a/commands/fs-absolute +++ b/commands/fs-absolute @@ -15,11 +15,11 @@ function fs_absolute() ( fs-absolute [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. EXAMPLES: fs-absolute -- .. @@ -37,14 +37,14 @@ function fs_absolute() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -66,7 +66,7 @@ function fs_absolute() ( # ===================================== # Act - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- fs-absolute.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- fs-absolute.bash -- "${option_inputs[@]}" return ) diff --git a/commands/fs-dequarantine b/commands/fs-dequarantine index ca595d5e8..3a7162624 100755 --- a/commands/fs-dequarantine +++ b/commands/fs-dequarantine @@ -12,7 +12,14 @@ function fs_dequarantine() ( Remove the quarantine flag from a path. USAGE: - fs-dequarantine [--] ... + fs-dequarantine [...options] [--] ... + + OPTIONS: + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. + --user= + --group= + Forwarded to [sudo-helper]. RETURNS: [0] if all s were not quarantined or successfully dequarantined @@ -27,14 +34,14 @@ function fs_dequarantine() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -62,7 +69,7 @@ function fs_dequarantine() ( fi # invoke with sudo escalation enabled by default - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- fs-dequarantine.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- fs-dequarantine.bash -- "${option_inputs[@]}" return ) diff --git a/commands/fs-parents b/commands/fs-parents index 60bce8dce..2466f08e4 100755 --- a/commands/fs-parents +++ b/commands/fs-parents @@ -20,11 +20,10 @@ function fs_parents() ( --root If specified, include the root directory in the output. - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [fs-absolute]. QUIRKS: Use [fs-realpath] if you want symlinks resolved. @@ -36,7 +35,7 @@ function fs_parents() ( } # process - local item option_paths=() option_self='no' option_root='no' option_sudo='no' option_user='' option_group='' + local item option_paths=() option_self='no' option_root='no' option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift diff --git a/commands/fs-realpath b/commands/fs-realpath index dacbd6cde..cec2e2e3d 100755 --- a/commands/fs-realpath +++ b/commands/fs-realpath @@ -33,11 +33,10 @@ function fs_realpath() ( --relative-base= If provided, print absolute paths unless paths below DIR - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper] and [is-symlink]. QUIRKS: If you don't care about symlinks, you should prefer to use [fs-absolute] instead as it is simpler. @@ -50,7 +49,7 @@ function fs_realpath() ( } # options - local item option_paths=() option_resolve='yes' option_validate='yes' option_relative='no' option_relative_to='' option_relative_base='' option_sudo='no' option_user='' option_group='' + local item option_paths=() option_resolve='yes' option_validate='yes' option_relative='no' option_relative_to='' option_relative_base='' option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift diff --git a/commands/fs-rm b/commands/fs-rm index bf964d6ce..9c56fdc9b 100755 --- a/commands/fs-rm +++ b/commands/fs-rm @@ -32,12 +32,10 @@ function fs_rm() ( --optional If specified, doesn't fail if no s were provided. - --sudo - If specified, use sudo when removing the files. - + --sudo= --user= --group= - If specified run the removal commands as this and . + Forwarded to [sudo-helper]. --readable Make the and its content readable. @@ -67,7 +65,7 @@ function fs_rm() ( } # process - local item option_quiet='no' option_inputs=() option_reason='' option_optional='no' option_confirm='' option_confirm_if_empty='' option_sudo='no' option_user='' option_group='' option_readable='' option_trim='' option_trash='' option_delete='' option_preferences=() + local item option_quiet='no' option_inputs=() option_reason='' option_optional='no' option_confirm='' option_confirm_if_empty='' option_sudo='' option_user='' option_group='' option_readable='' option_trim='' option_trash='' option_delete='' option_preferences=() while [[ $# -ne 0 ]]; do item="$1" shift diff --git a/commands/fs-structure b/commands/fs-structure index d33a13ef4..de11801ff 100755 --- a/commands/fs-structure +++ b/commands/fs-structure @@ -43,11 +43,10 @@ function fs_structure() ( --no-color If specified, don't use colors. - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper], [is-missing], [fs-absolute], [is-empty-directory]. EOF if [[ $# -ne 0 ]]; then echo-error "$@" @@ -56,7 +55,7 @@ function fs_structure() ( } # process - local item option_inputs=() option_sudo='no' option_user='' option_group='' option_perms='' option_time='' option_eza='' option_color + local item option_inputs=() option_sudo='' option_user='' option_group='' option_perms='' option_time='' option_eza='' option_color option_color="$(get-terminal-color-support --fallback=yes -- "$@")" while [[ $# -ne 0 ]]; do item="$1" diff --git a/commands/fs-trim b/commands/fs-trim index c82a00f23..34ab4154d 100755 --- a/commands/fs-trim +++ b/commands/fs-trim @@ -127,11 +127,10 @@ function fs_trim() ( If disabled, do not confirm the actions. If empty, confirm only the default action. - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper] and various filesystem commands. --cache If provided, paths of these case-insensitive filenames will be removed: ${cache_filenames[*]} @@ -158,7 +157,7 @@ function fs_trim() ( } # process - local item option_quiet='' option_inputs=() option_sudo='no' option_user='' option_group='' option_confirm='' option_all='' option_cache='' option_module='' option_empty_files='' option_broken_symlinks='' option_empty_directories='' + local item option_quiet='' option_inputs=() option_sudo='' option_user='' option_group='' option_confirm='' option_all='' option_cache='' option_module='' option_empty_files='' option_broken_symlinks='' option_empty_directories='' while [[ $# -ne 0 ]]; do item="$1" shift diff --git a/commands/get-flag-value b/commands/get-flag-value index 0d223a214..ac34319c7 100755 --- a/commands/get-flag-value +++ b/commands/get-flag-value @@ -187,6 +187,9 @@ function get_flag_value() ( --fallback= | --missing= When the flag is missing, use as the value. + --fallback-on-empty + When the flag is empty, use the fallback value. + --affirmative Parse the flag as an affirmative value, e.g. [yes] or [no] @@ -203,7 +206,7 @@ function get_flag_value() ( } # process - local item option_name='' option_multi=no option_fallback='' option_boolean='no' option_invert='no' + local item option_name='' option_multi=no option_fallback='' option_boolean='no' option_invert='no' option_fallback_on_empty='no' while [[ $# -ne 0 ]]; do item="$1" shift @@ -211,6 +214,7 @@ function get_flag_value() ( '--help' | '-h') help ;; '--multi') option_multi='yes' ;; '--fallback='* | '--missing='*) option_fallback="${item#*=}" ;; + '--fallback-on-empty') option_fallback_on_empty='yes' ;; '--affirmative') option_boolean='yes' ;; '--non-affirmative') option_boolean='yes' @@ -231,7 +235,7 @@ function get_flag_value() ( # ===================================== # Action - local found='no' name inverted index value + local name inverted index value values=() had_nonempty_value='no' for item in "$@"; do # prepare name="$option_name" @@ -257,7 +261,6 @@ function get_flag_value() ( # not our specific flag continue fi - found='yes' # fallback the name if [[ -z $name ]]; then @@ -300,7 +303,10 @@ function get_flag_value() ( fi # output - __print_lines "$value" + values+=("$value") + if [[ -n $value ]]; then + had_nonempty_value='yes' + fi # if single, one result is all we want if [[ $option_multi == 'no' ]]; then @@ -309,12 +315,14 @@ function get_flag_value() ( done # handle missing case - if [[ $found == 'no' ]]; then + if [[ ($had_nonempty_value == 'no' && $option_fallback_on_empty == 'yes') || ${#values[@]} -eq 0 ]]; then if [[ -n $option_fallback ]]; then __print_lines "$option_fallback" else return 91 # ENOMSG 91 No message of desired type fi + else + __print_lines "${values[@]}" fi ) diff --git a/commands/is-accessible b/commands/is-accessible index a18ba6453..7b0b2f6b0 100755 --- a/commands/is-accessible +++ b/commands/is-accessible @@ -10,7 +10,7 @@ function is_accessible_test() ( eval-tester --name='no args' --status=22 --ignore-stderr \ -- "$command" -- - # test escalation + # test no escalation local tuples=( 22 '' @@ -21,17 +21,17 @@ function is_accessible_test() ( 0 "$root/targets/subdir/empty-file" 0 "$root/targets/subdir/file" 0 "$root/targets/non-accessible-dir" - 0 "$root/targets/non-accessible-dir/subdir" - 0 "$root/targets/non-accessible-dir/subdir/empty-dir" - 0 "$root/targets/non-accessible-dir/subdir/empty-file" - 0 "$root/targets/non-accessible-dir/subdir/file" + 13 "$root/targets/non-accessible-dir/subdir" + 13 "$root/targets/non-accessible-dir/subdir/empty-dir" + 13 "$root/targets/non-accessible-dir/subdir/empty-file" + 13 "$root/targets/non-accessible-dir/subdir/file" 0 "$root/targets/non-accessible-empty-file" 0 "$root/targets/non-accessible-file" 0 "$root/targets/non-executable-dir" - 0 "$root/targets/non-executable-dir/subdir" - 0 "$root/targets/non-executable-dir/subdir/empty-dir" - 0 "$root/targets/non-executable-dir/subdir/empty-file" - 0 "$root/targets/non-executable-dir/subdir/file" + 13 "$root/targets/non-executable-dir/subdir" + 13 "$root/targets/non-executable-dir/subdir/empty-dir" + 13 "$root/targets/non-executable-dir/subdir/empty-file" + 13 "$root/targets/non-executable-dir/subdir/file" 0 "$root/targets/non-executable-empty-file" 0 "$root/targets/non-executable-file" 0 "$root/targets/non-readable-dir" @@ -56,17 +56,17 @@ function is_accessible_test() ( 0 "$root/symlinks/non-accessible-dir" 0 "$root/symlinks/non-accessible-empty-file" 0 "$root/symlinks/non-accessible-file" - 0 "$root/symlinks/non-accessible-subdir-empty-dir" - 0 "$root/symlinks/non-accessible-subdir-empty-file" - 0 "$root/symlinks/non-accessible-subdir-file" - 0 "$root/symlinks/non-accessible-subdir" + 13 "$root/symlinks/non-accessible-subdir-empty-dir" + 13 "$root/symlinks/non-accessible-subdir-empty-file" + 13 "$root/symlinks/non-accessible-subdir-file" + 13 "$root/symlinks/non-accessible-subdir" 0 "$root/symlinks/non-executable-dir" 0 "$root/symlinks/non-executable-empty-file" 0 "$root/symlinks/non-executable-file" - 0 "$root/symlinks/non-executable-subdir-empty-dir" - 0 "$root/symlinks/non-executable-subdir-empty-file" - 0 "$root/symlinks/non-executable-subdir-file" - 0 "$root/symlinks/non-executable-subdir" + 13 "$root/symlinks/non-executable-subdir-empty-dir" + 13 "$root/symlinks/non-executable-subdir-empty-file" + 13 "$root/symlinks/non-executable-subdir-file" + 13 "$root/symlinks/non-executable-subdir" 0 "$root/symlinks/non-readable-dir" 0 "$root/symlinks/non-readable-empty-file" 0 "$root/symlinks/non-readable-file" @@ -82,7 +82,7 @@ function is_accessible_test() ( 0 "$root/symlinks/non-writable-subdir-file" 0 "$root/symlinks/non-writable-subdir" ) - fs_tests__tuples --group='test escalation' "$command" --sudo -- "${tuples[@]}" + fs_tests__tuples --group='test escalation' "$command" --no-sudo -- "${tuples[@]}" # test default escalation tuples=( @@ -106,7 +106,7 @@ function is_accessible_test() ( ) fs_tests__tuples --group='test default escalation' "$command" -- "${tuples[@]}" - # test no escalation + # test with escalation tuples=( "$(fs_tests__root_status 0)" "$root/targets/non-accessible-dir/subdir" "$(fs_tests__root_status 0)" "$root/targets/non-accessible-dir/subdir/empty-dir" @@ -126,7 +126,7 @@ function is_accessible_test() ( "$(fs_tests__root_status 0)" "$root/symlinks/non-executable-subdir-file" "$(fs_tests__root_status 0)" "$root/symlinks/non-executable-subdir" ) - fs_tests__tuples --group='test no escalation' "$command" --no-sudo -- "${tuples[@]}" + fs_tests__tuples --group='test no escalation' "$command" --sudo -- "${tuples[@]}" # break the symlinks sudo-helper -- rm -rf "$root/targets" @@ -184,11 +184,10 @@ function is_accessible() ( is-accessible [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were accessible @@ -201,7 +200,7 @@ function is_accessible() ( } # process - local item option_inputs=() option_sudo='no' option_user='' option_group='' + local item option_inputs=() option_sudo='' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift @@ -230,7 +229,7 @@ function is_accessible() ( # ===================================== # Action - sudo-helper --inherit --optional --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-accessible.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-accessible.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-broken-symlink b/commands/is-broken-symlink index 5ff84f22a..16aa8c5aa 100755 --- a/commands/is-broken-symlink +++ b/commands/is-broken-symlink @@ -1,69 +1,10 @@ #!/usr/bin/env bash function is_broken_symlink_test() ( - source "$DOROTHY/sources/bash.bash" + source "$DOROTHY/sources/tests.bash" echo-style --h1="TEST: $0" - # test standard paths - eval-tester --name='no args' --status=22 --ignore-stderr \ - -- is-broken-symlink -- - - eval-tester --name='empty args' --status=22 \ - -- is-broken-symlink -- '' '' - - eval-tester --name='missing' --status=2 \ - -- is-broken-symlink -- "$DOROTHY/this-does-not-exist" - - eval-tester --name='dir' --status=17 \ - -- is-broken-symlink -- "$DOROTHY" - - eval-tester --name='file' --status=17 \ - -- is-broken-symlink -- "$DOROTHY/README.md" - - # prep - local root dir_target dir_symlink file_target file_symlink - root="$(fs-temp --directory='is-broken-symlink-test')" - fs-rm --quiet --no-confirm -- "$root" - dir_target="$(fs-temp --root="$root" --directory='dir_target' --touch)" - file_target="$(fs-temp --root="$root" --file='file_target' --touch)" - dir_symlink="$(fs-temp --root="$root" --directory='dir_symlink' --no-touch)" - file_symlink="$(fs-temp --root="$root" --file='file_symlink' --no-touch)" - symlink-helper --existing="$dir_target" --symlink="$dir_symlink" --quiet - symlink-helper --existing="$file_target" --symlink="$file_symlink" --quiet - - # test working symlinks - eval-tester --name='symlink dir' --status=17 \ - -- is-broken-symlink -- "$dir_symlink" - - eval-tester --name='symlink file' --status=17 \ - -- is-broken-symlink -- "$file_symlink" - - eval-tester --name='symlink dir then dir' --status=17 \ - -- is-broken-symlink -- "$dir_symlink" "$DOROTHY" - - eval-tester --name='symlink file then file' --status=17 \ - -- is-broken-symlink -- "$file_symlink" "$DOROTHY/README.md" - - eval-tester --name='symlink file then missing' --status=17 \ - -- is-broken-symlink -- "$file_symlink" "$DOROTHY/this-does-not-exist" - - # test broken symlinks - fs-rm --quiet --no-confirm -- "$dir_target" "$file_target" - - eval-tester --name='broken symlink dir' \ - -- is-broken-symlink -- "$dir_symlink" - - eval-tester --name='broken symlink file' \ - -- is-broken-symlink -- "$file_symlink" - - eval-tester --name='broken symlink dir then dir' --status=79 \ - -- is-broken-symlink -- "$dir_symlink" "$DOROTHY" - - eval-tester --name='broken symlink file then file' --status=79 \ - -- is-broken-symlink -- "$file_symlink" "$DOROTHY/README.md" - - eval-tester --name='broken symlink file then missing' --status=2 \ - -- is-broken-symlink -- "$file_symlink" "$DOROTHY/this-does-not-exist" + # @todo echo-style --g1="TEST: $0" return 0 @@ -84,11 +25,11 @@ function is_broken_symlink() ( is-broken-symlink [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were broken symlinks @@ -105,14 +46,14 @@ function is_broken_symlink() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -134,7 +75,7 @@ function is_broken_symlink() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-broken-symlink.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-broken-symlink.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-directory b/commands/is-directory index 67319e6c4..894b216c5 100755 --- a/commands/is-directory +++ b/commands/is-directory @@ -1,81 +1,10 @@ #!/usr/bin/env bash function is_directory_test() ( - source "$DOROTHY/sources/bash.bash" + source "$DOROTHY/sources/tests.bash" echo-style --h1="TEST: $0" - # test standard paths - eval-tester --name='no args' --status=22 --ignore-stderr \ - -- is-directory -- - - eval-tester --name='empty args' --status=22 \ - -- is-directory -- '' '' - - eval-tester --name='missing' --status=2 \ - -- is-directory -- "$DOROTHY/this-does-not-exist" - - eval-tester --name='directory' \ - -- is-directory -- "$DOROTHY" - - eval-tester --name='file' --status=20 \ - -- is-directory -- "$DOROTHY/README.md" - - eval-tester --name='file then dir' --status=20 \ - -- is-directory -- "$DOROTHY/README.md" "$DOROTHY" - - eval-tester --name='dir then file' --status=20 \ - -- is-directory -- "$DOROTHY" "$DOROTHY/README.md" - - eval-tester --name='dir then file then invalid' --status=20 \ - -- is-directory -- "$DOROTHY" "$DOROTHY/README.md" '' - - eval-tester --name='dir then invalid then file' --status=22 \ - -- is-directory -- "$DOROTHY" '' "$DOROTHY/README.md" - - # prep - local root dir_target dir_symlink file_target file_symlink - root="$(fs-temp --directory='is-directory-test')" - fs-rm --quiet --no-confirm -- "$root" - dir_target="$(fs-temp --root="$root" --directory='dir_target' --touch)" - file_target="$(fs-temp --root="$root" --file='file_target' --touch)" - dir_symlink="$(fs-temp --root="$root" --directory='dir_symlink' --no-touch)" - file_symlink="$(fs-temp --root="$root" --file='file_symlink' --no-touch)" - symlink-helper --existing="$dir_target" --symlink="$dir_symlink" --quiet - symlink-helper --existing="$file_target" --symlink="$file_symlink" --quiet - - # test working symlinks - eval-tester --name='symlink dir' \ - -- is-directory -- "$dir_symlink" - - eval-tester --name='symlink file' --status=20 \ - -- is-directory -- "$file_symlink" - - eval-tester --name='symlink dir then dir' \ - -- is-directory -- "$dir_symlink" "$DOROTHY" - - eval-tester --name='symlink dir then file' --status=20 \ - -- is-directory -- "$dir_symlink" "$DOROTHY/README.md" - - eval-tester --name='symlink dir then missing' --status=2 \ - -- is-directory -- "$dir_symlink" "$DOROTHY/this-does-not-exist" - - # test broken symlinks - fs-rm --quiet --no-confirm -- "$dir_target" "$file_target" - - eval-tester --name='broken symlink dir' --status=9 \ - -- is-directory -- "$dir_symlink" - - eval-tester --name='broken symlink file' --status=9 \ - -- is-directory -- "$file_symlink" - - eval-tester --name='broken symlink dir then dir' --status=9 \ - -- is-directory -- "$dir_symlink" "$DOROTHY" - - eval-tester --name='broken symlink dir then file' --status=9 \ - -- is-directory -- "$dir_symlink" "$DOROTHY/README.md" - - eval-tester --name='broken symlink dir then missing' --status=9 \ - -- is-directory -- "$dir_symlink" "$DOROTHY/this-does-not-exist" + # @todo echo-style --g1="TEST: $0" return 0 @@ -96,11 +25,11 @@ function is_directory() ( is-directory [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were a directory, or an unbroken symlink to a directory @@ -117,14 +46,14 @@ function is_directory() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -146,7 +75,7 @@ function is_directory() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-directory.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-directory.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-empty-directory b/commands/is-empty-directory index 8e32a91d2..f0b2cf9a6 100755 --- a/commands/is-empty-directory +++ b/commands/is-empty-directory @@ -108,11 +108,11 @@ function is_empty_directory() ( is-empty-directory [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were a readable empty directory @@ -130,14 +130,14 @@ function is_empty_directory() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -159,7 +159,7 @@ function is_empty_directory() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-empty-directory.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-empty-directory.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-empty-file b/commands/is-empty-file index be0362ce6..fce9f6471 100755 --- a/commands/is-empty-file +++ b/commands/is-empty-file @@ -101,11 +101,11 @@ function is_empty_file() ( is-empty-file [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were a readable zero-length file @@ -123,14 +123,14 @@ function is_empty_file() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -152,7 +152,7 @@ function is_empty_file() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-empty-file.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-empty-file.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-executable b/commands/is-executable index 5e90a9ae4..7fc16efc7 100755 --- a/commands/is-executable +++ b/commands/is-executable @@ -110,11 +110,11 @@ function is_executable() ( is-executable [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s are executable @@ -131,14 +131,14 @@ function is_executable() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -160,7 +160,7 @@ function is_executable() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-executable.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-executable.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-file b/commands/is-file index 4f9d6ca5c..0af80008f 100755 --- a/commands/is-file +++ b/commands/is-file @@ -75,11 +75,11 @@ function is_file() ( is-file [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were a file @@ -96,14 +96,14 @@ function is_file() ( } # process - local item option_inputs=() option_sudo='no' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -125,7 +125,7 @@ function is_file() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-file.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-file.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-missing b/commands/is-missing index 8ebeb4a83..d268a38f7 100755 --- a/commands/is-missing +++ b/commands/is-missing @@ -78,11 +78,11 @@ function is_missing() ( is-missing [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were missing (not even a broken symlink). @@ -97,14 +97,14 @@ function is_missing() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -126,7 +126,7 @@ function is_missing() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-missing.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-missing.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-nonempty-file b/commands/is-nonempty-file index fb510464b..2d24f8c30 100755 --- a/commands/is-nonempty-file +++ b/commands/is-nonempty-file @@ -101,11 +101,11 @@ function is_nonempty_file() ( is-nonempty-file [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were a readable non-zero-length file @@ -123,14 +123,14 @@ function is_nonempty_file() ( } # process - local item option_inputs=() option_sudo='no' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -152,7 +152,7 @@ function is_nonempty_file() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-nonempty-file.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-nonempty-file.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-not-directory b/commands/is-not-directory index 373bfbd86..994e3c8be 100755 --- a/commands/is-not-directory +++ b/commands/is-not-directory @@ -100,11 +100,11 @@ function is_not_directory() ( is-not-directory [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s existed, and were neither a directory, nor an unbroken symlink to a directory @@ -121,14 +121,14 @@ function is_not_directory() ( } # process - local item option_inputs=() option_sudo='no' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -150,7 +150,7 @@ function is_not_directory() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-not-directory.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-not-directory.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-not-symlink b/commands/is-not-symlink index ee6b2bab1..dd975ee23 100755 --- a/commands/is-not-symlink +++ b/commands/is-not-symlink @@ -84,11 +84,11 @@ function is_not_symlink() ( is-not-symlink [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s existed and were not a symlink (broken or otherwise) @@ -104,14 +104,14 @@ function is_not_symlink() ( } # process - local item option_inputs=() option_sudo='no' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -133,7 +133,7 @@ function is_not_symlink() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-not-symlink.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-not-symlink.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-present b/commands/is-present index 4e3a47820..8230dbcb3 100755 --- a/commands/is-present +++ b/commands/is-present @@ -79,11 +79,11 @@ function is_present() ( is-present [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were present (file, directory, symlink, broken symlink). @@ -98,14 +98,14 @@ function is_present() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -127,7 +127,7 @@ function is_present() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-present.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-present.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-readable b/commands/is-readable index c9a7fbf69..b00b40ce6 100755 --- a/commands/is-readable +++ b/commands/is-readable @@ -105,11 +105,11 @@ function is_readable() ( is-readable [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s are readable @@ -126,14 +126,14 @@ function is_readable() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -155,7 +155,7 @@ function is_readable() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-readable.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-readable.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-symlink b/commands/is-symlink index 1b6911275..ca0dad298 100755 --- a/commands/is-symlink +++ b/commands/is-symlink @@ -78,11 +78,11 @@ function is_symlink() ( is-symlink [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s were a symlink (broken or otherwise, accessible or otherwise) @@ -98,14 +98,14 @@ function is_symlink() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -127,7 +127,7 @@ function is_symlink() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-symlink.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-symlink.bash -- "${option_inputs[@]}" return ) diff --git a/commands/is-writable b/commands/is-writable index e0f5f9442..09a6fd35b 100755 --- a/commands/is-writable +++ b/commands/is-writable @@ -103,11 +103,11 @@ function is_writable() ( is-writable [...options] [--] ... OPTIONS: - --sudo - If specified, use sudo on filesystem interactions. + --sudo= + Defaults to [13], escalating to root if permission would otherwise be denied. --user= --group= - If specified use this user and/or group for filesystem interactions. + Forwarded to [sudo-helper]. RETURNS: [0] if all s are writable @@ -124,14 +124,14 @@ function is_writable() ( } # process - local item option_inputs=() option_sudo='yes' option_user='' option_group='' + local item option_inputs=() option_sudo='13' option_user='' option_group='' while [[ $# -ne 0 ]]; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--no-sudo'* | '--sudo'*) - option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + option_sudo="$(get-flag-value --affirmative --fallback-on-empty --fallback="$option_sudo" -- "$item")" ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; @@ -153,7 +153,7 @@ function is_writable() ( # ===================================== # Action - sudo-helper --inherit --optional=13 --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-writable.bash -- "${option_inputs[@]}" + sudo-helper --inherit --sudo="$option_sudo" --user="$option_user" --group="$option_group" -- is-writable.bash -- "${option_inputs[@]}" return ) diff --git a/commands/sudo-helper b/commands/sudo-helper index c24693e5e..02475150c 100755 --- a/commands/sudo-helper +++ b/commands/sudo-helper @@ -10,7 +10,7 @@ function sudo_helper() ( function help { cat <<-EOF >/dev/stderr ABOUT: - Run a command as root, be it via sudo or doas, or neither if not needed. + Run the command with escalation to root, be it via sudo or doas, or neither if not needed. USAGE: sudo-helper [...options] -- [...args] @@ -18,16 +18,17 @@ function sudo_helper() ( OPTIONS: --reason= - If a prompt is required for your sudo/root/login password, this reason will be used to explain why sudo was required. + If a prompt is required for your sudo/root/login password, this reason will be used to explain why escalation was required. + --sudo=> + If specified as yes, the default, then the command will be escalated to root. + If specified as no or empty string, then the command will be run without escalation. + If specified as failure, then the command will be run without escalation, and if it fails, it will be run with escalation. + If specified as an integer, then the command will be run without escalation, and if it fails with that exit status, it will be run with escalation. --user= - Specify a user to run the command as. + Specify a user to run the command as. Forces --sudo=yes --group= - Specify a group to run the command as. - --sudo=no | --required=no - If specified, and no nor is provided, then sudo will not be used, and the command will be run normally. - --optional - If specified, and no nor is provided, then try the command first without sudo, and if it fails, try again with sudo. + Specify a group to run the command as. Forces --sudo=yes --inherit If enabled, inherit environment variables include PATH. @@ -51,7 +52,7 @@ function sudo_helper() ( # process # option_quiet='no' is an important default to ensure our call to eval-helper can still be interpolated - local item option_cmd=() option_quiet='no' option_reason='' option_user='' option_group='' option_required='yes' option_optional='no' option_confirm='no' option_wrap='no' option_inherit='no' option_local='' + local item option_cmd=() option_quiet='no' option_reason='' option_user='' option_group='' option_sudo='yes' option_optional='no' option_confirm='no' option_wrap='no' option_inherit='no' option_local='' while [[ $# -ne 0 ]]; do item="$1" shift @@ -64,14 +65,11 @@ function sudo_helper() ( option_quiet="$(get-flag-value --affirmative --fallback="$option_quiet" -- "$item")" ;; '--reason='*) option_reason="${item#*=}" ;; + '--no-sudo'* | '--sudo'*) + option_sudo="$(get-flag-value --affirmative --fallback="$option_sudo" -- "$item")" + ;; '--user='*) option_user="${item#*=}" ;; '--group='*) option_group="${item#*=}" ;; - '--no-sudo'* | '--sudo'* | '--no-required'* | '--required'*) - option_required="$(get-flag-value --affirmative --fallback="$option_required" -- "$item")" - ;; - '--no-optional'* | '--optional'*) - option_optional="$(get-flag-value --affirmative --fallback="$option_optional" -- "$item")" - ;; '--no-inherit'* | '--inherit'*) option_inherit="$(get-flag-value --affirmative --fallback="$option_inherit" -- "$item")" ;; @@ -133,10 +131,11 @@ function sudo_helper() ( help 'No was provided.' fi - # adjust + # ensure sudo is a valid value if [[ -n $option_user || -n $option_user ]]; then - option_required='yes' - option_optional='no' + option_sudo='yes' + elif [[ -z $option_sudo ]]; then + option_sudo='no' fi # ===================================== @@ -176,17 +175,17 @@ function sudo_helper() ( fi # try without sudo - if [[ $option_required == 'no' || $technique == 'none' ]]; then + if [[ $option_sudo == 'no' || $technique == 'none' ]]; then __wrap "${option_cmd[@]}" return - elif [[ $option_optional == 'yes' ]]; then + elif [[ $option_sudo == 'failure' ]]; then if __wrap "${option_cmd[@]}"; then return 0 fi - elif is-integer -- "$option_optional"; then + elif is-integer -- "$option_sudo"; then local status=0 __wrap "${option_cmd[@]}" || status=$? - if [[ $status -eq 0 || $status -ne $option_optional ]]; then + if [[ $status -eq 0 || $status -ne $option_sudo ]]; then return "$status" fi fi diff --git a/sources/tests.bash b/sources/tests.bash index 363325941..a5dd14340 100644 --- a/sources/tests.bash +++ b/sources/tests.bash @@ -134,7 +134,7 @@ function fs_tests__tuples { root="$(fs-temp --directory="$command")" # tests - if [[ -n "$group" ]]; then + if [[ -n $group ]]; then echo-style --h2="$group" fi local index status path total="${#tuples[@]}" result=0 @@ -148,12 +148,12 @@ function fs_tests__tuples { fi done if [[ $result -ne 0 ]]; then - if [[ -n "$group" ]]; then + if [[ -n $group ]]; then echo-style --e2="$group" fi return 1 fi - if [[ -n "$group" ]]; then + if [[ -n $group ]]; then echo-style --g2="$group" fi return 0