Skip to content

Commit 10d3b81

Browse files
committed
__do, eval-helper, fs-own, symlink-helper: bugfix
- `bash.bash:__do`: - fix `--redirect-stdout`, it was appending the creating FD instead of forwarding to it - `fs-own`: - fix elevation not working - support `--changes` on macos (need to test implications on alpine) - support `-...` instead of just `--...` (still doesn't support combing `-...`) - correctly send `chown`/`chmod` output to STDERR - `symlink-helper`: - ignore broken symlinks if they still point to the intended location - colorise formatting on existing symlinks - `eval-helper`: - don't mkdir root home, as it is not necessary (might be different on non-macos envuronments) - if needing to make home, perform the normal elevate flow on the home creation, so the user knows why they are being prompted for their password - if the home making fails, attempt to continue without home
1 parent ad77844 commit 10d3b81

4 files changed

Lines changed: 89 additions & 65 deletions

File tree

β€Žcommands/eval-helperβ€Ž

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ function eval_helper() ( # to use this as a function, it needs to change from a
183183
If a prompt is required to momentarily grant privileges, this reason will be used to explain why elevation was required.
184184
--inherit
185185
If enabled, when elevating, the PATH will be inherited to the executing command.
186-
186+
--home
187+
If disabled, do not ensure the HOME is correct for the elevated user. If the HOME does exist, it will be used.
188+
If the elevate <user> is [root], this will default to disabled.
187189
EOF
188190
if [[ $# -ne 0 ]]; then
189191
echo-error "$@"
@@ -198,7 +200,7 @@ function eval_helper() ( # to use this as a function, it needs to change from a
198200
option_terminal_lines='' option_terminal_columns='' \
199201
option_confirm='' \
200202
option_until='' option_until_interval='' option_until_attempts='' \
201-
option_elevated=() option_elevate=() option_user='' option_group='' option_reason='' option_inherit='no' # option_copy_status='' option_redirect_status=''
203+
option_elevated=() option_elevate=() option_user='' option_group='' option_reason='' option_inherit='no' option_home='' # option_copy_status='' option_redirect_status=''
202204
while [[ $# -ne 0 ]]; do
203205
item="$1"
204206
shift
@@ -256,6 +258,9 @@ function eval_helper() ( # to use this as a function, it needs to change from a
256258
'--no-inherit'* | '--inherit'*)
257259
option_inherit="$(get-flag-value --affirmative --fallback="$option_inherit" -- "$item")"
258260
;;
261+
'--no-home'* | '--home'*)
262+
option_home="$(get-flag-value --affirmative --fallback="$option_home" -- "$item")"
263+
;;
259264
# </elevate>
260265
# command
261266
'--')
@@ -277,6 +282,15 @@ function eval_helper() ( # to use this as a function, it needs to change from a
277282
fi
278283
fi
279284

285+
# home
286+
if [[ -z $option_home ]]; then
287+
if [[ $option_user == 'root' ]]; then
288+
option_home='no'
289+
else
290+
option_home='yes'
291+
fi
292+
fi
293+
280294
# require command
281295
if [[ ${#option_cmd[@]} -eq 0 ]]; then
282296
help 'No <command> was provided.'
@@ -671,10 +685,17 @@ function eval_helper() ( # to use this as a function, it needs to change from a
671685
# ensure home is correctly configured for sudo
672686
if [[ -n $home ]]; then
673687
if [[ ! -e $home && ! -L $home ]]; then
674-
sudo mkdir -p -- "$home" # don't delegate to other commands/functions, as they will call this
675-
fs-own --quiet --user="$option_user" --group="$option_group" --no-recursive -- "$home"
688+
if [[ $option_home == 'no' ]]; then
689+
home='' # root user doesn't need home
690+
elif mkdir -p -- "$home" &>/dev/null || eval-helper --elevate --no-home -- mkdir -p -- "$home"; then
691+
fs-own --quiet --user="$option_user" --group="$option_group" --no-recursive -- "$home" || :
692+
else
693+
home=''
694+
fi
695+
fi
696+
if [[ -n $home ]]; then
697+
cmd_elevate+=(--set-home)
676698
fi
677-
cmd_elevate+=(--set-home)
678699
fi
679700

680701
# sudo supports passing environment variables

β€Žcommands/fs-ownβ€Ž

Lines changed: 58 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ function fs_own_test() (
1111
file="$(fs-temp --root="$root" --file='file' --touch)"
1212

1313
local flag flags=(
14+
--root
15+
--admin
16+
--me
1417
--X
1518
--x
1619
--r
@@ -20,24 +23,17 @@ function fs_own_test() (
2023
--ugx
2124
--permissions='a-xrw,ug+Xrw'
2225
# --reference="$DOROTHY" <-- on macos this is 40755 which fails when applied to files
23-
--me
24-
--admin
25-
--root
2626
)
2727
fs-structure -- "$root" "$dir"
2828

29-
local stderr=''
30-
if is-mac; then
31-
stderr='Reporting permission changes is not provided by this Operating System.'
32-
fi
3329
for flag in "${flags[@]}"; do
3430
__print_line
35-
eval-tester --stderr="$stderr" -- fs-own --no-color --changes "$flag" -- "$dir" "$file"
31+
eval-tester --ignore-stderr -- fs-own --no-color --changes "$flag" -- "$dir" "$file"
3632
eval-tester -- fs-own --no-color --quiet "$flag" -- "$dir" "$file"
37-
eval-tester -- fs-own --no-color --verbose "$flag" -- "$dir" "$file"
38-
eval-tester --stderr="$stderr" -- fs-own --no-color --recursive --changes "$flag" -- "$dir"
33+
eval-tester --ignore-stderr -- fs-own --no-color --verbose "$flag" -- "$dir" "$file"
34+
eval-tester --ignore-stderr -- fs-own --no-color --recursive --changes "$flag" -- "$dir"
3935
eval-tester -- fs-own --no-color --recursive --quiet "$flag" -- "$dir"
40-
eval-tester -- fs-own --no-color --recursive --verbose "$flag" -- "$dir"
36+
eval-tester --ignore-stderr -- fs-own --no-color --recursive --verbose "$flag" -- "$dir"
4137
fs-structure -- "$root" "$dir" || :
4238
done
4339

@@ -62,6 +58,7 @@ function fs_own_test() (
6258
)
6359
function fs_own() (
6460
source "$DOROTHY/sources/bash.bash"
61+
source "$(type -P eval-helper)"
6562

6663
# =====================================
6764
# Arguments
@@ -72,32 +69,31 @@ function fs_own() (
7269
Claim ownership of a path, by updating its permissions via chmod and chown.
7370
7471
USAGE:
75-
fs-own [...options] [--] ...<path>
72+
fs-own [...options] -- ...<path>
7673
7774
EXAMPLE:
7875
fs-own --recursive --ug -- .
7976
8077
OPTIONS:
8178
--quiet | --verbose | --changes
82-
if --verbose, apply --changes if supported and use --verbose on executed chmod/chown commands.
83-
if --quiet, apply --no-changes
84-
if neither --verbose or --quiet then apply --changes if supported
79+
if [--changes], the default, only output to STDERR the changes
80+
if [--verbose], output to STDERR all operations
8581
86-
--X
82+
--X | -X
8783
sets <permissions> to be executable directories for the user: +x
88-
--x
84+
--x | -x
8985
sets <permissions> to be executable for the user: +x
90-
--r
86+
--r | -r
9187
sets <permissions> to be executable for the user: +r
92-
--w
88+
--w | -w
9389
sets <permissions> to be executable for the user: +w
94-
--u
90+
--u | -u
9591
sets <permissions> to only be available to the user: a-xrw,u+Xrw
96-
--ux
92+
--ux | -ux
9793
sets <permissions> to only be available and executable to the user: a-xrw,u+xrw
98-
--ug
94+
--ug | -ug
9995
sets <permissions> to only be available to the user and group: a-xrw,ug+Xrw
100-
--ugx
96+
--ugx | -ugx
10197
sets <permissions> to only be available and executable to the user and group: a-xrw,ug+xrw
10298
--permissions=<permissions>
10399
sets file and directory permissions.
@@ -204,43 +200,43 @@ function fs_own() (
204200
fi
205201
option_permissions='+X'
206202
;;
207-
'--x')
203+
'--x' | '-x')
208204
if [[ -n $option_permissions ]]; then
209205
help "$item cannot be specified with other <permissions>"
210206
fi
211207
option_permissions='+x'
212208
;;
213-
'--r')
209+
'--r' | '-r')
214210
if [[ -n $option_permissions ]]; then
215211
help "$item cannot be specified with other <permissions>"
216212
fi
217213
option_permissions='+r'
218214
;;
219-
'--w')
215+
'--w' | '-w')
220216
if [[ -n $option_permissions ]]; then
221217
help "$item cannot be specified with other <permissions>"
222218
fi
223219
option_permissions='+w'
224220
;;
225-
'--u')
221+
'--u' | '-u')
226222
if [[ -n $option_permissions ]]; then
227223
help "$item cannot be specified with other <permissions>"
228224
fi
229225
option_permissions='a-xrw,u+Xrw'
230226
;;
231-
'--ux')
227+
'--ux' | '-ux')
232228
if [[ -n $option_permissions ]]; then
233229
help "$item cannot be specified with other <permissions>"
234230
fi
235231
option_permissions='a-xrw,u+xrw'
236232
;;
237-
'--ug')
233+
'--ug' | '-ug')
238234
if [[ -n $option_permissions ]]; then
239235
help "$item cannot be specified with other <permissions>"
240236
fi
241237
option_permissions='a-xrw,ug+Xrw'
242238
;;
243-
'--ugx')
239+
'--ugx' | '-ugx')
244240
if [[ -n $option_permissions ]]; then
245241
help "$item cannot be specified with other <permissions>"
246242
fi
@@ -264,7 +260,7 @@ function fs_own() (
264260
break
265261
;;
266262
'--'*) help "An unrecognised flag was provided: $item" ;;
267-
*) option_paths+=("$item") ;;
263+
*) help "An unrecognised argument was provided: $item" ;;
268264
esac
269265
done
270266

@@ -392,32 +388,41 @@ function fs_own() (
392388
fi
393389

394390
# adjustments: changes, quiet, verbose
395-
if [[ -z $option_changes ]]; then
396-
if [[ $option_quiet == 'yes' ]]; then
397-
option_changes='no'
391+
function __filter_changes {
392+
cat
393+
}
394+
if [[ $option_quiet == 'no' ]]; then
395+
if is-mac; then
396+
# Reports even if there are no changes.
397+
# -v: Cause chown to be verbose, showing files as the owner is modified. If the -v flag is specified more than once, chown will print the filename, followed by the old and new numeric user/group ID.
398+
# -v: Cause chmod to be verbose, showing filenames as the mode is modified. If the -v flag is specified more than once, the old and new modes of the file will also be printed, in both octal and symbolic notation.
399+
ch_args+=('-vv')
398400
else
399-
# neither --quiet/--verbose, or just --verbose
400-
# in which case, enable changes if supported
401-
if is-mac || is-alpine; then
402-
option_changes='no'
403-
else
404-
option_changes='yes'
405-
fi
401+
# -v, --verbose: output a diagnostic for every file processed
402+
ch_args+=('--verbose')
406403
fi
407-
elif [[ $option_changes == 'yes' ]]; then
404+
elif [[ $option_changes != 'no' ]]; then
408405
if is-mac || is-alpine; then
409-
echo-style --stderr --dim='Reporting permission changes is not provided by this Operating System.'
406+
ch_args+=('-vv')
407+
function __filter_changes {
408+
local line before after
409+
while IFS= read -r line; do
410+
if [[ $line != *' -> '* ]]; then
411+
__print_lines "$line"
412+
continue
413+
fi
414+
before="$(__get_substring_before_last "$line" ' -> ')"
415+
after="$(__get_substring_after_last "$line" ' -> ')"
416+
before="$(__get_substring_after_last "$before" ': ')"
417+
if [[ $before != "$after" ]]; then
418+
__print_lines "$line"
419+
fi
420+
done
421+
}
410422
else
411423
ch_args+=('--changes')
412424
fi
413425
fi
414-
if [[ $option_quiet == 'no' ]]; then
415-
if is-mac; then
416-
ch_args+=('-v')
417-
else
418-
ch_args+=('--verbose')
419-
fi
420-
fi
421426

422427
# =====================================
423428
# Prepare
@@ -443,7 +448,7 @@ function fs_own() (
443448
# chown
444449
if [[ -n $owner ]]; then
445450
# as root
446-
eval-helper --elevated="$option_elevated" --elevate="$option_elevated" --reason="$option_reason" -- \
451+
eval_helper --redirect-stdout='(__filter_changes)' --redirect-output=STDERR --elevated="$option_elevated" --elevate="$option_elevate" --reason="$option_reason" --user=root -- \
447452
chown "${ch_args[@]}" "$owner" "${double_dash_args[@]}" "${paths[@]}" || return # eval
448453
fi
449454

@@ -452,14 +457,14 @@ function fs_own() (
452457
# https://superuser.com/a/91966/32418
453458
# removing readable perms on a directory, while recursing, will cause permission denied failure
454459
# as user
455-
eval-helper --elevated="$option_elevated" --elevate="$option_elevated" --user="$option_user" --group="$option_group" --reason="$option_reason" -- \
460+
eval_helper --redirect-stdout='(__filter_changes)' --redirect-output=STDERR --elevated="$option_elevated" --elevate="$option_elevate" --user="$option_user" --group="$option_group" --reason="$option_reason" -- \
456461
chmod "${ch_args[@]}" "$option_permissions" "${double_dash_args[@]}" "${paths[@]}" || return # eval
457462
fi
458463
}
459464

460465
# determine paths
461466
for path in "${option_paths[@]}"; do
462-
if is-present --quiet="$option_quiet" --elevated="$option_elevated" --elevate="$option_elevated" --user="$option_user" --group="$option_group" --reason="$option_reason" -- "$path"; then
467+
if is-present --quiet="$option_quiet" --elevated="$option_elevated" --elevate="$option_elevate" --user="$option_user" --group="$option_group" --reason="$option_reason" -- "$path"; then
463468
paths+=("$path") # it exists, update ownership for it
464469
fi
465470
done

β€Žcommands/symlink-helperβ€Ž

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,26 +177,23 @@ function symlink_helper() (
177177
fi
178178

179179
# check if the symlink is already desired
180-
if is-exist --elevated="$option_elevated" --elevate="$option_elevate" --user="$option_user" --group="$option_group" --reason="$option_reason" -- "$symlink_resolved"; then
180+
if is-present --elevated="$option_elevated" --elevate="$option_elevate" --user="$option_user" --group="$option_group" --reason="$option_reason" -- "$symlink"; then
181181
if [[ $symlink != "$symlink_resolved" ]]; then
182182
if [[ $symlink_resolved == "$target_resolved" ]]; then
183183
if [[ $option_quiet == 'no' ]]; then
184-
echo-style --stderr --bold='πŸ‘ Symlink already created at ' --path="$symlink" --bold=' targetting ' --path="$target"
184+
echo-style --stderr --note='πŸ‘ Symlink already created at ' --path="$symlink" --bold=' targetting ' --path="$target"
185185
fi
186186
continue
187187
fi
188188
if [[ -z $option_quiet || $option_quiet == 'no' ]]; then
189-
echo-style --stderr --bold='πŸ’β€β™€οΈ Symlink already exists at ' --path="$symlink" ' ' --bold='recreating...'
189+
echo-style --stderr --note='πŸ’β€β™€οΈ Symlink already exists at ' --path="$symlink" --bold=' targetting ' --path="$target" ' ' --note='recreating...'
190190
fi
191191
# is a symlink but a different target, drop it and recreate
192192
__wrap rm -f -- "$symlink" >&2
193193
else
194194
# not a symlink, confirm with the user what to do
195195
fs-rm --quiet="$option_quiet" --confirm --elevated="$option_elevated" --elevate="$option_elevate" --user="$option_user" --group="$option_group" --reason="$option_reason" -- "$symlink" >&2
196196
fi
197-
elif [[ $symlink != "$symlink_resolved" ]]; then
198-
# a broken symlink exists at the location, drop it and recreate
199-
__wrap rm -f -- "$symlink" >&2
200197
else
201198
# nothing exists at the location, ensure its parent path at least exists
202199
__wrap mkdir -p -- "$(fs-path --parents -- "$symlink")" >&2

β€Žsources/bash.bashβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,8 +1170,9 @@ function __do {
11701170

11711171
# execute while tracking the exit status to our semaphore file
11721172
# can't use `__try` as >() is a subshell, so the status variable application won't escape the subshell
1173+
# note [>(...)] and [> >(...)] are different, the former interpolates as a file descriptor, the latter forwards stdout to the file descriptor
11731174
case "$arg_flag" in
1174-
--redirect-stdout) __do --right-to-left "$@" >(__do --redirect-status="$semaphore_file_target" -- eval "$code") ;;
1175+
--redirect-stdout) __do --right-to-left "$@" > >(__do --redirect-status="$semaphore_file_target" -- eval "$code") ;;
11751176
--redirect-stderr) __do --right-to-left "$@" 2> >(__do --redirect-status="$semaphore_file_target" -- eval "$code") ;;
11761177
--redirect-output) __do --right-to-left "$@" &> >(__do --redirect-status="$semaphore_file_target" -- eval "$code") ;;
11771178
*)

0 commit comments

Comments
Β (0)