diff --git a/home/.chezmoiscripts/darwin/run_once_01_install-homebrew.sh.tmpl b/home/.chezmoiscripts/darwin/run_once_01_install-homebrew.sh.tmpl index 423a8cb..c2a7afb 100644 --- a/home/.chezmoiscripts/darwin/run_once_01_install-homebrew.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_once_01_install-homebrew.sh.tmpl @@ -2,5 +2,6 @@ {{ if eq .chezmoi.os "darwin" }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} {{ template "lib/install/homebrew.sh" . }} {{ end }} diff --git a/home/.chezmoiscripts/darwin/run_onchange_02_install-packages.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_02_install-packages.sh.tmpl index fcd636c..fe2d052 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_02_install-packages.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_02_install-packages.sh.tmpl @@ -4,6 +4,7 @@ {{ if eq .chezmoi.os "darwin" }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} HOMEBREW_BUNDLE_CONTENT=$(cat <<'BREWFILE' {{ range $groups }}# {{ . }} {{- $g := index $.packages.darwin.homebrew . }} diff --git a/home/.chezmoiscripts/darwin/run_onchange_03_install-mise-tools.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_03_install-mise-tools.sh.tmpl index 63bebd4..1a169cf 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_03_install-mise-tools.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_03_install-mise-tools.sh.tmpl @@ -4,5 +4,6 @@ {{ if eq .chezmoi.os "darwin" }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} {{ template "lib/install/mise.sh" . }} {{ end }} diff --git a/home/.chezmoiscripts/darwin/run_onchange_03_install-uv-tools.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_03_install-uv-tools.sh.tmpl index e69c052..7760612 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_03_install-uv-tools.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_03_install-uv-tools.sh.tmpl @@ -9,6 +9,7 @@ {{ if and (eq .chezmoi.os "darwin") $hasTools }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} UV_TOOLS=( {{ range $groups -}} {{ $tools := index $.uv.tools . -}} diff --git a/home/.chezmoiscripts/darwin/run_onchange_04_install-vscode-extensions.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_04_install-vscode-extensions.sh.tmpl index 46ad3cd..92778b9 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_04_install-vscode-extensions.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_04_install-vscode-extensions.sh.tmpl @@ -3,6 +3,7 @@ {{ if eq .chezmoi.os "darwin" }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} VSCODE_EXTENSIONS=( # shared {{ range .vscode.shared -}} diff --git a/home/.chezmoiscripts/darwin/run_onchange_06_install-apm.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_06_install-apm.sh.tmpl index cd2ec78..6e6035c 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_06_install-apm.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_06_install-apm.sh.tmpl @@ -11,5 +11,6 @@ {{ if eq .chezmoi.os "darwin" }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} {{ template "lib/install/apm.sh" . }} {{ end }} diff --git a/home/.chezmoiscripts/darwin/run_onchange_07_fix-opencode-agent-tools.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_07_fix-opencode-agent-tools.sh.tmpl index d3a8a6d..8b7ee22 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_07_fix-opencode-agent-tools.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_07_fix-opencode-agent-tools.sh.tmpl @@ -3,5 +3,6 @@ {{ if eq .chezmoi.os "darwin" }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} {{ template "lib/install/opencode-agent-tools.sh" . }} {{ end }} diff --git a/home/.chezmoiscripts/darwin/run_onchange_08_install-graphify-skills.sh.tmpl b/home/.chezmoiscripts/darwin/run_onchange_08_install-graphify-skills.sh.tmpl index 89a579e..1e38d42 100644 --- a/home/.chezmoiscripts/darwin/run_onchange_08_install-graphify-skills.sh.tmpl +++ b/home/.chezmoiscripts/darwin/run_onchange_08_install-graphify-skills.sh.tmpl @@ -10,6 +10,7 @@ {{ if and (eq .chezmoi.os "darwin") (gt (len $platforms) 0) }} {{ template "lib/common/log.sh" . }} +{{ template "lib/common/install-prelude.sh" . }} GRAPHIFY_PLATFORMS=( {{ range $platforms -}} "{{ . }}" diff --git a/home/.chezmoitemplates/lib/common/install-prelude.sh b/home/.chezmoitemplates/lib/common/install-prelude.sh new file mode 100644 index 0000000..692c3c0 --- /dev/null +++ b/home/.chezmoitemplates/lib/common/install-prelude.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# @file lib/common/install-prelude.sh +# @brief Shared prelude for install libraries under lib/install. +# @description +# Provides the install-time trace toggle and the require_command guard so +# each install library keeps only its unique work. Depends on lib/common/log.sh +# for log_error. Sourceable from bats tests and injected into chezmoi run +# scripts via chezmoi template rendering, after lib/common/log.sh and before +# the install library. +# +# Error-handling convention: +# Missing prerequisite tool: call require_command and return on failure. + +if [ "${DOTFILES_DEBUG:-}" ]; then + set -x +fi + +# +# @description Fail when a required command is absent from PATH. +# @arg $1 Command name to look up. +# @arg $2 Hint shown when the command is missing. +# @exitcode 0 Command is available. +# @exitcode 1 Command is missing. +# +function require_command() { + command -v "$1" >/dev/null 2>&1 || { + log_error "[$1] not found. $2" + return 1 + } +} diff --git a/home/.chezmoitemplates/lib/install/apm.sh b/home/.chezmoitemplates/lib/install/apm.sh index 694f0ea..fed3c3b 100644 --- a/home/.chezmoitemplates/lib/install/apm.sh +++ b/home/.chezmoitemplates/lib/install/apm.sh @@ -8,10 +8,6 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - # # @description Install APM dependencies from `${HOME}/.apm/apm.yml`. # diff --git a/home/.chezmoitemplates/lib/install/graphify-skills.sh b/home/.chezmoitemplates/lib/install/graphify-skills.sh index 6e1830c..9786f69 100644 --- a/home/.chezmoitemplates/lib/install/graphify-skills.sh +++ b/home/.chezmoitemplates/lib/install/graphify-skills.sh @@ -8,17 +8,6 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - -# -# @description Check if the Graphify CLI is installed. -# -function is_graphify_installed() { - command -v graphify >/dev/null 2>&1 -} - # # @description Install Graphify skills for selected platforms. # @@ -37,10 +26,7 @@ function graphify_skills_install_main() { return 0 fi - if ! is_graphify_installed; then - log_error "[graphify] graphify not found. Ensure run_onchange_03_install-uv-tools ran successfully." - return 1 - fi + require_command graphify "Ensure run_onchange_03_install-uv-tools ran successfully." || return 1 log_info "[graphify] Installing Graphify agent skills..." diff --git a/home/.chezmoitemplates/lib/install/homebrew-bundle.sh b/home/.chezmoitemplates/lib/install/homebrew-bundle.sh index 5be19fa..bfbf39c 100644 --- a/home/.chezmoitemplates/lib/install/homebrew-bundle.sh +++ b/home/.chezmoitemplates/lib/install/homebrew-bundle.sh @@ -8,25 +8,11 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - -# -# @description Check if Homebrew is installed. -# -function is_homebrew_installed() { - command -v brew >/dev/null 2>&1 -} - # # @description Install packages from rendered Brewfile content. # function homebrew_bundle_main() { - if ! is_homebrew_installed; then - log_error "[homebrew] Homebrew not found. Ensure run_once_01_install-homebrew ran successfully." - return 1 - fi + require_command brew "Ensure run_once_01_install-homebrew ran successfully." || return 1 log_info "[homebrew] Updating Homebrew metadata..." brew update diff --git a/home/.chezmoitemplates/lib/install/homebrew.sh b/home/.chezmoitemplates/lib/install/homebrew.sh index cb8cfa6..184180d 100644 --- a/home/.chezmoitemplates/lib/install/homebrew.sh +++ b/home/.chezmoitemplates/lib/install/homebrew.sh @@ -7,10 +7,6 @@ # rendering. set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - # # @description Check if Homebrew is installed. # diff --git a/home/.chezmoitemplates/lib/install/mise.sh b/home/.chezmoitemplates/lib/install/mise.sh index 121d900..e6e9618 100644 --- a/home/.chezmoitemplates/lib/install/mise.sh +++ b/home/.chezmoitemplates/lib/install/mise.sh @@ -8,17 +8,6 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - -# -# @description Check if mise is installed. -# -function is_mise_installed() { - command -v mise >/dev/null 2>&1 -} - # # @description Install tools declared in mise config. # @@ -32,10 +21,7 @@ function mise_install_main() { # @description Run the mise install flow. # function main() { - if ! is_mise_installed; then - log_error "[mise] mise not found. Ensure run_onchange_02_install-packages ran successfully." - return 1 - fi + require_command mise "Ensure run_onchange_02_install-packages ran successfully." || return 1 mise_install_main } diff --git a/home/.chezmoitemplates/lib/install/opencode-agent-tools.sh b/home/.chezmoitemplates/lib/install/opencode-agent-tools.sh index 9be23a3..1a52cfa 100644 --- a/home/.chezmoitemplates/lib/install/opencode-agent-tools.sh +++ b/home/.chezmoitemplates/lib/install/opencode-agent-tools.sh @@ -14,10 +14,6 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - # # @description Rewrite one markdown file's frontmatter `tools:` array # (if any) into opencode's expected map form. Writes back in place. diff --git a/home/.chezmoitemplates/lib/install/uv-tools.sh b/home/.chezmoitemplates/lib/install/uv-tools.sh index d59f1f7..262f482 100644 --- a/home/.chezmoitemplates/lib/install/uv-tools.sh +++ b/home/.chezmoitemplates/lib/install/uv-tools.sh @@ -8,17 +8,6 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - -# -# @description Check if uv is installed. -# -function is_uv_installed() { - command -v uv >/dev/null 2>&1 -} - # # @description Install tools declared in UV_TOOLS. # @@ -38,10 +27,7 @@ function uv_tools_install_main() { # @description Run the uv tool install flow. # function main() { - if ! is_uv_installed; then - log_error "[uv] uv not found. Ensure run_onchange_03_install-mise-tools ran successfully." - return 1 - fi + require_command uv "Ensure run_onchange_03_install-mise-tools ran successfully." || return 1 uv_tools_install_main } diff --git a/home/.chezmoitemplates/lib/install/vscode.sh b/home/.chezmoitemplates/lib/install/vscode.sh index de5d29c..582db2c 100644 --- a/home/.chezmoitemplates/lib/install/vscode.sh +++ b/home/.chezmoitemplates/lib/install/vscode.sh @@ -8,10 +8,6 @@ set -Eeuo pipefail -if [ "${DOTFILES_DEBUG:-}" ]; then - set -x -fi - # # @description Check if the VS Code CLI is installed. # diff --git a/tests/template/darwin-install-scripts.bats b/tests/template/darwin-install-scripts.bats index c1e2859..7a676ee 100644 --- a/tests/template/darwin-install-scripts.bats +++ b/tests/template/darwin-install-scripts.bats @@ -43,6 +43,18 @@ render_template_with_data() { assert_file_contains "$GRAPHIFY_TEMPLATE" '{{ template "lib/install/graphify-skills.sh" . }}' } +@test "darwin install script templates inject the install prelude" { + local prelude='{{ template "lib/common/install-prelude.sh" . }}' + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_once_01_install-homebrew.sh.tmpl" "$prelude" + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_02_install-packages.sh.tmpl" "$prelude" + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_03_install-mise-tools.sh.tmpl" "$prelude" + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_03_install-uv-tools.sh.tmpl" "$prelude" + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_04_install-vscode-extensions.sh.tmpl" "$prelude" + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_06_install-apm.sh.tmpl" "$prelude" + assert_file_contains "$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_07_fix-opencode-agent-tools.sh.tmpl" "$prelude" + assert_file_contains "$GRAPHIFY_TEMPLATE" "$prelude" +} + @test "rendered darwin install scripts are syntactically valid bash" { for template in "$DOTFILES_ROOT"/home/.chezmoiscripts/darwin/*.tmpl; do rendered="$(render_template "$template")" diff --git a/tests/unit/lib/install/graphify-skills.bats b/tests/unit/lib/install/graphify-skills.bats index 466fdef..57877ec 100644 --- a/tests/unit/lib/install/graphify-skills.bats +++ b/tests/unit/lib/install/graphify-skills.bats @@ -5,6 +5,7 @@ load '../../../test_helpers/load.bash' LOG_LIB="$DOTFILES_ROOT/home/.chezmoitemplates/lib/common/log.sh" +PRELUDE="$DOTFILES_ROOT/home/.chezmoitemplates/lib/common/install-prelude.sh" LIB="$DOTFILES_ROOT/home/.chezmoitemplates/lib/install/graphify-skills.sh" setup() { @@ -21,7 +22,7 @@ GRAPHIFY } @test "main: installs each Graphify platform" { - run bash -c "source '$LOG_LIB' && source '$LIB' && GRAPHIFY_PLATFORMS=('agents' 'claude') && main" + run bash -c "source '$LOG_LIB' && source '$PRELUDE' && source '$LIB' && GRAPHIFY_PLATFORMS=('agents' 'claude') && main" assert_success assert_line "[graphify] Installing Graphify agent skills..." @@ -30,7 +31,7 @@ GRAPHIFY } @test "main: skips empty platform entries" { - run bash -c "source '$LOG_LIB' && source '$LIB' && GRAPHIFY_PLATFORMS=('agents' '' 'claude') && main" + run bash -c "source '$LOG_LIB' && source '$PRELUDE' && source '$LIB' && GRAPHIFY_PLATFORMS=('agents' '' 'claude') && main" assert_success [ "$(<"$GRAPHIFY_ARGS_FILE")" = $'install --platform agents\ninstall --platform claude' ] @@ -39,7 +40,7 @@ GRAPHIFY @test "main: exits cleanly with no Graphify platforms" { rm -f "$BATS_TEST_TMPDIR/bin/graphify" - run bash -c "source '$LOG_LIB' && source '$LIB' && GRAPHIFY_PLATFORMS=() && main" + run bash -c "source '$LOG_LIB' && source '$PRELUDE' && source '$LIB' && GRAPHIFY_PLATFORMS=() && main" assert_success assert_line "[graphify] No Graphify platforms to install." @@ -49,8 +50,8 @@ GRAPHIFY @test "main: fails when graphify is missing" { rm -f "$BATS_TEST_TMPDIR/bin/graphify" - run bash -c "source '$LOG_LIB' && source '$LIB' && GRAPHIFY_PLATFORMS=('agents') && main" + run bash -c "source '$LOG_LIB' && source '$PRELUDE' && source '$LIB' && GRAPHIFY_PLATFORMS=('agents') && main" assert_failure 1 - assert_line "error: [graphify] graphify not found. Ensure run_onchange_03_install-uv-tools ran successfully." + assert_line "error: [graphify] not found. Ensure run_onchange_03_install-uv-tools ran successfully." } diff --git a/tests/unit/lib/install/homebrew-bundle.bats b/tests/unit/lib/install/homebrew-bundle.bats index 396d249..4023b74 100644 --- a/tests/unit/lib/install/homebrew-bundle.bats +++ b/tests/unit/lib/install/homebrew-bundle.bats @@ -5,6 +5,7 @@ load '../../../test_helpers/load.bash' LOG_LIB="$DOTFILES_ROOT/home/.chezmoitemplates/lib/common/log.sh" +PRELUDE="$DOTFILES_ROOT/home/.chezmoitemplates/lib/common/install-prelude.sh" LIB="$DOTFILES_ROOT/home/.chezmoitemplates/lib/install/homebrew-bundle.sh" setup() { @@ -35,7 +36,7 @@ BREW @test "homebrew_bundle_main: runs brew bundle with rendered Brewfile content" { export HOMEBREW_BUNDLE_CONTENT=$'tap "homebrew/core"\nbrew "git"' - run bash -c "source '$LOG_LIB' && source '$LIB' && homebrew_bundle_main" + run bash -c "source '$LOG_LIB' && source '$PRELUDE' && source '$LIB' && homebrew_bundle_main" assert_success assert_line "[homebrew] Updating Homebrew metadata..." @@ -49,7 +50,7 @@ BREW export HOMEBREW_BUNDLE_CONTENT='brew "git"' export BREW_BUNDLE_EXIT_CODE=7 - run bash -c "source '$LOG_LIB' && source '$LIB' && homebrew_bundle_main" + run bash -c "source '$LOG_LIB' && source '$PRELUDE' && source '$LIB' && homebrew_bundle_main" assert_failure 7 assert_line "[homebrew] Running brew bundle..."