summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-12 08:51:15 +0300
committerPaul Buetow <paul@buetow.org>2026-06-12 08:51:15 +0300
commit08dcc822ece08c72805b18cbd663a4f7fecbf726 (patch)
tree111a7a9839471112efa5f1a378a0c0a9f7a4c634
parent675d450919c63ec9d9955e8ae6a734d8086d96fd (diff)
Guard template render setup failures for bm0
-rwxr-xr-xbin/shuriken75
-rw-r--r--src/lib/template.source.sh75
-rwxr-xr-xtests/cli.sh140
3 files changed, 264 insertions, 26 deletions
diff --git a/bin/shuriken b/bin/shuriken
index 7ed6069..82c84db 100755
--- a/bin/shuriken
+++ b/bin/shuriken
@@ -724,11 +724,16 @@ template_required_context_vars() {
validate_template_context() {
local -r template_name="$1"; shift
local -r context_name="$1"; shift
+ local -i status=0
local -a required_vars=()
template_required_context_vars_to required_vars "$template_name"
require_template_context_vars "$template_name" "$context_name" \
- "${required_vars[@]}" || return
+ "${required_vars[@]}"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
source_template_file() {
@@ -739,19 +744,28 @@ source_template_file() {
local -i status=0
context_file=$(mktemp)
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
{
serialize_template_render_context "$render_vars_name"
printf 'unset BASH_ENV\n'
} > "$context_file"
-
- if env -i PATH="$PATH" BASH_ENV="$context_file" \
- bash -euo pipefail -- "$template_path" >> "$output_path"; then
- rm -f "$context_file"
- else
- status=$?
+ status=$?
+ if (( status != 0 )); then
rm -f "$context_file"
return "$status"
fi
+
+ env -i PATH="$PATH" BASH_ENV="$context_file" \
+ bash -euo pipefail -- "$template_path" >> "$output_path"
+ status=$?
+ rm -f "$context_file"
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
parse_template_context() {
@@ -913,13 +927,18 @@ validate_template_render_request() {
local -r template_name="$1"; shift
local -r context_name="$1"; shift
local -r template_path="$TEMPLATE_DIR/$template_name.tmpl"
+ local -i status=0
if [ ! -r "$template_path" ]; then
config_error "template file $template_path must be readable"
return 1
fi
- validate_template_context "$template_name" "$context_name" || return
+ validate_template_context "$template_name" "$context_name"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
render_template() {
@@ -929,6 +948,7 @@ render_template() {
local -r template_path="$TEMPLATE_DIR/$template_name.tmpl"
local dist_html
local html_dir
+ local -i status=0
# Passed by name to prepare_template_render_vars and source_template_file.
# shellcheck disable=SC2034
local -A render_vars=()
@@ -940,19 +960,48 @@ render_template() {
"Rendering $template_name template into $(_display_path "$dist_html")/$html"
mkdir -p "$dist_html"
- prepare_template_render_vars render_vars "$context_name" || return
- source_template_file "$template_path" "$dist_html/$html" render_vars || return
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ prepare_template_render_vars render_vars "$context_name"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ source_template_file "$template_path" "$dist_html/$html" render_vars
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
template() {
local -r template_name="$1"; shift
local -r html="$1"; shift
+ local -i status=0
# shellcheck disable=SC2034
local -A render_context=()
- parse_template_context "$template_name" render_context "$@" || return
- validate_template_render_request "$template_name" render_context || return
- render_template "$template_name" "$html" render_context || return
+ parse_template_context "$template_name" render_context "$@"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ validate_template_render_request "$template_name" render_context
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ render_template "$template_name" "$html" render_context
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
# Inlined from src/lib/image.source.sh
diff --git a/src/lib/template.source.sh b/src/lib/template.source.sh
index 776d25a..93b8187 100644
--- a/src/lib/template.source.sh
+++ b/src/lib/template.source.sh
@@ -279,11 +279,16 @@ template_required_context_vars() {
validate_template_context() {
local -r template_name="$1"; shift
local -r context_name="$1"; shift
+ local -i status=0
local -a required_vars=()
template_required_context_vars_to required_vars "$template_name"
require_template_context_vars "$template_name" "$context_name" \
- "${required_vars[@]}" || return
+ "${required_vars[@]}"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
source_template_file() {
@@ -294,19 +299,28 @@ source_template_file() {
local -i status=0
context_file=$(mktemp)
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
{
serialize_template_render_context "$render_vars_name"
printf 'unset BASH_ENV\n'
} > "$context_file"
-
- if env -i PATH="$PATH" BASH_ENV="$context_file" \
- bash -euo pipefail -- "$template_path" >> "$output_path"; then
- rm -f "$context_file"
- else
- status=$?
+ status=$?
+ if (( status != 0 )); then
rm -f "$context_file"
return "$status"
fi
+
+ env -i PATH="$PATH" BASH_ENV="$context_file" \
+ bash -euo pipefail -- "$template_path" >> "$output_path"
+ status=$?
+ rm -f "$context_file"
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
parse_template_context() {
@@ -468,13 +482,18 @@ validate_template_render_request() {
local -r template_name="$1"; shift
local -r context_name="$1"; shift
local -r template_path="$TEMPLATE_DIR/$template_name.tmpl"
+ local -i status=0
if [ ! -r "$template_path" ]; then
config_error "template file $template_path must be readable"
return 1
fi
- validate_template_context "$template_name" "$context_name" || return
+ validate_template_context "$template_name" "$context_name"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
render_template() {
@@ -484,6 +503,7 @@ render_template() {
local -r template_path="$TEMPLATE_DIR/$template_name.tmpl"
local dist_html
local html_dir
+ local -i status=0
# Passed by name to prepare_template_render_vars and source_template_file.
# shellcheck disable=SC2034
local -A render_vars=()
@@ -495,17 +515,46 @@ render_template() {
"Rendering $template_name template into $(_display_path "$dist_html")/$html"
mkdir -p "$dist_html"
- prepare_template_render_vars render_vars "$context_name" || return
- source_template_file "$template_path" "$dist_html/$html" render_vars || return
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ prepare_template_render_vars render_vars "$context_name"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ source_template_file "$template_path" "$dist_html/$html" render_vars
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
template() {
local -r template_name="$1"; shift
local -r html="$1"; shift
+ local -i status=0
# shellcheck disable=SC2034
local -A render_context=()
- parse_template_context "$template_name" render_context "$@" || return
- validate_template_render_request "$template_name" render_context || return
- render_template "$template_name" "$html" render_context || return
+ parse_template_context "$template_name" render_context "$@"
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ validate_template_render_request "$template_name" render_context
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
+ render_template "$template_name" "$html" render_context
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
}
diff --git a/tests/cli.sh b/tests/cli.sh
index 89947e0..311cff9 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -2075,6 +2075,60 @@ BASH
test::teardown
}
+test_generate_action_runs_with_errexit_active() {
+ local config_file
+ local output
+ local ran_file
+ local -i status=0
+
+ test::setup
+ config_file="$TEST_TMPDIR/shuriken.conf"
+ ran_file="$TEST_TMPDIR/dry-run-continued"
+ mkdir -p "$TEST_TMPDIR/incoming"
+ test::write_preflight_config \
+ "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ "$TEST_REPO_ROOT/share/templates/default"
+
+ set +e
+ output=$(
+ bash -euo pipefail -s "$TEST_SHURIKEN" "$config_file" "$ran_file" \
+ 2>&1 \
+ <<'BASH'
+shuriken="$1"; shift
+config_file="$1"; shift
+ran_file="$1"; shift
+
+# shellcheck source=/dev/null
+source <(sed '$d' "$shuriken")
+
+dry_run() {
+ false
+ printf 'dry_run continued\n' > "$ran_file"
+}
+
+SHURIKEN_CLI_ACTION=--dry-run
+SHURIKEN_CLI_CONFIG_FILE="$config_file"
+SHURIKEN_CLI_HAS_CONFIG_OVERRIDES=no
+SHURIKEN_CLI_OVERRIDES=()
+SHURIKEN_CLI_SYNC_DESTINATIONS=()
+SHURIKEN_FORCE_GENERATE=no
+
+run_configured_action
+BASH
+ )
+ status=$?
+ set -e
+
+ if (( status == 0 )); then
+ printf 'FAIL: expected run_configured_action to fail\n' >&2
+ printf '%s\n' "$output" >&2
+ exit 1
+ fi
+
+ test::assert_path_absent "$ran_file"
+ test::teardown
+}
+
test_generate_preflight_accepts_empty_height() {
local config_file
local fake_bin
@@ -3274,6 +3328,86 @@ test_template_context_validator_fails_fast_without_errexit() {
"$output"
}
+test_template_mktemp_failure_does_not_render_without_errexit() {
+ local fake_bin
+ local output
+ local output_file
+ local ran_file
+ local template_dir
+ local -i status=0
+
+ test::setup
+ fake_bin="$TEST_TMPDIR/bin"
+ template_dir="$TEST_TMPDIR/templates"
+ output_file="$TEST_TMPDIR/dist/out.html"
+ ran_file="$TEST_TMPDIR/template-ran"
+ mkdir -p "$fake_bin" "$template_dir" "$TEST_TMPDIR/dist"
+ {
+ printf '#!/usr/bin/env bash\n'
+ printf 'exit 42\n'
+ } > "$fake_bin/mktemp"
+ chmod 0755 "$fake_bin/mktemp"
+ {
+ printf 'printf rendered >> %q\n' "$ran_file"
+ printf 'printf rendered\n'
+ } > "$template_dir/preview.tmpl"
+
+ set +e
+ output=$(
+ bash -euo pipefail -s \
+ "$TEST_SHURIKEN" \
+ "$fake_bin" \
+ "$template_dir" \
+ "$TEST_TMPDIR/dist" \
+ 2>&1 \
+ <<'BASH'
+shuriken="$1"; shift
+fake_bin="$1"; shift
+template_dir="$1"; shift
+dist_dir="$1"; shift
+
+# shellcheck source=/dev/null
+source <(sed '$d' "$shuriken")
+
+PATH="$fake_bin:$PATH"
+DIST_DIR="$dist_dir"
+TEMPLATE_DIR="$template_dir"
+TITLE='Template mktemp failure'
+HEIGHT=''
+THUMBHEIGHT=30
+MAXPREVIEWS=40
+ORIGINAL_BASEPATH=''
+TARBALL_INCLUDE=no
+SHURIKEN_OUTPUT_MODE=quiet
+
+template preview out.html \
+ animation_class '' \
+ backhref '#' \
+ html_dir . \
+ page_num 1 \
+ photo photo.jpg \
+ preview_num 1 \
+ thumbs_dir thumbs
+BASH
+ )
+ status=$?
+ set -e
+
+ if (( status == 0 )); then
+ printf 'FAIL: expected template rendering to fail\n' >&2
+ printf '%s\n' "$output" >&2
+ exit 1
+ fi
+
+ test::assert_path_absent "$ran_file"
+ if [ -s "$output_file" ]; then
+ printf 'FAIL: expected template output to stay empty\n' >&2
+ cat "$output_file" >&2
+ exit 1
+ fi
+ test::teardown
+}
+
test_generate_swap_failure_restores_dist() {
local config_file
local fake_bin
@@ -4091,6 +4225,9 @@ main() {
'--generate validation failure skips action without errexit' \
test_generate_validation_failure_skips_action_without_errexit
test::run_case \
+ '--generate action runs with errexit active' \
+ test_generate_action_runs_with_errexit_active
+ test::run_case \
'--generate preflight accepts empty HEIGHT' \
test_generate_preflight_accepts_empty_height
test::run_case \
@@ -4175,6 +4312,9 @@ main() {
'template context validator fails fast without errexit' \
test_template_context_validator_fails_fast_without_errexit
test::run_case \
+ 'template mktemp failure does not render without errexit' \
+ test_template_mktemp_failure_does_not_render_without_errexit
+ test::run_case \
'--generate swap failure restores final dist' \
test_generate_swap_failure_restores_dist
test::run_case \