summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-13 10:04:15 +0300
committerPaul Buetow <paul@buetow.org>2026-06-13 10:04:15 +0300
commite9437367b8fc7a4cb0ffed6c0a8ba89356a3b9ad (patch)
tree70c10195c1ad8c435e0d09faaab89b96afa0fc18
parentdfcb18a189da91885172a9323a08a0d235432c5f (diff)
dm0: split dry-run planning from output
-rwxr-xr-xbin/shuriken136
-rw-r--r--src/lib/album.source.sh134
-rwxr-xr-xtests/cli.sh56
3 files changed, 243 insertions, 83 deletions
diff --git a/bin/shuriken b/bin/shuriken
index 82bd24e..b37aad3 100755
--- a/bin/shuriken
+++ b/bin/shuriken
@@ -2406,69 +2406,121 @@ refresh_splash() {
}
dry_run() {
- local -i image_count=0
- local -i html_index_count=1
+ # shellcheck disable=SC2034
+ local -A dry_run_plan=()
+
+ collect_dry_run_plan dry_run_plan
+ print_dry_run_plan dry_run_plan
+}
+
+collect_dry_run_page_plan() {
+ local -r plan_name="$1"; shift
+ # shellcheck disable=SC2178
+ local -n plan_ref="$plan_name"
+ local -r image_count="$1"; shift
local -i page_count=0
local -i redirect_count=0
- local -i details_count=0
- image_count=$(count_incoming_images)
+ plan_ref["html_index_count"]=1
+ plan_ref["page_count"]=0
+ plan_ref["redirect_count"]=0
+ plan_ref["details_count"]=0
if (( image_count > 0 )); then
- details_count=$image_count
page_count=$(( (image_count + MAXPREVIEWS - 1) / MAXPREVIEWS ))
redirect_count=$(( page_count * 4 + 2 ))
+ plan_ref["details_count"]="$image_count"
+ plan_ref["page_count"]="$page_count"
+ plan_ref["redirect_count"]="$redirect_count"
fi
+}
+
+collect_dry_run_plan() {
+ local -r plan_name="$1"; shift
+ # shellcheck disable=SC2178
+ local -n plan_ref="$plan_name"
+ local -i image_count=0
+
+ image_count=$(count_incoming_images)
+ plan_ref=()
+ plan_ref["config_source"]="$SHURIKEN_CONFIG_SOURCE"
+ plan_ref["incoming_dir"]="$INCOMING_DIR"
+ plan_ref["dist_dir"]="$DIST_DIR"
+ plan_ref["template_dir"]="$TEMPLATE_DIR"
+ plan_ref["title"]="$TITLE"
+ plan_ref["height"]="$HEIGHT"
+ plan_ref["thumbheight"]="$THUMBHEIGHT"
+ plan_ref["maxpreviews"]="$MAXPREVIEWS"
+ plan_ref["image_jobs"]="$IMAGE_JOBS"
+ plan_ref["random_seed"]="$RANDOM_SEED"
+ plan_ref["shuffle"]="$SHUFFLE"
+ plan_ref["splash_page"]="$SPLASH_PAGE"
+ plan_ref["image_count"]="$image_count"
+ plan_ref["tarball_include"]="$TARBALL_INCLUDE"
+ plan_ref["tarball_name_plan"]='not planned'
- printf 'Dry run: no files will be written.\n'
- printf 'Config source: %s\n' "$SHURIKEN_CONFIG_SOURCE"
- printf 'Incoming directory: %s\n' "$INCOMING_DIR"
- printf 'Output directory: %s\n' "$DIST_DIR"
- printf 'Template directory: %s\n' "$TEMPLATE_DIR"
- printf 'Title: %s\n' "$TITLE"
- printf 'Height: %s\n' "$HEIGHT"
- printf 'Thumb height: %s\n' "$THUMBHEIGHT"
- printf 'Max previews per page: %s\n' "$MAXPREVIEWS"
- printf 'Image jobs: %s\n' "$IMAGE_JOBS"
- printf 'Random seed: %s\n' "$RANDOM_SEED"
- printf 'Shuffle: %s\n' "$SHUFFLE"
- printf 'Splash page: %s\n' "$SPLASH_PAGE"
- printf 'Image count: %s\n' "$image_count"
- printf 'Tarball setting: %s\n' "$TARBALL_INCLUDE"
if [ "$TARBALL_INCLUDE" = yes ]; then
- printf 'Tarball name plan: %s\n' "$(tarball_name_plan)"
- else
- printf 'Tarball name plan: not planned\n'
+ plan_ref["tarball_name_plan"]=$(tarball_name_plan)
fi
+ collect_dry_run_page_plan "$plan_name" "$image_count"
+}
+
+print_dry_run_plan() {
+ local -r plan_name="$1"; shift
+ # shellcheck disable=SC2178
+ local -n plan_ref="$plan_name"
+
+ printf 'Dry run: no files will be written.\n'
+ printf 'Config source: %s\n' "${plan_ref["config_source"]}"
+ printf 'Incoming directory: %s\n' "${plan_ref["incoming_dir"]}"
+ printf 'Output directory: %s\n' "${plan_ref["dist_dir"]}"
+ printf 'Template directory: %s\n' "${plan_ref["template_dir"]}"
+ printf 'Title: %s\n' "${plan_ref["title"]}"
+ printf 'Height: %s\n' "${plan_ref["height"]}"
+ printf 'Thumb height: %s\n' "${plan_ref["thumbheight"]}"
+ printf 'Max previews per page: %s\n' "${plan_ref["maxpreviews"]}"
+ printf 'Image jobs: %s\n' "${plan_ref["image_jobs"]}"
+ printf 'Random seed: %s\n' "${plan_ref["random_seed"]}"
+ printf 'Shuffle: %s\n' "${plan_ref["shuffle"]}"
+ printf 'Splash page: %s\n' "${plan_ref["splash_page"]}"
+ printf 'Image count: %s\n' "${plan_ref["image_count"]}"
+ printf 'Tarball setting: %s\n' "${plan_ref["tarball_include"]}"
+ printf 'Tarball name plan: %s\n' "${plan_ref["tarball_name_plan"]}"
+
printf 'Planned directories:\n'
- printf ' %s\n' "$DIST_DIR"
- printf ' %s/photos\n' "$DIST_DIR"
- printf ' %s/thumbs\n' "$DIST_DIR"
- printf ' %s/blurs\n' "$DIST_DIR"
+ printf ' %s\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/photos\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/thumbs\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/blurs\n' "${plan_ref["dist_dir"]}"
printf 'Planned generated files:\n'
- if [ "$SPLASH_PAGE" = yes ]; then
+ if [ "${plan_ref["splash_page"]}" = yes ]; then
printf ' %s/index.html (%s splash page)\n' \
- "$DIST_DIR" "$html_index_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["html_index_count"]}"
else
printf ' %s/index.html (%s album index redirect)\n' \
- "$DIST_DIR" "$html_index_count"
- fi
- printf ' %s/favicon.ico\n' "$DIST_DIR"
- printf ' %s/shuriken.json\n' "$DIST_DIR"
- printf ' %s/photos/* (%s image files)\n' "$DIST_DIR" "$image_count"
- printf ' %s/thumbs/* (%s image files)\n' "$DIST_DIR" "$image_count"
- printf ' %s/blurs/* (%s image files)\n' "$DIST_DIR" "$image_count"
- printf ' %s/page-*.html (%s preview pages)\n' "$DIST_DIR" "$page_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["html_index_count"]}"
+ fi
+ printf ' %s/favicon.ico\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/shuriken.json\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/photos/* (%s image files)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
+ printf ' %s/thumbs/* (%s image files)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
+ printf ' %s/blurs/* (%s image files)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
+ printf ' %s/page-*.html (%s preview pages)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["page_count"]}"
printf ' %s/[page]-[image].html (%s view pages)\n' \
- "$DIST_DIR" "$image_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
printf ' %s/[page]-[image]-details.html (%s details pages)\n' \
- "$DIST_DIR" "$details_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["details_count"]}"
printf ' %s/[redirect].html (%s navigation redirects)\n' \
- "$DIST_DIR" "$redirect_count"
- if [ "$TARBALL_INCLUDE" = yes ]; then
- printf ' %s/%s\n' "$DIST_DIR" "$(tarball_name_plan)"
+ "${plan_ref["dist_dir"]}" "${plan_ref["redirect_count"]}"
+ if [ "${plan_ref["tarball_include"]}" = yes ]; then
+ printf ' %s/%s\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["tarball_name_plan"]}"
fi
}
diff --git a/src/lib/album.source.sh b/src/lib/album.source.sh
index 6043fe0..beec5fd 100644
--- a/src/lib/album.source.sh
+++ b/src/lib/album.source.sh
@@ -1059,68 +1059,120 @@ refresh_splash() {
}
dry_run() {
- local -i image_count=0
- local -i html_index_count=1
+ # shellcheck disable=SC2034
+ local -A dry_run_plan=()
+
+ collect_dry_run_plan dry_run_plan
+ print_dry_run_plan dry_run_plan
+}
+
+collect_dry_run_page_plan() {
+ local -r plan_name="$1"; shift
+ # shellcheck disable=SC2178
+ local -n plan_ref="$plan_name"
+ local -r image_count="$1"; shift
local -i page_count=0
local -i redirect_count=0
- local -i details_count=0
- image_count=$(count_incoming_images)
+ plan_ref["html_index_count"]=1
+ plan_ref["page_count"]=0
+ plan_ref["redirect_count"]=0
+ plan_ref["details_count"]=0
if (( image_count > 0 )); then
- details_count=$image_count
page_count=$(( (image_count + MAXPREVIEWS - 1) / MAXPREVIEWS ))
redirect_count=$(( page_count * 4 + 2 ))
+ plan_ref["details_count"]="$image_count"
+ plan_ref["page_count"]="$page_count"
+ plan_ref["redirect_count"]="$redirect_count"
fi
+}
+
+collect_dry_run_plan() {
+ local -r plan_name="$1"; shift
+ # shellcheck disable=SC2178
+ local -n plan_ref="$plan_name"
+ local -i image_count=0
+
+ image_count=$(count_incoming_images)
+ plan_ref=()
+ plan_ref["config_source"]="$SHURIKEN_CONFIG_SOURCE"
+ plan_ref["incoming_dir"]="$INCOMING_DIR"
+ plan_ref["dist_dir"]="$DIST_DIR"
+ plan_ref["template_dir"]="$TEMPLATE_DIR"
+ plan_ref["title"]="$TITLE"
+ plan_ref["height"]="$HEIGHT"
+ plan_ref["thumbheight"]="$THUMBHEIGHT"
+ plan_ref["maxpreviews"]="$MAXPREVIEWS"
+ plan_ref["image_jobs"]="$IMAGE_JOBS"
+ plan_ref["random_seed"]="$RANDOM_SEED"
+ plan_ref["shuffle"]="$SHUFFLE"
+ plan_ref["splash_page"]="$SPLASH_PAGE"
+ plan_ref["image_count"]="$image_count"
+ plan_ref["tarball_include"]="$TARBALL_INCLUDE"
+ plan_ref["tarball_name_plan"]='not planned'
- printf 'Dry run: no files will be written.\n'
- printf 'Config source: %s\n' "$SHURIKEN_CONFIG_SOURCE"
- printf 'Incoming directory: %s\n' "$INCOMING_DIR"
- printf 'Output directory: %s\n' "$DIST_DIR"
- printf 'Template directory: %s\n' "$TEMPLATE_DIR"
- printf 'Title: %s\n' "$TITLE"
- printf 'Height: %s\n' "$HEIGHT"
- printf 'Thumb height: %s\n' "$THUMBHEIGHT"
- printf 'Max previews per page: %s\n' "$MAXPREVIEWS"
- printf 'Image jobs: %s\n' "$IMAGE_JOBS"
- printf 'Random seed: %s\n' "$RANDOM_SEED"
- printf 'Shuffle: %s\n' "$SHUFFLE"
- printf 'Splash page: %s\n' "$SPLASH_PAGE"
- printf 'Image count: %s\n' "$image_count"
- printf 'Tarball setting: %s\n' "$TARBALL_INCLUDE"
if [ "$TARBALL_INCLUDE" = yes ]; then
- printf 'Tarball name plan: %s\n' "$(tarball_name_plan)"
- else
- printf 'Tarball name plan: not planned\n'
+ plan_ref["tarball_name_plan"]=$(tarball_name_plan)
fi
+ collect_dry_run_page_plan "$plan_name" "$image_count"
+}
+
+print_dry_run_plan() {
+ local -r plan_name="$1"; shift
+ # shellcheck disable=SC2178
+ local -n plan_ref="$plan_name"
+
+ printf 'Dry run: no files will be written.\n'
+ printf 'Config source: %s\n' "${plan_ref["config_source"]}"
+ printf 'Incoming directory: %s\n' "${plan_ref["incoming_dir"]}"
+ printf 'Output directory: %s\n' "${plan_ref["dist_dir"]}"
+ printf 'Template directory: %s\n' "${plan_ref["template_dir"]}"
+ printf 'Title: %s\n' "${plan_ref["title"]}"
+ printf 'Height: %s\n' "${plan_ref["height"]}"
+ printf 'Thumb height: %s\n' "${plan_ref["thumbheight"]}"
+ printf 'Max previews per page: %s\n' "${plan_ref["maxpreviews"]}"
+ printf 'Image jobs: %s\n' "${plan_ref["image_jobs"]}"
+ printf 'Random seed: %s\n' "${plan_ref["random_seed"]}"
+ printf 'Shuffle: %s\n' "${plan_ref["shuffle"]}"
+ printf 'Splash page: %s\n' "${plan_ref["splash_page"]}"
+ printf 'Image count: %s\n' "${plan_ref["image_count"]}"
+ printf 'Tarball setting: %s\n' "${plan_ref["tarball_include"]}"
+ printf 'Tarball name plan: %s\n' "${plan_ref["tarball_name_plan"]}"
+
printf 'Planned directories:\n'
- printf ' %s\n' "$DIST_DIR"
- printf ' %s/photos\n' "$DIST_DIR"
- printf ' %s/thumbs\n' "$DIST_DIR"
- printf ' %s/blurs\n' "$DIST_DIR"
+ printf ' %s\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/photos\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/thumbs\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/blurs\n' "${plan_ref["dist_dir"]}"
printf 'Planned generated files:\n'
- if [ "$SPLASH_PAGE" = yes ]; then
+ if [ "${plan_ref["splash_page"]}" = yes ]; then
printf ' %s/index.html (%s splash page)\n' \
- "$DIST_DIR" "$html_index_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["html_index_count"]}"
else
printf ' %s/index.html (%s album index redirect)\n' \
- "$DIST_DIR" "$html_index_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["html_index_count"]}"
fi
- printf ' %s/favicon.ico\n' "$DIST_DIR"
- printf ' %s/shuriken.json\n' "$DIST_DIR"
- printf ' %s/photos/* (%s image files)\n' "$DIST_DIR" "$image_count"
- printf ' %s/thumbs/* (%s image files)\n' "$DIST_DIR" "$image_count"
- printf ' %s/blurs/* (%s image files)\n' "$DIST_DIR" "$image_count"
- printf ' %s/page-*.html (%s preview pages)\n' "$DIST_DIR" "$page_count"
+ printf ' %s/favicon.ico\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/shuriken.json\n' "${plan_ref["dist_dir"]}"
+ printf ' %s/photos/* (%s image files)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
+ printf ' %s/thumbs/* (%s image files)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
+ printf ' %s/blurs/* (%s image files)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
+ printf ' %s/page-*.html (%s preview pages)\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["page_count"]}"
printf ' %s/[page]-[image].html (%s view pages)\n' \
- "$DIST_DIR" "$image_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["image_count"]}"
printf ' %s/[page]-[image]-details.html (%s details pages)\n' \
- "$DIST_DIR" "$details_count"
+ "${plan_ref["dist_dir"]}" "${plan_ref["details_count"]}"
printf ' %s/[redirect].html (%s navigation redirects)\n' \
- "$DIST_DIR" "$redirect_count"
- if [ "$TARBALL_INCLUDE" = yes ]; then
- printf ' %s/%s\n' "$DIST_DIR" "$(tarball_name_plan)"
+ "${plan_ref["dist_dir"]}" "${plan_ref["redirect_count"]}"
+ if [ "${plan_ref["tarball_include"]}" = yes ]; then
+ printf ' %s/%s\n' \
+ "${plan_ref["dist_dir"]}" "${plan_ref["tarball_name_plan"]}"
fi
}
diff --git a/tests/cli.sh b/tests/cli.sh
index 7aeddfd..c4e3814 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -1801,6 +1801,59 @@ test_dry_run_reports_cli_overrides_without_writes() {
test::teardown
}
+test_dry_run_reports_empty_plan_without_writes() {
+ local config_file
+ local dist_dir
+ local fake_bin
+ local forbidden_log
+ local incoming_dir
+ local output
+
+ test::setup
+ fake_bin="$TEST_TMPDIR/bin"
+ config_file="$TEST_TMPDIR/shuriken.conf"
+ dist_dir="$TEST_TMPDIR/dist"
+ forbidden_log="$TEST_TMPDIR/forbidden-tools.log"
+ incoming_dir="$TEST_TMPDIR/incoming"
+ mkdir -p "$incoming_dir"
+ test::install_failing_generation_tools "$fake_bin"
+ test::write_preflight_config \
+ "$config_file" "$incoming_dir" "$dist_dir" \
+ "$TEST_REPO_ROOT/share/templates/default"
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ PATH="$fake_bin:$PATH" \
+ TEST_FORBIDDEN_TOOL_LOG="$forbidden_log" \
+ "$TEST_SHURIKEN" --dry-run --config "$config_file"
+ )
+
+ test::assert_contains 'Dry run: no files will be written.' "$output"
+ test::assert_contains 'Image count: 0' "$output"
+ test::assert_contains 'Tarball name plan: not planned' "$output"
+ test::assert_contains \
+ " $dist_dir/index.html (1 splash page)" \
+ "$output"
+ test::assert_contains " $dist_dir/photos/* (0 image files)" "$output"
+ test::assert_contains " $dist_dir/thumbs/* (0 image files)" "$output"
+ test::assert_contains " $dist_dir/blurs/* (0 image files)" "$output"
+ test::assert_contains " $dist_dir/page-*.html (0 preview pages)" \
+ "$output"
+ test::assert_contains \
+ " $dist_dir/[page]-[image].html (0 view pages)" \
+ "$output"
+ test::assert_contains \
+ " $dist_dir/[page]-[image]-details.html (0 details pages)" \
+ "$output"
+ test::assert_contains \
+ " $dist_dir/[redirect].html (0 navigation redirects)" \
+ "$output"
+ test::assert_path_absent "$dist_dir"
+ test::assert_path_absent "$forbidden_log"
+ test::assert_no_staging_dirs "$TEST_TMPDIR"
+ test::teardown
+}
+
test_dry_run_rejects_invalid_config_and_input() {
local config_file
local dist_dir
@@ -4766,6 +4819,9 @@ main() {
'--dry-run reports CLI overrides without writes' \
test_dry_run_reports_cli_overrides_without_writes
test::run_case \
+ '--dry-run reports empty plan without writes' \
+ test_dry_run_reports_empty_plan_without_writes
+ test::run_case \
'--dry-run rejects invalid config and input' \
test_dry_run_rejects_invalid_config_and_input
test::run_case \