102 lines
2.7 KiB
Bash
102 lines
2.7 KiB
Bash
#####################################################################
|
|
|
|
setup.filesystem.write-managed-block() {
|
|
# replaces (or appends) a dotwryn-managed block in a file, taking the
|
|
# block body from stdin, so that every run refreshes the block rather
|
|
# than appending another copy of it
|
|
#
|
|
# callers should use a "<<-" heredoc: it strips leading TABS (letting
|
|
# the body stay indented with its caller) but leaves SPACES alone, so
|
|
# indent the block's own nesting with spaces to keep it in the output
|
|
#
|
|
# "--one-line" trades the begin/end banner for a trailing comment on
|
|
# the line itself, which suits a one-line entry like an rc source
|
|
local file tag
|
|
local comment='#'
|
|
local one_line=false
|
|
|
|
local _s _p
|
|
while [[ "${#}" -gt 0 ]]
|
|
do
|
|
_s=1
|
|
case "${1}" in
|
|
( --comment ) _s=2
|
|
comment="${2}"
|
|
;;
|
|
( --tag ) _s=2
|
|
tag="${2}"
|
|
;;
|
|
( --one-line )
|
|
one_line=true
|
|
;;
|
|
( * )
|
|
case "$((_p+=1))" in
|
|
( 1 ) file="${1}" ;;
|
|
( * ) echo.error "write-managed-block: unexpected argument '${1}'" ;;
|
|
esac
|
|
;;
|
|
esac
|
|
shift "${_s}"
|
|
done
|
|
unset _s _p
|
|
|
|
[[ "${file}" ]] \
|
|
|| echo.error 'write-managed-block: no file given' \
|
|
|| return 1
|
|
|
|
# a single file can carry several managed blocks, so each one has to be
|
|
# named to know which of them it owns
|
|
[[ "${tag}" ]] \
|
|
|| echo.error "write-managed-block: no --tag given for '${file}'" \
|
|
|| return 1
|
|
|
|
local body="$(cat)"
|
|
|
|
[[ "${one_line}" == false ]] || [[ "${body}" != *$'\n'* ]] \
|
|
|| echo.error "write-managed-block: --one-line needs a single-line body for '${file}'" \
|
|
|| return 1
|
|
|
|
mkdir -p -- "${file:h}"
|
|
touch -- "${file}"
|
|
|
|
local -a lines block
|
|
lines=("${(@f)$(<"${file}")}")
|
|
[[ -s "${file}" ]] || lines=()
|
|
|
|
# an existing block is replaced where it sits, so anything the user
|
|
# wrote around it keeps its position
|
|
local begin_index end_index
|
|
case "${one_line}" in
|
|
( true )
|
|
local marker="${comment} managed by dotwryn setup (${tag})"
|
|
block=("${body} ${marker}")
|
|
|
|
# "(b)" keeps the tag's parentheses literal rather than glob
|
|
begin_index="${lines[(i)*${(b)marker}]}"
|
|
end_index="${begin_index}"
|
|
;;
|
|
( false )
|
|
local begin="${comment} >>> managed by dotwryn setup (${tag}) >>>"
|
|
local end="${comment} <<< managed by dotwryn setup (${tag}) <<<"
|
|
block=("${begin}" "${(@f)body}" "${end}")
|
|
|
|
begin_index="${lines[(ie)${begin}]}"
|
|
end_index="${lines[(ie)${end}]}"
|
|
[[ "${end_index}" -le "${#lines[@]}" ]] || end_index="${#lines[@]}"
|
|
;;
|
|
esac
|
|
|
|
if [[ "${begin_index}" -gt "${#lines[@]}" ]]
|
|
then
|
|
lines+=("${block[@]}")
|
|
else
|
|
lines=(
|
|
"${lines[@]:0:$((begin_index - 1))}"
|
|
"${block[@]}"
|
|
"${lines[@]:${end_index}}"
|
|
)
|
|
fi
|
|
|
|
print -l -- "${lines[@]}" > "${file}"
|
|
}
|