- iso/build-live-iso.sh: copy install.sh+lib/ to /usr/local/lib/void-installer/, config+profiles to /usr/local/share/installer/, bake secrets.env as /etc/installer-secrets.env, add 'Install Void Linux' .desktop launcher (opens alacritty+sudo), create /usr/local/bin/void-install wrapper - installer/first-login.sh: skip nix profile add when /nix has <4GB free (live tmpfs overlay fills up with ~3-4GB of nix packages); packages are installed on first login after the system is installed instead
129 lines
5.3 KiB
Bash
129 lines
5.3 KiB
Bash
#!/bin/bash
|
|
# First-login one-shot setup for the user.
|
|
# Installs: Claude Code, NVM + node LTS, VS Code extensions,
|
|
# and (if NIX_PACKAGES_FILE is present) nix user packages
|
|
# (google-chrome, spotify, discord, localsend, mission-center).
|
|
# Idempotent: creates ~/.first-login-done marker on success.
|
|
|
|
# NOTE: do NOT use `set -u` here — nvm.sh references unbound vars.
|
|
LOG="$HOME/.first-login.log"
|
|
exec > >(tee -a "$LOG") 2>&1
|
|
|
|
echo "==> [$(date)] first-login setup starting"
|
|
|
|
# Need network. Wait up to 60s for HTTPS connectivity.
|
|
# Use curl with a short timeout rather than getent — getent blocks indefinitely
|
|
# when the DNS nameserver is unreachable (e.g. QEMU's 10.0.2.3 not responding).
|
|
for i in $(seq 1 20); do
|
|
curl -fsSL --max-time 3 --connect-timeout 3 -o /dev/null https://api.github.com 2>/dev/null && break
|
|
sleep 3
|
|
done
|
|
if ! curl -fsSL --max-time 3 --connect-timeout 3 -o /dev/null https://api.github.com 2>/dev/null; then
|
|
echo "!! no network; aborting first-login setup (will retry next login)"
|
|
exit 0
|
|
fi
|
|
|
|
# --- Claude Code (official native installer) ---
|
|
mkdir -p "$HOME/.local/bin"
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
if ! command -v claude >/dev/null 2>&1 && [[ ! -x "$HOME/.local/bin/claude" ]]; then
|
|
echo "==> installing Claude Code via official installer"
|
|
curl -fsSL https://claude.ai/install.sh | bash || {
|
|
echo "!! claude install failed"; }
|
|
fi
|
|
|
|
# --- Nix user packages (google-chrome, spotify, discord, etc.) ---
|
|
# Present when running from the live ISO (written by build-live-iso.sh).
|
|
# In the installed system the packages come from first-boot-nix.sh instead.
|
|
# NOTE: nix packages are intentionally skipped in the live session — they
|
|
# can total 3-4 GB which exceeds the tmpfs overlay on typical hardware.
|
|
# They will be installed on the first login after the system is installed.
|
|
NIX_PACKAGES_FILE="${NIX_PACKAGES_FILE:-/usr/local/libexec/nix-packages.list}"
|
|
if [[ -r "$NIX_PACKAGES_FILE" ]] && command -v nix >/dev/null 2>&1; then
|
|
remaining=$(df -k /nix 2>/dev/null | awk 'NR==2{print $4}')
|
|
# Require at least 4GB free in /nix before attempting package install
|
|
if [[ -n "$remaining" && "$remaining" -lt 4194304 ]]; then
|
|
echo "==> skipping nix packages in live session (only ${remaining}KB free in /nix)"
|
|
echo " packages will be installed on first login after installation"
|
|
else
|
|
echo "==> installing nix user packages from $NIX_PACKAGES_FILE"
|
|
|
|
# Source nix profile.d scripts so PATH and env are set.
|
|
for f in /etc/profile.d/nix*.sh; do
|
|
# shellcheck disable=SC1090
|
|
[[ -r "$f" ]] && . "$f"
|
|
done
|
|
|
|
# Guard: nix-env --switch-profile creates a circular symlink when given
|
|
# ~/.nix-profile as the target (it points to itself). Remove it so
|
|
# 'nix profile add' can initialise a clean profile.
|
|
if [[ -L "$HOME/.nix-profile" ]]; then
|
|
_target=$(readlink "$HOME/.nix-profile")
|
|
if [[ "$_target" == ".nix-profile" || "$_target" == "$HOME/.nix-profile" ]]; then
|
|
echo " removing circular .nix-profile symlink"
|
|
rm -f "$HOME/.nix-profile"
|
|
fi
|
|
unset _target
|
|
fi
|
|
|
|
# D-Bus session is available when autostarted from Cinnamon.
|
|
if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]]; then
|
|
eval "$(dbus-launch --sh-syntax 2>/dev/null)" || true
|
|
fi
|
|
|
|
export NIXPKGS_ALLOW_UNFREE=1
|
|
|
|
mapfile -t pkgs < <(grep -vE '^\s*(#|$)' "$NIX_PACKAGES_FILE")
|
|
if [[ ${#pkgs[@]} -gt 0 ]]; then
|
|
echo " packages: ${pkgs[*]}"
|
|
# 'nix profile install' is deprecated as of nix 2.x — use 'nix profile add'
|
|
nix profile add --impure "${pkgs[@]}" 2>&1 || {
|
|
echo "!! nix profile add failed (partial install may have succeeded)"; }
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# --- NVM (best effort; nvm.sh has unbound vars so isolate it) ---
|
|
if [[ ! -s "$HOME/.nvm/nvm.sh" ]]; then
|
|
echo "==> installing NVM"
|
|
export NVM_DIR="$HOME/.nvm"
|
|
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash || \
|
|
echo "!! NVM install failed (continuing)"
|
|
fi
|
|
|
|
if [[ -s "$HOME/.nvm/nvm.sh" ]]; then
|
|
export NVM_DIR="$HOME/.nvm"
|
|
(
|
|
set +u
|
|
# shellcheck disable=SC1091
|
|
. "$NVM_DIR/nvm.sh"
|
|
if ! nvm ls --no-colors 2>/dev/null | grep -qE 'lts/'; then
|
|
echo "==> installing node LTS"
|
|
nvm install --lts || echo "!! node install failed"
|
|
fi
|
|
nvm use --lts >/dev/null 2>&1 || true
|
|
) || true
|
|
|
|
NODE_BIN_DIR="$(ls -d "$HOME"/.nvm/versions/node/v*/bin 2>/dev/null | sort -V | tail -1)"
|
|
if [[ -n "$NODE_BIN_DIR" && -d "$NODE_BIN_DIR" ]]; then
|
|
for bin in node npm npx; do
|
|
[[ -x "$NODE_BIN_DIR/$bin" ]] && ln -sf "$NODE_BIN_DIR/$bin" "$HOME/.local/bin/$bin"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# --- VS Code extensions ---
|
|
EXT_FILE=/etc/installer-vscode-extensions.txt
|
|
if [[ -r "$EXT_FILE" ]] && command -v code >/dev/null 2>&1; then
|
|
echo "==> installing VS Code extensions"
|
|
while read -r ext; do
|
|
[[ -z "$ext" || "$ext" =~ ^# ]] && continue
|
|
echo " -> $ext"
|
|
code --install-extension "$ext" --force >/dev/null 2>&1 || \
|
|
echo " (failed: $ext)"
|
|
done < "$EXT_FILE"
|
|
fi
|
|
|
|
touch "$HOME/.first-login-done"
|
|
echo "==> [$(date)] first-login setup done"
|