Skip to content

Commit

Permalink
huge reliability improvements
Browse files Browse the repository at this point in the history
- renamed all functions to use underscore, even command functions, as the distinction of function is essential to prevent errexit disablement
- use `eval_capture` from `bash.bash` to prevent errexit disabling on conditional function calls, applied to:
    - alias-helper
    - ask
    - choose-menu
    - choose-option
    - command-working
    - config-edit
    - config-helper
    - confirm
    - down
    - echo-affirmative
    - echo-exit-affirmative
    - echo-exit-code
    - echo-file
    - echo-non-affirmative
    - echo-style
    - eval-helper
    - eval-tester
    - fail
    - fetch
    - fs-own
    - fs-realpath
    - fs-rm
    - fs-size
    - get-devices
    - git-helper
    - gocryptfs-helper
    - macos-drive
    - macos-installer
    - mount-helper
    - secret
    - select-shell
    - setup-dns
    - setup-git
    - setup-linux
    - setup-mac-brew
    - setup-node
    - setup-util
    - ssh-helper
    - until-success
- ensure functions that are called conditionally have explicit returns, applied to:
    - debug-network
    - dorothy
    - get-devices
    - git-helper
    - mount-helper
    - read-key
    - select-hosts
    - setup-dns
    - setup-linux-fonts
    - setup-node
    - ssh-helper
- remove return traps for more reliable options, applied to:
    - confirm
    - fs-rm
    - fs-size
    - gocryptfs-helper
    - mount-helper
    - unziptar
- consistent exit code convention
    - correct timeout exit code to 60
    - correct stdinargs missing help exit code from 38 to 78
    - correct timeout detection from >= 128 to 142
        - this should allow ctrl+c to properly abort ask/confirm/choose
    - document exit codes >= 128 in read-key
    - `return $?` changed to `return`
    - `"$?"` changed to `$?`
- `bash.bash`
    - adjust defaults for better errexit shimming, add `eval_capture`
    - remove `require_nullglob` as it is supported by an early bash version
- ask:
    - removed unused `--flag=...` argument
    - correct an error not being output to stderr
- config-edit:
    - ensure `sponge` dependency is installed
- dorothy:
    - update defaults from `bash.bash`
    - fix bad USER export
    - execution of tests makes more sense
- down:
    - support `got`
    - use `get-installer` to fallback to first successful preference
    - better aria2c compatibility
    - preferences updated for best user experience
    - fixed failed downloads being reported as successful, thanks to new `eval_capture` usage
- echo-clear-lines:
    - enforce stdin usage rather than polyfill to it
- echo-quiet:
    - add better help
- eval-helper:
    - stderr now actually goes to stderr, thanks to learnigns and usage of `eval_capture`
- fs-realpath:
    - use `get-installer` to fallback to first successful preference
- fs-rm:
    - support `--trash` argument
    - don't output directory information for files
- get-installer:
    - support way more aliases
    - add tests
- get-os-theme and setup-environment-commands:
    - support `THEME` env var
        -  use `--refresh` to ignore `THEME` env var
        -  this dramatically speeds up performance for `echo-style`
    - quicker macos theme detection
    - fallback to light mode, rather than failing, if otherwise we were able to detect
- github-download:
    - ignore `sbom` extensions
    - fix broken ref/release logic
- get-url-upgrade:
    - better support for recursion
- add `is-appimage`
- macos-theme:
    - fix missing sponge dep
- macos-installer:
    - correct exit code, when installer fails discovery
    - remove peculiar cat usage
- secret:
    - use `fs-rm`
    - provide reason for sudo, thanks to new improvements to `sudo-helper`
    - alias `signin` and `signout`
- service-helper:
    - provide reason for sudo, thanks to new improvements to `sudo-helper`
- setup-mac:
    - use `fs-rm`
- setup-mac-brew:
    - fix missing sponge dep
- setup-node:
    - fix missing sd dep
- setup-util:
    - removed `github` method, use `download` instead
    - added `DOWNLOAD_BUILD_EVAL` and `DOWNLOAD_BUILD_FILTER`
    - uninstall now uninstalls from all package systems, rather than just the first succesful one
        - this fixes the issue where a utility that is installed in multiple package systems is still present after uninstall
        - this requires methods to detect if they are relevant when uninstalling
        - this improves the output to know exactly all the package systems that where used for the action
        - instead of always removing the XDG bin, we now let the methods figure that out
    - re-did and documented order preference, eliminating need for custom preferences in most cases
    - uninstalling tea packages now also removes the cache of the package
- setup-util-*:
    - rewrote for performance, and greater asset support
    - added `setup-util-got`
    - renamed `setup-util-kypton` to `setup-util-krypton`
    - added `setup-util-linux-purge` for removing old kernels
    - removed `setup-util-slap`
    - added `setup-util-trash`
- sudo-helper:
    - fix bad reason formatting
- twitter-helper:
    - use setup-util
- unziptar:
    - support DMG files
- docs:
    - replaced `coding/exit-return-codes` with `bash/errors`
- sources:
    - removed `strict.bash` it should have been purged when `bash.bash` was added
  • Loading branch information
balupton committed Aug 14, 2023
1 parent 107a34d commit 12e208e
Show file tree
Hide file tree
Showing 490 changed files with 7,938 additions and 4,817 deletions.
Empty file modified .editorconfig
100644 → 100755
Empty file.
Empty file modified .github/FUNDING.yml
100644 → 100755
Empty file.
Empty file modified .github/workflows/dorothy.yml
100644 → 100755
Empty file.
Empty file modified .trunk/configs/.markdownlint.yaml
100644 → 100755
Empty file.
Empty file modified .trunk/configs/.prettierrc.yaml
100644 → 100755
Empty file.
Empty file modified .trunk/configs/.shellcheckrc
100644 → 100755
Empty file.
Empty file modified .trunk/configs/.yamllint.yaml
100644 → 100755
Empty file.
Empty file modified .trunk/configs/eslint.config.js
100644 → 100755
Empty file.
Empty file modified .trunk/configs/ruff.toml
100644 → 100755
Empty file.
14 changes: 7 additions & 7 deletions .trunk/trunk.yaml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cli:
plugins:
sources:
- id: trunk
ref: v1.0.0
ref: v1.1.1
uri: https://github.com/trunk-io/plugins
runtimes:
enabled:
Expand All @@ -20,18 +20,18 @@ actions:
- trunk-upgrade-available
lint:
enabled:
- [email protected].347
- trufflehog@3.45.2
- [email protected].364
- trufflehog@3.48.0
- [email protected]
- [email protected]
- eslint@8.45.0
- flake8@6.0.0
- eslint@8.47.0
- flake8@6.1.0
- git-diff-check@SYSTEM
- [email protected]
- [email protected]
- [email protected]
- [email protected].0
- [email protected].280
- [email protected].1
- [email protected].284
- [email protected]
- [email protected]
- [email protected]
Expand Down
Empty file modified .vscode/extensions.json
100644 → 100755
Empty file.
Empty file modified .vscode/workspace.code-workspace
100644 → 100755
Empty file.
Empty file modified LICENSE.md
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
50 changes: 25 additions & 25 deletions commands/alias-helper
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash

function alias-helper() (
function alias_helper() (
source "$DOROTHY/sources/bash.bash"

# =====================================
Expand Down Expand Up @@ -33,7 +33,7 @@ function alias-helper() (
if test "$#" -ne 0; then
echo-error "$@"
fi
return 22 # Invalid argument
return 22 # EINVAL 22 Invalid argument
}

# process
Expand Down Expand Up @@ -76,7 +76,7 @@ function alias-helper() (

function get_alias_target {
local path="$1"
silent-stderr osascript <<-EOF
osascript 2>/dev/null <<-EOF
tell application "Finder"
set theItem to (POSIX file "$path") as alias
if the kind of theItem is "alias" then
Expand All @@ -90,32 +90,33 @@ function alias-helper() (
local path="$1" alias
if test -L "$path"; then
echo-style --bold+red="$path" ' ' --error='<- origin is a symlink not an alias' >/dev/stderr
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
elif test -e "$path"; then
alias="$(get_alias_origin "$path" || :)"
eval_capture --stdoutvar=alias -- get_alias_origin "$path"
if test -n "$alias"; then
# don't output anything, we are just verifying
return 0
else
echo-style --bold+red="$path" ' ' --error='<- origin is not an alias' >/dev/stderr
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
fi
else
echo-style --bold+red="$path" ' ' --error='<- origin does not exist' >/dev/stderr
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
fi
}

function do_target {
local path="$1" target
if do_verify "$path"; then
target="$(get_alias_target "$path" || :)"
local path="$1" target ec
eval_capture --statusvar=ec -- do_verify "$path"
if test "$ec" -eq 0; then
eval_capture --stdoutvar=target -- get_alias_target "$path"
if test -n "$target"; then
echo "$target" # output the target from the origin
return 0
else
echo-style --bold+red="$path" ' ' --error='<- alias target is broken' >/dev/stderr
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
fi
fi
}
Expand All @@ -124,26 +125,26 @@ function alias-helper() (
local path="$1" origin target

# verify
origin="$(get_alias_origin "$path" || :)"
eval_capture --stdoutvar=origin -- get_alias_origin "$path"
if test -z "$origin"; then
{
echo-style \
--bold+red="$path" \
$'\t' \
$'\t' --error='← not an alias'
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
} >/dev/stderr
fi

# target
target="$(get_alias_target "$path" || :)"
eval_capture --stdoutvar=target -- get_alias_target "$path"
if test -z "$target"; then
{
echo-style \
--bold="$origin" \
$'\t' \
$'\t' --error='← target broken'
return 9 # EBADF Bad file descriptor
return 9 # EBADF 9 Bad file descriptor
} >/dev/stderr
fi
if test ! -e "$target"; then
Expand All @@ -152,7 +153,7 @@ function alias-helper() (
--bold="$origin" \
--nocolor=$'\t' --color+dim=$'\t\t' --bold+red="$target" \
$'\t' --error='← target missing'
return 2 # ENOENT No such file or directory
return 2 # ENOENT 2 No such file or directory
} >/dev/stderr
fi

Expand All @@ -177,7 +178,7 @@ function alias-helper() (
else
{
echo-style --error='Invalid path or unsupported type:' ' ' --code="$path"
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
} >/dev/stderr
fi

Expand All @@ -201,26 +202,26 @@ function alias-helper() (
local path="$1" origin target

# verify alias
origin="$(get_alias_origin "$path" || :)"
eval_capture --stdoutvar=origin -- get_alias_origin "$path"
if test -z "$origin"; then
{
echo-style --bold+red="$path" ' ' --error='<- not an alias'
return 22 # EINVAL Invalid argument
return 22 # EINVAL 22 Invalid argument
} >/dev/stderr
fi

# verify target
target="$(get_alias_target "$path" || :)"
eval_capture --stdoutvar=target -- get_alias_target "$path"
if test -z "$target"; then
{
echo-style --bold="$origin" --dim='' --bold+red="$target" ' ' --error='← target broken'
return 9 # EBADF Bad file descriptor
return 9 # EBADF 9 Bad file descriptor
} >/dev/stderr
fi
if test ! -e "$target"; then
{
echo-style --bold="$origin" --dim='' --bold+red="$target" ' ' --error='← target missing'
return 2 # ENOENT No such file or directory
return 2 # ENOENT 2 No such file or directory
} >/dev/stderr
fi

Expand All @@ -239,14 +240,13 @@ function alias-helper() (

if test "$(type -t "do_$action")" = 'function'; then
"do_$action" "${args[@]}"
return "$?"
else
echo-style --error="Action [$action] not yet implemented." >/dev/stderr
return 78 # Function not implemented
return 78 # ENOSYS 78 Function not implemented
fi
)

# fire if invoked standalone
if test "$0" = "${BASH_SOURCE[0]}"; then
alias-helper "$@"
alias_helper "$@"
fi
79 changes: 38 additions & 41 deletions commands/ask
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,15 @@ function ask() (
--timeout=<seconds>
Specifies a custom timeout value in seconds.
--flag=<string> -- <...args>
Specifies a flag to search the arguments for, to set a default value.
EOF
if test "$#" -ne 0; then
echo-error "$@"
fi
return 22 # Invalid argument
return 22 # EINVAL 22 Invalid argument
}

# process
local item args=() option_question='' option_default='' option_password='no' option_required='no' option_confirm='no' option_timeout='' option_flag=''
local item args=() option_question='' option_default='' option_password='no' option_required='no' option_confirm='no' option_timeout=''
while test "$#" -ne 0; do
item="$1"
shift
Expand All @@ -53,7 +50,6 @@ function ask() (
'--question='*) option_question="${item#*--question=}" ;;
'--default='*) option_default="${item#*--default=}" ;;
'--timeout='*) option_timeout="${item#*--timeout=}" ;;
'--flag='*) option_flag="${item#*--flag=}" ;;
'--no-password'* | '--password'*)
option_password="$(get-flag-value password --missing="$option_password" -- "$item" | echo-affirmative)"
;;
Expand All @@ -73,23 +69,23 @@ function ask() (
esac
done

# prepare flags
local result read_flags=('-r')
# =====================================
# Action

# prepare
local RESULT ASKED='no'
if test -n "$option_default"; then
result="$option_default"
elif test -n "$option_flag"; then
result="$(get-flag-value "$option_flag" -- "${args[@]}")"
RESULT="$option_default"
else
result=''
RESULT=''
fi

# helpers
local asked='no'
function on_timeout {
if is-value "$result"; then
echo-style --notice="Ask timed out, using fallback value: " --code="$result" >/dev/stderr
if is-value "$RESULT"; then
echo-style --notice="Ask timed out, using fallback value: " --code="$RESULT" >/dev/stderr
sleep 5
echo "$result"
echo "$RESULT"
return 0
elif test "$option_required" = 'no'; then
echo-style --notice='Ask timed out, as the field was optional will use no value.' >/dev/stderr
Expand All @@ -98,54 +94,54 @@ function ask() (
else
echo-style --warning='Ask timed out, with no fallback.' >/dev/stderr
sleep 5
return 62 # Timer expired
return 60 # ETIMEDOUT 60 Operation timed out
fi
}
function ask {
function do_ask { # has sideffects: RESULT, ASKED
local ec
tty_auto
asked='yes' # not lcoal
ASKED='yes' # not lcoal
if test -n "${1-}"; then
echo "$1" >/dev/tty
fi
while true; do
ec=0 && read "${read_flags[@]}" -t 300 -r -p "> " result || ec="$?"
if test "$ec" -gt 128; then
return 62 # Timer expired
ec=0 && read -r -t 300 -r -p '> ' RESULT || ec=$?
if test "$ec" -eq 142; then
return 60 # ETIMEDOUT 60 Operation timed out
fi
if is-value "$result"; then
if is-value "$RESULT"; then
break
elif test "$option_required" = 'no'; then
result=''
RESULT=''
break
fi
done
validate
do_validate
}
function validate {
function do_validate {
local ec choice choices=()
if is-value "$result"; then
if is-value "$RESULT"; then
# we have a value, so go for it
if test "$option_confirm" != 'yes'; then
echo "$result"
echo "$RESULT"
return 0
fi
# proceed with confirm
if test "$asked" = 'yes'; then
if test "$ASKED" = 'yes'; then
if test "$option_password" = 'yes'; then
choices+=('existing' 'use the entered password')
else
choices+=('existing' "use the entered value: [$result]")
choices+=('existing' "use the entered value: [$RESULT]")
fi
else
if test "$option_password" = 'yes'; then
choices+=('existing' 'use the preconfigured password')
else
choices+=('existing' "use the preconfigured value: [$result]")
choices+=('existing' "use the preconfigured value: [$RESULT]")
fi
fi
fi
if test "$asked" = 'yes'; then
if test "$ASKED" = 'yes'; then
choices+=('custom' 'redo the entered value')
else
choices+=('custom' 'enter a value')
Expand All @@ -155,22 +151,23 @@ function ask() (
fi

# as need to confirm, adjust the timeout
if test -z "$option_timeout" && (is-value "$result" || test "$option_required" = 'no'); then
if test -z "$option_timeout" && (is-value "$RESULT" || test "$option_required" = 'no'); then
# timeout of one minute for confirms of existing values, or optional values
option_timeout=60
fi

# ask
ec=0 && choice="$(choose-option \
eval_capture --statusvar=ec --stdoutvar=choice -- \
choose-option \
--timeout="$option_timeout" \
--question="$option_question" \
--label -- "${choices[@]}")" || ec="$?"
--label -- "${choices[@]}"

# check
if test "$ec" -eq 62; then
if test "$ec" -eq 60; then
echo-style --error="Choose timed out: $ec" >/dev/stderr
on_timeout
return "$?"
return
elif test "$ec" -ne 0; then
echo-style --error="Choose failed: $ec" >/dev/stderr
sleep 5
Expand All @@ -180,17 +177,17 @@ function ask() (
# handle
if test "$choice" = 'existing'; then
# done, sucess
echo "$result"
echo "$RESULT"
return 0
elif test "$choice" = 'custom'; then
# ask
ec=0 && ask "$option_question" || ec="$?"
eval_capture --statusvar=ec -- do_ask "$option_question"

# check for failure
if test "$ec" -ne 0; then
# timeout probably
on_timeout
return "$?"
return
fi

# done, success
Expand All @@ -208,7 +205,7 @@ function ask() (
}

# act
validate
do_validate
)

# fire if invoked standalone
Expand Down
Loading

0 comments on commit 12e208e

Please sign in to comment.