mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 22:07:03 +01:00
Also bumps the 16 meta/requirements pins the freshness gate flagged (anthropic 1.5.0, numpy 2.5.3, pytest-randomly 5, flake8-bugbear 26.9.9, ruff 0.16.7, pyright 1.1.414, selenium 4.49.0, hypothesis 6.168.0, lxml 6.1.3, pipdeptree 4.2.5, the two types-* stubs) and Flutter 3.47.3 in meta/.fvmrc. One test still expected the pre-move ~/mcp-servers path. The pre-commit hook fed .zsh files to shfmt and shellcheck, neither of which parses zsh (SC2148/SC1071), so no zsh file could be committed since the hook was tightened on 2026-08-22; those now get `zsh -n` instead. The hook's own shfmt pass also staged its reformat of 8 shell files. CI_GREEN_SKIP because main is red on exactly the dependency-freshness finding this commit fixes, which is the documented use of that flag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
216 lines
8.9 KiB
Bash
Executable File
216 lines
8.9 KiB
Bash
Executable File
#!/bin/bash
|
||
# Unified installer for all personal Linux system modules.
|
||
#
|
||
# This installer is CROSS-REPO: several modules were extracted into sibling
|
||
# repos. A missing sibling is cloned automatically (see require_extracted_repo);
|
||
# a clone that fails is a loud module failure, never a silent skip.
|
||
#
|
||
# CORE modules (always installed):
|
||
# 0. Guard library (guardctl) – github.com/kuhyx/utils (~/src/utils/guard-lib)
|
||
# 1. Workout screen locker – github.com/kuhyx/screen-locker (~/src/screen-locker)
|
||
# 2. Hosts blocking setup – github.com/kuhyx/hosts-blocker (~/src/hosts-blocker)
|
||
# 3. Midnight shutdown timer – github.com/kuhyx/digital-wellbeing
|
||
#
|
||
# SECONDARY modules (prompted unless --all / --none given):
|
||
# 4. Steam backlog enforcer – github.com/kuhyx/steam-backlog-enforcer
|
||
# 5. Pacman wrapper – github.com/kuhyx/digital-wellbeing (~/src/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"
|
||
# 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
|
||
}
|
||
|
||
# install_module_from_repo <repo-name> <what> <script-rel-path> [args...]
|
||
# Runs an installer that lives in a sibling repo extracted out of this monorepo.
|
||
#
|
||
# This installer is cross-repo: screen-locker, steam-backlog-enforcer and
|
||
# guard-lib (inside utils) are separate checkouts now. require_extracted_repo
|
||
# clones a missing one, so a bare machine still gets a working install from the
|
||
# single documented command. If the clone fails, or the repo is present but the
|
||
# script inside it is not, that is a hard failure -- the module lands in the
|
||
# Failed() summary rather than being silently skipped, which is the failure mode
|
||
# that let these two defects survive unnoticed.
|
||
#
|
||
# ROOT_MODE selects how the script is invoked:
|
||
# auto - run as-is; the script elevates itself if it needs to (default)
|
||
# sudo - run under sudo; for scripts that require root but do NOT self-elevate
|
||
# (guard-lib's install.sh hard-exits as non-root instead of re-execing)
|
||
# Never blanket-sudo: screen-locker installs a systemd *user* service into
|
||
# $HOME/.config/systemd/user, so running it as root would install it for /root.
|
||
install_module_from_repo() {
|
||
local repo="$1" what="$2" rel="$3" root_mode="${ROOT_MODE:-auto}"
|
||
shift 3
|
||
local dir script
|
||
dir="$(require_extracted_repo "$repo" "$what")" || return 1
|
||
script="$dir/$rel"
|
||
if [[ ! -f $script ]]; then
|
||
printf 'ERROR: %s: expected installer not found at %s\n' "$what" "$script" >&2
|
||
return 1
|
||
fi
|
||
if [[ $root_mode == "sudo" && $EUID -ne 0 ]]; then
|
||
sudo bash "$script" "$@"
|
||
else
|
||
bash "$script" "$@"
|
||
fi
|
||
}
|
||
|
||
# install_root_module <repo> <what> <script-rel-path> [args...]
|
||
# As install_module_from_repo, for installers that require root but do not
|
||
# elevate themselves. A separate function rather than an env prefix because
|
||
# `env VAR=x fn` does not work -- these are shell functions, not binaries.
|
||
install_root_module() {
|
||
ROOT_MODE=sudo install_module_from_repo "$@"
|
||
}
|
||
|
||
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…")"
|
||
|
||
# guard-lib provides guardctl, which the hosts guards and the shutdown timer
|
||
# both hard-depend on. It must land BEFORE them: setup_midnight_shutdown.sh
|
||
# dies with "guardctl not found on PATH" otherwise, which used to make the
|
||
# midnight-shutdown module fail on every fresh machine.
|
||
#
|
||
# guard-lib is not its own repo -- it is a subdirectory of github.com/kuhyx/utils,
|
||
# so the handle is "utils". Asking for "guard-lib" would resolve to ~/guard-lib
|
||
# and derive a clone URL that does not exist.
|
||
run_installer "Guard library (guardctl)" \
|
||
install_root_module utils "Guard library" guard-lib/install.sh
|
||
|
||
run_installer "Workout screen locker" \
|
||
install_module_from_repo screen-locker "Workout screen locker" install_systemd.sh
|
||
|
||
run_installer "Hosts blocking" \
|
||
install_module_from_repo hosts-blocker "Hosts blocking" install.sh
|
||
|
||
run_installer "Midnight shutdown timer" \
|
||
install_module_from_repo digital-wellbeing "Midnight shutdown timer" setup_midnight_shutdown.sh
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# SECONDARY MODULES (prompted unless --all / --none)
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
printf '\n%s\n' "$(bold "Secondary modules (${SECONDARY_MODE})…")"
|
||
|
||
ask_install "Steam backlog enforcer" \
|
||
install_module_from_repo steam-backlog-enforcer "Steam backlog enforcer" install.sh
|
||
|
||
ask_install "Pacman wrapper" \
|
||
install_module_from_repo digital-wellbeing "Pacman wrapper" pacman/install_pacman_wrapper.sh
|
||
|
||
ask_install "i3 configuration" \
|
||
bash "$LINUX_CONFIG/i3/install.sh"
|
||
|
||
ask_install "Compulsive opening blockade" \
|
||
install_root_module digital-wellbeing "Compulsive opening blockade" block_compulsive_opening.sh install
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
print_summary
|