valise-sh 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +152 -2
- package/README.md +99 -146
- package/bin/valise +57 -5376
- package/docs/architecture.md +77 -121
- package/docs/contrib-modules.md +172 -218
- package/docs/installation.md +137 -83
- package/docs/module-abi.md +125 -126
- package/docs/projects.md +249 -0
- package/docs/release-policy.md +68 -93
- package/docs/shared-modules.md +40 -39
- package/examples/README.md +12 -11
- package/examples/e2e/README.md +59 -66
- package/examples/e2e/bundles.tsv +6 -0
- package/examples/e2e/module.d/e2e_aliases.meta +1 -2
- package/examples/e2e/module.d/e2e_completions_bash.meta +0 -1
- package/examples/e2e/module.d/e2e_completions_zsh.meta +0 -1
- package/examples/e2e/module.d/e2e_env_setup.meta +2 -3
- package/examples/e2e/module.d/e2e_fish_features.meta +0 -1
- package/examples/e2e/module.d/e2e_generated_config.meta +1 -2
- package/examples/e2e/module.d/e2e_ksh_features.meta +0 -1
- package/examples/e2e/module.d/e2e_layer_probe.meta +1 -2
- package/examples/e2e/module.d/e2e_optional_network.meta +1 -2
- package/examples/e2e/module.d/e2e_platform_tools.meta +8 -0
- package/examples/e2e/module.d/e2e_platform_tools_bsd.meta +2 -3
- package/examples/e2e/module.d/e2e_platform_tools_darwin.meta +2 -3
- package/examples/e2e/module.d/e2e_platform_tools_linux.meta +2 -3
- package/examples/e2e/valise.conf +4 -0
- package/examples/e2e/variants.tsv +3 -0
- package/examples/local/module.d/hello_valise.meta +1 -2
- package/examples/profile-project/README.md +78 -108
- package/examples/profile-project/bundles.tsv +8 -0
- package/examples/profile-project/{shell/layers → layers}/demo/module.d/contrib_demo_greeting.meta +1 -2
- package/examples/profile-project/{shell/module.d → module.d}/greeting.meta +1 -2
- package/examples/profile-project/{shell/module.d → module.d}/profile_main.meta +0 -1
- package/examples/profile-project/{shell/modules → modules}/greeting.sh +1 -1
- package/examples/profile-project/valise.conf +4 -0
- package/examples/profile-project/variants.tsv +3 -0
- package/examples/shared/README.md +13 -34
- package/examples/shared/module.d/contrib_shared_paths.meta +2 -3
- package/examples/shared/module.d/contrib_shared_umask.meta +1 -2
- package/examples/shared/modules/shared/contrib_shared_paths.sh +2 -2
- package/lib/capabilities.sh +40 -13
- package/lib/cli/commands.sh +278 -0
- package/lib/cli/common.sh +326 -0
- package/lib/cli/devtools.sh +539 -0
- package/lib/cli/fish-hook.sh +986 -0
- package/lib/cli/integration.sh +337 -0
- package/lib/cli/lifecycle.sh +578 -0
- package/lib/cli/project.sh +1807 -0
- package/lib/cli/store.sh +1023 -0
- package/lib/cli/usage.sh +308 -0
- package/lib/compiler.awk +11 -4
- package/lib/fish/loader.fish +69 -9
- package/lib/fish/metadata.fish +49 -5
- package/lib/fish/profile.fish +170 -0
- package/lib/loader.sh +6 -8
- package/lib/metadata.sh +111 -5
- package/manifests/parser-support.tsv +2 -2
- package/module.d/valise_editor.meta +9 -0
- package/module.d/valise_history.meta +9 -0
- package/module.d/valise_pager.meta +9 -0
- package/module.d/valise_path.meta +9 -0
- package/module.d/{platform_bsd.meta → valise_platform_bsd.meta} +3 -4
- package/module.d/{platform_linux.meta → valise_platform_linux.meta} +3 -4
- package/module.d/{platform_macos.meta → valise_platform_macos.meta} +3 -4
- package/module.d/{platform_posix.meta → valise_platform_posix.meta} +2 -3
- package/module.d/valise_xdg.meta +9 -0
- package/modules/system/{contrib_editor.sh → valise_editor.sh} +2 -2
- package/modules/system/{contrib_history.sh → valise_history.sh} +2 -2
- package/modules/system/{contrib_pager.sh → valise_pager.sh} +2 -2
- package/modules/system/{contrib_path.sh → valise_path.sh} +3 -3
- package/modules/system/{contrib_xdg.sh → valise_xdg.sh} +2 -2
- package/package.json +91 -10
- package/docs/variants.md +0 -327
- package/entrypoints/.gitkeep +0 -0
- package/entrypoints/fish/profile.fish +0 -99
- package/examples/e2e/build-manifest.sh +0 -138
- package/examples/local/.gitkeep +0 -0
- package/examples/profile-project/shell/release/bundle-roots +0 -9
- package/examples/profile-project/shell/release/install-variants +0 -3
- package/examples/profile-project/shell/release/module-registry.tsv +0 -4
- package/examples/profile-project/shell/release/project.conf +0 -3
- package/lib/.gitkeep +0 -0
- package/manifests/.gitkeep +0 -0
- package/module.d/.gitkeep +0 -0
- package/module.d/contrib_editor.meta +0 -10
- package/module.d/contrib_history.meta +0 -10
- package/module.d/contrib_pager.meta +0 -10
- package/module.d/contrib_path.meta +0 -10
- package/module.d/contrib_xdg.meta +0 -10
- package/modules/.gitkeep +0 -0
- /package/examples/profile-project/{shell/layers → layers}/demo/modules/shared/contrib_demo_greeting.sh +0 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# Copyright (c) 2026 Joseph Cumines
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# valise CLI: shared helpers, XDG roots, trusted utilities, file probes.
|
|
4
|
+
# Sourced by bin/valise; not executable on its own.
|
|
5
|
+
|
|
6
|
+
die() {
|
|
7
|
+
printf 'valise: error: %s\n' "$*" >&2
|
|
8
|
+
exit 1
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
info() {
|
|
12
|
+
printf 'valise: %s\n' "$*"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
# Verification failure reporting. The default mode aborts the command, which
|
|
16
|
+
# is what install and release use. Quiet mode returns a nonzero status
|
|
17
|
+
# instead, so a diagnostic command can report the failure and carry on. The
|
|
18
|
+
# message text is identical in both modes.
|
|
19
|
+
_verify_quiet=0
|
|
20
|
+
_verify_fail() {
|
|
21
|
+
if [ "$_verify_quiet" -eq 1 ]; then
|
|
22
|
+
printf 'valise: error: %s\n' "$*" >&2
|
|
23
|
+
return 1
|
|
24
|
+
fi
|
|
25
|
+
die "$*"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Lexically normalize an absolute path: collapse repeated slashes, drop "."
|
|
29
|
+
# segments, and resolve ".." against the preceding component. Relative paths
|
|
30
|
+
# are resolved against the physical working directory first.
|
|
31
|
+
path_normalize() {
|
|
32
|
+
_path_norm_value=$1
|
|
33
|
+
case "$_path_norm_value" in
|
|
34
|
+
/*) ;;
|
|
35
|
+
*) _path_norm_value=$(pwd -P)/$_path_norm_value ;;
|
|
36
|
+
esac
|
|
37
|
+
_path_norm_out=
|
|
38
|
+
if [ "${IFS+x}" = x ]; then
|
|
39
|
+
_path_norm_ifs_was_set=1
|
|
40
|
+
_path_norm_old_ifs=${IFS-}
|
|
41
|
+
else
|
|
42
|
+
_path_norm_ifs_was_set=0
|
|
43
|
+
_path_norm_old_ifs=
|
|
44
|
+
fi
|
|
45
|
+
case $- in
|
|
46
|
+
*f*) _path_norm_glob_was_set=1 ;;
|
|
47
|
+
*) _path_norm_glob_was_set=0 ;;
|
|
48
|
+
esac
|
|
49
|
+
set -f
|
|
50
|
+
IFS=/
|
|
51
|
+
for _path_norm_part in $_path_norm_value; do
|
|
52
|
+
case "$_path_norm_part" in
|
|
53
|
+
''|.) continue ;;
|
|
54
|
+
..)
|
|
55
|
+
case "$_path_norm_out" in
|
|
56
|
+
'') ;;
|
|
57
|
+
*/*) _path_norm_out=${_path_norm_out%/*} ;;
|
|
58
|
+
*) _path_norm_out= ;;
|
|
59
|
+
esac
|
|
60
|
+
continue
|
|
61
|
+
;;
|
|
62
|
+
esac
|
|
63
|
+
_path_norm_out=${_path_norm_out:+$_path_norm_out/}$_path_norm_part
|
|
64
|
+
done
|
|
65
|
+
if [ "$_path_norm_ifs_was_set" -eq 1 ]; then
|
|
66
|
+
IFS=$_path_norm_old_ifs
|
|
67
|
+
else
|
|
68
|
+
unset IFS
|
|
69
|
+
fi
|
|
70
|
+
if [ "$_path_norm_glob_was_set" -eq 0 ]; then
|
|
71
|
+
set +f
|
|
72
|
+
fi
|
|
73
|
+
printf '/%s\n' "$_path_norm_out"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# XDG defaults per install-contracts.md.
|
|
77
|
+
#
|
|
78
|
+
# The roots are normalized to absolute paths. A relative XDG_DATA_HOME would
|
|
79
|
+
# otherwise be written into the active symlink verbatim, and a relative
|
|
80
|
+
# symlink target resolves against the directory holding the link rather
|
|
81
|
+
# than the caller's working directory. The pointer would then dangle, and
|
|
82
|
+
# prune would compare the active release by a path spelling that never
|
|
83
|
+
# matches the release directory.
|
|
84
|
+
VALISE_XDG_DATA=$(path_normalize "${XDG_DATA_HOME:-$HOME/.local/share}/valise")
|
|
85
|
+
VALISE_XDG_CONFIG=$(path_normalize "${XDG_CONFIG_HOME:-$HOME/.config}/valise")
|
|
86
|
+
VALISE_XDG_STATE=$(path_normalize "${XDG_STATE_HOME:-$HOME/.local/state}/valise")
|
|
87
|
+
VALISE_RELEASES_DIR="$VALISE_XDG_DATA/releases"
|
|
88
|
+
VALISE_ACTIVE_LINK="$VALISE_XDG_CONFIG/active"
|
|
89
|
+
VALISE_LOCK_DIR="$VALISE_XDG_STATE/lock"
|
|
90
|
+
|
|
91
|
+
# POSIX path parent extraction avoids ambient dirname resolution in manifest
|
|
92
|
+
# discovery and every subsequent source/destination validation path.
|
|
93
|
+
path_parent() {
|
|
94
|
+
_path_parent_value=$1
|
|
95
|
+
# Strip trailing slashes so "out/" and "out" share one parent (".").
|
|
96
|
+
# Without this, path_parent("out/") is "out" itself: parent-mkdir creates
|
|
97
|
+
# the destination, the emptiness check treats it as pre-created-empty, and
|
|
98
|
+
# staging lands inside the destination (publish then fails ENOTEMPTY).
|
|
99
|
+
while [ "$_path_parent_value" != "/" ] &&
|
|
100
|
+
[ "${_path_parent_value%/}" != "$_path_parent_value" ]; do
|
|
101
|
+
_path_parent_value=${_path_parent_value%/}
|
|
102
|
+
done
|
|
103
|
+
case "$_path_parent_value" in
|
|
104
|
+
*/*)
|
|
105
|
+
_path_parent_value=${_path_parent_value%/*}
|
|
106
|
+
[ -n "$_path_parent_value" ] || _path_parent_value=/
|
|
107
|
+
;;
|
|
108
|
+
*) _path_parent_value=. ;;
|
|
109
|
+
esac
|
|
110
|
+
printf '%s\n' "$_path_parent_value"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Physical directory of bin/valise, resolved once by bin/valise before any
|
|
114
|
+
# library is sourced.
|
|
115
|
+
valise_script_dir() {
|
|
116
|
+
printf '%s\n' "$_valise_engine_bin"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Emit a single-quoted literal for generated POSIX shell code. The generated
|
|
120
|
+
# snippets must not interpolate user-controlled XDG paths into double quotes:
|
|
121
|
+
# `$()` and backticks would still execute there. POSIX single quotes preserve
|
|
122
|
+
# every character except apostrophe, which is represented by the standard
|
|
123
|
+
# '\'' sequence.
|
|
124
|
+
shell_quote() {
|
|
125
|
+
_shell_quote_value=$1
|
|
126
|
+
printf "'"
|
|
127
|
+
while [ -n "$_shell_quote_value" ]; do
|
|
128
|
+
_shell_quote_char=${_shell_quote_value%"${_shell_quote_value#?}"}
|
|
129
|
+
_shell_quote_value=${_shell_quote_value#?}
|
|
130
|
+
case "$_shell_quote_char" in
|
|
131
|
+
"'") printf "%s" "'\\''" ;;
|
|
132
|
+
*) printf '%s' "$_shell_quote_char" ;;
|
|
133
|
+
esac
|
|
134
|
+
done
|
|
135
|
+
printf "'"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# Fish single-quoted literals use a backslash-escaped apostrophe. Encode each
|
|
139
|
+
# source backslash as two backslashes so a backslash immediately before an
|
|
140
|
+
# apostrophe cannot change the quote grammar. Dollar signs, semicolons, and
|
|
141
|
+
# command-substitution markers remain literal, so arbitrary XDG paths cannot
|
|
142
|
+
# inject Fish commands.
|
|
143
|
+
fish_quote() {
|
|
144
|
+
_fish_quote_value=$1
|
|
145
|
+
printf "'"
|
|
146
|
+
while [ -n "$_fish_quote_value" ]; do
|
|
147
|
+
_fish_quote_char=${_fish_quote_value%"${_fish_quote_value#?}"}
|
|
148
|
+
_fish_quote_value=${_fish_quote_value#?}
|
|
149
|
+
case "$_fish_quote_char" in
|
|
150
|
+
\\) printf '%s' '\\' ;;
|
|
151
|
+
"'") printf '%s' "\\'" ;;
|
|
152
|
+
*) printf '%s' "$_fish_quote_char" ;;
|
|
153
|
+
esac
|
|
154
|
+
done
|
|
155
|
+
printf "'"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
trusted_uname() {
|
|
159
|
+
if [ -x /usr/bin/uname ]; then
|
|
160
|
+
/usr/bin/uname "$@"
|
|
161
|
+
elif [ -x /bin/uname ]; then
|
|
162
|
+
/bin/uname "$@"
|
|
163
|
+
else
|
|
164
|
+
return 1
|
|
165
|
+
fi
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# Resolve only platform-owned utility paths for integrity operations. These
|
|
169
|
+
# checks must not be redirected by a caller-controlled PATH.
|
|
170
|
+
trusted_utility_path() {
|
|
171
|
+
case "$1" in
|
|
172
|
+
awk) _trusted_candidates='/usr/bin/awk /bin/awk' ;;
|
|
173
|
+
cat) _trusted_candidates='/bin/cat /usr/bin/cat' ;;
|
|
174
|
+
cp) _trusted_candidates='/bin/cp /usr/bin/cp' ;;
|
|
175
|
+
chmod) _trusted_candidates='/bin/chmod /usr/bin/chmod' ;;
|
|
176
|
+
cmp) _trusted_candidates='/usr/bin/cmp /bin/cmp' ;;
|
|
177
|
+
ln) _trusted_candidates='/bin/ln /usr/bin/ln' ;;
|
|
178
|
+
mkdir) _trusted_candidates='/bin/mkdir /usr/bin/mkdir' ;;
|
|
179
|
+
kill) _trusted_candidates='/bin/kill /usr/bin/kill' ;;
|
|
180
|
+
mktemp) _trusted_candidates='/usr/bin/mktemp /bin/mktemp /opt/homebrew/bin/mktemp /usr/local/bin/mktemp' ;;
|
|
181
|
+
readlink) _trusted_candidates='/usr/bin/readlink /bin/readlink' ;;
|
|
182
|
+
rmdir) _trusted_candidates='/bin/rmdir /usr/bin/rmdir' ;;
|
|
183
|
+
find) _trusted_candidates='/usr/bin/find /bin/find' ;;
|
|
184
|
+
fish) _trusted_candidates='/opt/homebrew/bin/fish /usr/local/bin/fish /usr/bin/fish /bin/fish' ;;
|
|
185
|
+
mv) _trusted_candidates='/bin/mv /usr/bin/mv' ;;
|
|
186
|
+
rm) _trusted_candidates='/bin/rm /usr/bin/rm' ;;
|
|
187
|
+
stat) _trusted_candidates='/usr/bin/stat /bin/stat' ;;
|
|
188
|
+
tail) _trusted_candidates='/usr/bin/tail /bin/tail' ;;
|
|
189
|
+
tr) _trusted_candidates='/usr/bin/tr /bin/tr' ;;
|
|
190
|
+
wc) _trusted_candidates='/usr/bin/wc /bin/wc' ;;
|
|
191
|
+
sha256sum) _trusted_candidates='/usr/bin/sha256sum /bin/sha256sum /sbin/sha256sum /opt/homebrew/bin/sha256sum /usr/local/bin/sha256sum' ;;
|
|
192
|
+
sha256) _trusted_candidates='/usr/bin/sha256 /bin/sha256 /sbin/sha256 /opt/homebrew/bin/sha256 /usr/local/bin/sha256' ;;
|
|
193
|
+
shasum) _trusted_candidates='/usr/bin/shasum /bin/shasum /opt/homebrew/bin/shasum /usr/local/bin/shasum' ;;
|
|
194
|
+
sort) _trusted_candidates='/usr/bin/sort /bin/sort' ;;
|
|
195
|
+
*) return 1 ;;
|
|
196
|
+
esac
|
|
197
|
+
for _trusted_candidate in $_trusted_candidates; do
|
|
198
|
+
if [ -x "$_trusted_candidate" ]; then
|
|
199
|
+
printf '%s\n' "$_trusted_candidate"
|
|
200
|
+
return 0
|
|
201
|
+
fi
|
|
202
|
+
done
|
|
203
|
+
return 1
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
readlink_target() {
|
|
207
|
+
_readlink_path=$(trusted_utility_path readlink) || return 1
|
|
208
|
+
"$_readlink_path" "$1"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# active_release_dir
|
|
212
|
+
# Print the physical directory the active pointer names, or fail. The result
|
|
213
|
+
# is canonical, so a trailing slash, a relative target, or an alias symlink
|
|
214
|
+
# never changes the release identity.
|
|
215
|
+
active_release_dir() {
|
|
216
|
+
[ -L "$VALISE_ACTIVE_LINK" ] || return 1
|
|
217
|
+
_ard_target=$(readlink_target "$VALISE_ACTIVE_LINK" 2>/dev/null) || return 1
|
|
218
|
+
[ -n "$_ard_target" ] || return 1
|
|
219
|
+
case "$_ard_target" in
|
|
220
|
+
/*) : ;;
|
|
221
|
+
*)
|
|
222
|
+
_ard_parent=$(cd "$(path_parent "$VALISE_ACTIVE_LINK")" 2>/dev/null && pwd -P) || return 1
|
|
223
|
+
_ard_target="$_ard_parent/$_ard_target"
|
|
224
|
+
;;
|
|
225
|
+
esac
|
|
226
|
+
_ard_target=$(path_normalize "$_ard_target") || return 1
|
|
227
|
+
(cd "$_ard_target" 2>/dev/null && pwd -P)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
# active_release_id
|
|
231
|
+
# Print the active release's directory name. Identity is the name, not the
|
|
232
|
+
# path spelling.
|
|
233
|
+
active_release_id() {
|
|
234
|
+
_ari_dir=$(active_release_dir) || return 1
|
|
235
|
+
printf '%s\n' "${_ari_dir##*/}"
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Print the canonical root of the engine checkout or package that ships this
|
|
239
|
+
# CLI. Its modules live in module.d/, its libraries in lib/.
|
|
240
|
+
engine_root() {
|
|
241
|
+
(cd "${_valise_engine_bin%/}/.." && pwd -P)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
VALISE_TAB=$(printf '\t')
|
|
245
|
+
VALISE_NL='
|
|
246
|
+
'
|
|
247
|
+
|
|
248
|
+
# Return a file's three-digit permission mode in the manifest's octal form.
|
|
249
|
+
# BSD stat and GNU stat use different option spellings, so probe both.
|
|
250
|
+
file_mode() {
|
|
251
|
+
_stat_path=$(trusted_utility_path stat) || return 1
|
|
252
|
+
# BSD stat accepts -f; GNU stat accepts -c. GNU stat may nevertheless
|
|
253
|
+
# accept -f as a filesystem-stat format and exit successfully, so select a
|
|
254
|
+
# result by validating the output rather than relying on exit status alone.
|
|
255
|
+
_mode_value=$("$_stat_path" -f '%Lp' "$1" 2>/dev/null || :)
|
|
256
|
+
case "$_mode_value" in
|
|
257
|
+
[0-7][0-7][0-7]) printf '0%s\n' "$_mode_value"; return 0 ;;
|
|
258
|
+
esac
|
|
259
|
+
_mode_value=$("$_stat_path" -c '%a' "$1" 2>/dev/null || :) || return 1
|
|
260
|
+
case "$_mode_value" in
|
|
261
|
+
[0-7][0-7][0-7]) printf '0%s\n' "$_mode_value" ;;
|
|
262
|
+
*) return 1 ;;
|
|
263
|
+
esac
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# Return a regular file's exact byte count without locale-dependent padding.
|
|
267
|
+
file_bytes() {
|
|
268
|
+
_wc_path=$(trusted_utility_path wc) || return 1
|
|
269
|
+
_tr_path=$(trusted_utility_path tr) || return 1
|
|
270
|
+
"$_wc_path" -c < "$1" | "$_tr_path" -d '[:space:]'
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# Return a file's modification time in whole epoch seconds. BSD stat and GNU
|
|
274
|
+
# stat use different option spellings, so probe both and select the result by
|
|
275
|
+
# validating the output rather than trusting exit status alone: GNU stat
|
|
276
|
+
# accepts -f as a filesystem-status flag and can exit successfully while
|
|
277
|
+
# printing something that is not a timestamp.
|
|
278
|
+
file_mtime() {
|
|
279
|
+
_mtime_stat=$(trusted_utility_path stat) || return 1
|
|
280
|
+
_mtime_value=$("$_mtime_stat" -c %Y "$1" 2>/dev/null || :)
|
|
281
|
+
case "$_mtime_value" in
|
|
282
|
+
'' | *[!0-9]*) ;;
|
|
283
|
+
*) printf '%s\n' "$_mtime_value"; return 0 ;;
|
|
284
|
+
esac
|
|
285
|
+
_mtime_value=$("$_mtime_stat" -f %m "$1" 2>/dev/null || :)
|
|
286
|
+
case "$_mtime_value" in
|
|
287
|
+
'' | *[!0-9]*) return 1 ;;
|
|
288
|
+
*) printf '%s\n' "$_mtime_value" ;;
|
|
289
|
+
esac
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
file_sha256() {
|
|
293
|
+
_sha_path=$(trusted_utility_path sha256sum 2>/dev/null || :)
|
|
294
|
+
if [ -n "$_sha_path" ]; then
|
|
295
|
+
_sha_output=$("$_sha_path" "$1") || return 1
|
|
296
|
+
else
|
|
297
|
+
_sha_path=$(trusted_utility_path shasum 2>/dev/null || :)
|
|
298
|
+
if [ -n "$_sha_path" ]; then
|
|
299
|
+
_sha_output=$("$_sha_path" -a 256 "$1") || return 1
|
|
300
|
+
else
|
|
301
|
+
_sha_path=$(trusted_utility_path sha256 2>/dev/null || :)
|
|
302
|
+
[ -n "$_sha_path" ] || return 1
|
|
303
|
+
_sha_output=$("$_sha_path" "$1") || return 1
|
|
304
|
+
fi
|
|
305
|
+
fi
|
|
306
|
+
# Supported utilities: sha256sum/shasum print "digest filename";
|
|
307
|
+
# BSD sha256 prints "SHA256 (filename) = digest" or just the digest.
|
|
308
|
+
# The BSD format strip must be gated behind the SHA256 ( prefix: a
|
|
309
|
+
# blanket *=* match corrupts sha256sum/shasum output whenever the
|
|
310
|
+
# absolute file path contains "= " (equals followed by space).
|
|
311
|
+
case "$_sha_output" in
|
|
312
|
+
"SHA256 ("*) _sha_output=${_sha_output##* = } ;;
|
|
313
|
+
esac
|
|
314
|
+
_sha_output=${_sha_output%% *}
|
|
315
|
+
_sha_output=${_sha_output%%$(printf '\t')*}
|
|
316
|
+
printf '%s\n' "$_sha_output"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
lower_hex() {
|
|
320
|
+
_tr_path=$(trusted_utility_path tr) || return 1
|
|
321
|
+
"$_tr_path" 'A-F' 'a-f'
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
cmd_version() {
|
|
325
|
+
printf '%s\n' "$VALISE_VERSION"
|
|
326
|
+
}
|