testsAndMisc/linux_configuration/install_core_system.sh
Krzysztof kuhy Rudnicki 6b828d29aa Extract digital-wellbeing; the directory-depth cap now enforces
The last unit over the cap is now github.com/kuhyx/digital-wellbeing, cloned
at ~/digital-wellbeing, and `--warn` is gone from the directory-depth-cap
hook. `check_directory_depth.sh --all` exits 0 with zero violations, down from
46 at the start of the session. That was the point of the campaign.

History was filtered across all three paths the unit has lived at (63
commits); the current path alone holds 2.

The six suites that test this code lived in linux_configuration/tests/ rather
than beside it, so they were filtered separately (24 commits) and merged in as
a second root. A path filter of the unit alone would have left them here,
testing code that had left the repo -- and their names would still have been
in shell-tests.yml's hardcoded arrays, failing CI on missing files.

linux_configuration/lib/common.sh is vendored into vendor/ rather than trimmed
to the four functions actually used: set_actual_user_vars calls two of the
others, so a trim breaks silently. It is in vendor/ and not lib/ because
test_music_parallelism.sh copies the unit's own lib/ into a scratch worktree
while stubbing the shared lib; in one directory the real common.sh overwrote
the stub, and the suite silently measured the wrong library.

Running the callers caught what shellcheck and grep both missed:
check_and_enable_services.sh died with "DW_REPO: unbound variable" because the
definition sat below its first use. It now runs clean and reports ok for every
extracted-unit check.

Two long-standing live defects fixed as a consequence. The pacman-wrapper
drift manifest embeds ABSOLUTE paths and had named deleted scripts/ paths
since the flatten, so the check reported a permanent false "stale or
tampered"; it now verifies, with unchanged hashes proving the extracted bytes
are identical. And the last two stale live references are gone: 8 -> 0.

The two pre-commit excludes for setup_midnight_shutdown.sh are dropped rather
than moved. lsattr shows nothing in the unit is chattr +i any more, and the
fixer hooks leave the file alone when allowed to run.

Removing 80 shell files also shrank the jscpd denominator enough that the
virtualenv/tqdm clones inside the GENERATED .ci-mirror-venv/ tipped the repo
to 2.09% and blocked this commit, which adds no duplication. That directory is
the same vendored third-party shell the ignore list already excludes as
.venv/, just under another name; jscpd walks the working tree rather than the
index, so being untracked did not spare it. Excluded by name: 1.74%.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
2026-08-23 20:57:51 +02:00

159 lines
6.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Unified installer for all personal Linux system modules.
#
# CORE modules (always installed):
# 1. Workout screen locker – python_pkg/screen_locker/
# 2. Hosts blocking setup – github.com/kuhyx/hosts-blocker (~/hosts-blocker)
# 3. Midnight shutdown timer – setup_midnight_shutdown.sh
#
# SECONDARY modules (prompted unless --all / --none given):
# 4. Steam backlog enforcer – python_pkg/steam_backlog_enforcer/
# 5. Pacman wrapper – github.com/kuhyx/digital-wellbeing (~/digital-wellbeing)
# 6. i3 configuration – i3/
# 7. Compulsive opening block – block_compulsive_opening.sh
#
# Usage:
# ./install_core_system.sh [--all | --none]
#
# Flags:
# --all Install all secondary modules without prompting
# --none Skip all secondary modules
# -h Show this help
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LINUX_CONFIG="$SCRIPT_DIR"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# Locates repos extracted out of this monorepo (hosts-blocker, ...).
# shellcheck source=lib/extracted_repos.sh
source "$LINUX_CONFIG/lib/extracted_repos.sh"
# ── Colour helpers ───────────────────────────────────────────────────────────
bold() { printf '\e[1m%s\e[0m' "$*"; }
green() { printf '\e[1;32m%s\e[0m' "$*"; }
yellow() { printf '\e[1;33m%s\e[0m' "$*"; }
red() { printf '\e[1;31m%s\e[0m' "$*"; }
header() { printf '\n%s\n%s\n' "$(bold "=== $1 ===")" "$(printf '=%.0s' {1..50})"; }
ok() { printf '%s %s\n' "$(green "✓")" "$*"; }
skip() { printf '%s %s\n' "$(yellow "–")" "$*"; }
fail() { printf '%s %s\n' "$(red "✗")" "$*"; }
# ── Argument parsing ─────────────────────────────────────────────────────────
SECONDARY_MODE="ask" # ask | all | none
for arg in "$@"; do
case "$arg" in
--all) SECONDARY_MODE="all" ;;
--none) SECONDARY_MODE="none" ;;
-h | --help)
sed -n '2,/^$/p' "$0"
exit 0
;;
*)
printf 'Unknown option: %s\n' "$arg" >&2
exit 1
;;
esac
done
# ── Result tracking ──────────────────────────────────────────────────────────
declare -a INSTALLED=()
declare -a SKIPPED=()
declare -a FAILED=()
run_installer() {
local name="$1"
shift
header "$name"
if "$@"; then
ok "$name installed"
INSTALLED+=("$name")
else
fail "$name failed (exit $?)"
FAILED+=("$name")
fi
}
ask_install() {
# ask_install <name> <command...>
# Prompts user; respects SECONDARY_MODE override.
local name="$1"
shift
if [[ $SECONDARY_MODE == "none" ]]; then
skip "$name (--none)"
SKIPPED+=("$name")
return
fi
if [[ $SECONDARY_MODE == "all" ]]; then
run_installer "$name" "$@"
return
fi
# interactive
local answer
printf '\nInstall %s? [y/N] ' "$(bold "$name")"
read -r answer
if [[ "${answer,,}" == "y" ]]; then
run_installer "$name" "$@"
else
skip "$name"
SKIPPED+=("$name")
fi
}
# ── Summary ──────────────────────────────────────────────────────────────────
print_summary() {
printf '\n%s\n' "$(bold "========== INSTALL SUMMARY ==========")"
if [[ ${#INSTALLED[@]} -gt 0 ]]; then
printf '%s\n' "$(green "Installed (${#INSTALLED[@]}):")"
for m in "${INSTALLED[@]}"; do printf ' %s %s\n' "$(green "✓")" "$m"; done
fi
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
printf '%s\n' "$(yellow "Skipped (${#SKIPPED[@]}):")"
for m in "${SKIPPED[@]}"; do printf ' %s %s\n' "$(yellow "–")" "$m"; done
fi
if [[ ${#FAILED[@]} -gt 0 ]]; then
printf '%s\n' "$(red "Failed (${#FAILED[@]}):")"
for m in "${FAILED[@]}"; do printf ' %s %s\n' "$(red "✗")" "$m"; done
return 1
fi
}
# ═══════════════════════════════════════════════════════════════════════════════
# CORE MODULES (always installed)
# ═══════════════════════════════════════════════════════════════════════════════
printf '\n%s\n' "$(bold "Installing CORE modules…")"
run_installer "Workout screen locker" \
bash "$REPO_ROOT/python_pkg/screen_locker/install_systemd.sh"
run_installer "Hosts blocking" \
bash "$(extracted_repo_dir hosts-blocker)/install.sh"
run_installer "Midnight shutdown timer" \
bash "$(extracted_repo_dir digital-wellbeing)/setup_midnight_shutdown.sh"
# ═══════════════════════════════════════════════════════════════════════════════
# SECONDARY MODULES (prompted unless --all / --none)
# ═══════════════════════════════════════════════════════════════════════════════
printf '\n%s\n' "$(bold "Secondary modules (${SECONDARY_MODE})…")"
ask_install "Steam backlog enforcer" \
sudo bash "$REPO_ROOT/python_pkg/steam_backlog_enforcer/install.sh"
ask_install "Pacman wrapper" \
bash "$(extracted_repo_dir digital-wellbeing)/pacman/install_pacman_wrapper.sh"
ask_install "i3 configuration" \
bash "$LINUX_CONFIG/i3/install.sh"
ask_install "Compulsive opening blockade" \
sudo bash "$(extracted_repo_dir digital-wellbeing)/block_compulsive_opening.sh" install
# ═══════════════════════════════════════════════════════════════════════════════
print_summary