fix: New README, new documentation for developpers, and many install.sh and update.sh fixes

This commit is contained in:
Gu://em_ 2026-05-04 22:57:12 +02:00
parent 38d2572e84
commit 6b92f7a0a0
5 changed files with 282 additions and 45 deletions

View file

@ -497,6 +497,9 @@ install_packages() {
local pkg_file pkgs group
# Helper: install a group and save state
# Note: AUR packages are installed one-by-one so a single failure does not abort
# the whole group. Official repo packages are bulk-installed with a per-
# package fallback. Only successfully installed packages are saved to state.
install_group() {
local group="$1"
local pkg_file="$PACKAGES_DIR/${group}.pkgs"
@ -506,25 +509,114 @@ install_packages() {
(( ${#pkgs[@]} == 0 )) && { info "${group}: empty — skipping"; return; }
step "Group: ${group} (${#pkgs[@]} packages)"
local succeeded=() failed=()
if [[ $group == aur ]]; then
run_quiet " Installing ${group}" paru_install "${pkgs[@]}"
for pkg in "${pkgs[@]}"; do
local tmp; tmp=$(mktemp)
if [[ $IS_TTY == true ]]; then
spinner_start " [aur] $pkg"
if paru -S --needed --noconfirm "$pkg" >"$tmp" 2>&1; then
spinner_stop ok "[aur] $pkg"; succeeded+=("$pkg")
else
spinner_stop fail "[aur] $pkg"
warn "paru output:"; cat "$tmp" | indent; failed+=("$pkg")
fi
else
printf " ... [aur] %s\n" "$pkg"
if paru -S --needed --noconfirm "$pkg" >"$tmp" 2>&1; then
ok "[aur] $pkg"; succeeded+=("$pkg")
else
err "[aur] $pkg"
warn "paru output:"; cat "$tmp" | indent; failed+=("$pkg")
fi
fi
rm -f "$tmp"
done
else
run_quiet " Installing ${group}" pacman_install "${pkgs[@]}"
local tmp; tmp=$(mktemp)
if pacman_install "${pkgs[@]}" >"$tmp" 2>&1; then
succeeded=("${pkgs[@]}"); rm -f "$tmp"
else
rm -f "$tmp"
warn "Bulk install failed for group '${group}' — retrying per package"
for pkg in "${pkgs[@]}"; do
local tmp2; tmp2=$(mktemp)
if [[ $IS_TTY == true ]]; then
spinner_start " [${group}] $pkg"
if pacman_install "$pkg" >"$tmp2" 2>&1; then
spinner_stop ok "[${group}] $pkg"; succeeded+=("$pkg")
else
spinner_stop fail "[${group}] $pkg"
warn "pacman output:"; cat "$tmp2" | indent; failed+=("$pkg")
fi
else
printf " ... [%s] %s\n" "$group" "$pkg"
if pacman_install "$pkg" >"$tmp2" 2>&1; then
ok "[${group}] $pkg"; succeeded+=("$pkg")
else
err "[${group}] $pkg"
warn "pacman output:"; cat "$tmp2" | indent; failed+=("$pkg")
fi
fi
rm -f "$tmp2"
done
fi
fi
save_pkg_list "$group" "${pkgs[@]}"
if (( ${#succeeded[@]} )); then
save_pkg_list "$group" "${succeeded[@]}"
fi
if (( ${#failed[@]} )); then
warn "Failed in group '${group}' (will retry on next update):"
for pkg in "${failed[@]}"; do
printf " - %s\n" "$pkg"
done
fi
return 0
}
# stow itself (needed for the next step)
run_quiet "Ensuring stow is present" sudo pacman -S --needed --noconfirm stow
# Core
# Build the set of groups that are handled specially so we can exclude them
# when iterating all .pkgs files for automatic groups.
local hw_groups=("${HW_CPU}-cpu" "${HW_GPU}-gpu")
local optional_group_names=()
local optional_file="$PACKAGES_DIR/optional.groups"
if [[ -f $optional_file ]]; then
mapfile -t optional_group_names < <(grep -v '^\s*#' "$optional_file" | grep -v '^\s*$')
fi
is_special_group() {
local g="$1"
# Returns 0 if the group is hw, optional, aur, or security (handled separately)
[[ $g == aur || $g == security ]] && return 0
for hw in "${hw_groups[@]}"; do [[ $g == "$hw" ]] && return 0; done
for og in "${optional_group_names[@]}"; do [[ $g == "$og" ]] && return 0; done
return 1
}
# 1. Core
install_group "core"
# Hardware
install_group "${HW_CPU}-cpu" 2>/dev/null || true
install_group "${HW_GPU}-gpu" 2>/dev/null || true
# 2. Hardware (auto-detected)
install_group "${HW_CPU}-cpu"
install_group "${HW_GPU}-gpu"
# Security extras
# 3. All remaining automatic groups (every .pkgs file that is not special)
while IFS= read -r pkg_file; do
local group; group=$(basename "$pkg_file" .pkgs)
is_special_group "$group" && continue
[[ $group == core ]] && continue # already done above
install_group "$group"
done < <(find "$PACKAGES_DIR" -maxdepth 1 -name "*.pkgs" | sort)
# 4. Security extras
if [[ $INSTALL_SECURITY == true ]]; then
local sec_pkgs=(ufw apparmor zram-generator)
step "Security extras"
@ -532,12 +624,12 @@ install_packages() {
save_pkg_list "security" "${sec_pkgs[@]}"
fi
# Optional chosen groups
# 5. Optional chosen groups
for group in "${CHOSEN_OPTIONAL_GROUPS[@]}"; do
install_group "$group"
done
# AUR group (always, if paru is present)
# 6. AUR group
install_group "aur"
phase_done
@ -547,9 +639,9 @@ install_packages() {
# STEP 9 — Clone into ~/.atlas-dotfiles and stow
# ─────────────────────────────────────────────────────────────────────────────
stow_dotfiles() {
phase "Copying and stowing dotfiles"
phase "Cloning and stowing dotfiles"
# ~/.atlas-dotfiles is the permanent home of the repo. They can delete the original
# ~/.atlas-dotfiles is the permanent home of the repo. You can delete the original
# clone after installation without breaking anything.
local remote_url
remote_url=$(git -C "$REPO_DIR" remote get-url origin 2>/dev/null || true)

View file

@ -15,6 +15,8 @@ STATE_DIR="$DOTFILES_DIR/.state"
PKG_STATE_DIR="$STATE_DIR/packages"
STATE_FILE="$STATE_DIR/update.state"
PACKAGES_DIR="$DOTFILES_DIR/packages"
STOW_DIR="$DOTFILES_DIR"
STOW_PKG="config"
STOW_TARGET="$HOME"
# ── Colours ──────────────────────────────────────────────────────────────────
@ -188,20 +190,32 @@ git_fetch_and_check() {
OLD_HASH="$local_hash"
}
# ── Conflict detection ────────────────────────────────────────────────────────
collect_changed_files() {
# Files changed inside the config/ stow package between old and new commit.
# Strip the leading "config/" prefix so paths are relative to $HOME,
# matching what stow creates as symlink targets.
# ── Change detection ────────────────────────────────────────────────────────────────
# Files changed inside config/ (stow package) — used for conflict detection.
# Paths are stripped of the "config/" prefix so they match $HOME-relative targets.
collect_changed_config_files() {
git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \
| grep '^config/' \
| sed 's|^config/||' \
|| true
}
# Returns 0 (true) if any file under packages/ changed between the two commits.
packages_changed() {
git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \
| grep -q '^packages/'
}
# Returns 0 (true) if any file under scripts/ changed between the two commits.
scripts_changed() {
git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \
| grep -q '^scripts/'
}
handle_conflicts() {
local repo_changed_files
mapfile -t repo_changed_files < <(collect_changed_files)
mapfile -t repo_changed_files < <(collect_changed_config_files)
if (( ${#repo_changed_files[@]} == 0 )); then
return
@ -502,10 +516,37 @@ main() {
if [[ $HAS_UPDATE == true ]]; then
handle_conflicts
apply_git_update
# Re-stow config/ whenever dotfiles changed
apply_stow
# Re-stow scripts/ when it changed (keeps ~/.local/bin helpers up to date)
if scripts_changed; then
info "scripts/ changed — re-linking binaries"
local err_file; err_file=$(mktemp)
if stow --dir="$DOTFILES_DIR" --target="$HOME" --restow scripts \
2>"$err_file"; then
ok "stow: scripts"
else
warn "stow: scripts (errors below)"
while IFS= read -r line; do
echo " ${DIM}${line}${RESET}"
done < "$err_file"
fi
rm -f "$err_file"
fi
state_set "last_commit" "$NEW_HASH"
# Re-process packages whenever packages/ changed, even if no git update
# produced new dotfiles — package lists are independent of stowed files.
if packages_changed; then
info "packages/ changed — running full package sync"
fi
fi
# Package sync runs on every invocation (diff vs saved state catches changes).
# This also handles the case where a previous run partially failed.
process_packages
process_aur_group