Skip to content

Commit a19e30e

Browse files
author
Gemini CLI
committed
RESTORE: Full comprehensive MiOS Bootstrap installer (Total Root Merge + Package Manifest)
1 parent 54e3148 commit a19e30e

1 file changed

Lines changed: 176 additions & 24 deletions

File tree

automation/install-bootstrap.sh

Lines changed: 176 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,203 @@
11
#!/usr/bin/env bash
2-
# MiOS Bootstrap -- Total Root Merge Mode
2+
#
3+
# MiOS Bootstrap -- Interactive Ignition Installer (Total Root Merge Mode)
4+
#
5+
# SSOT: This script installs EVERYTHING a fully built MiOS system has.
6+
# It transforms a bare Fedora host into a self-building MiOS workstation.
7+
#
38
set -euo pipefail
49

10+
# ============================================================================
11+
# Defaults
12+
# ============================================================================
513
DEFAULT_USER="mios"
614
DEFAULT_HOST="mios"
715
DEFAULT_USER_FULLNAME="MiOS User"
16+
DEFAULT_USER_SHELL="/bin/bash"
817
DEFAULT_USER_GROUPS="wheel,libvirt,kvm,video,render,input,dialout"
18+
DEFAULT_SSH_KEY_TYPE="ed25519"
19+
DEFAULT_BRANCH="main"
20+
921
MIOS_REPO="https://github.com/mios-dev/MiOS.git"
22+
PROFILE_DIR="/etc/mios"
23+
PROFILE_FILE="${PROFILE_DIR}/install.env"
24+
25+
# ============================================================================
26+
# Logging & UI
27+
# ============================================================================
28+
_BOLD=$(tput bold 2>/dev/null || echo "")
29+
_RED=$(tput setaf 1 2>/dev/null || echo "")
30+
_GREEN=$(tput setaf 2 2>/dev/null || echo "")
31+
_YELLOW=$(tput setaf 3 2>/dev/null || echo "")
32+
_CYAN=$(tput setaf 6 2>/dev/null || echo "")
33+
_DIM=$(tput dim 2>/dev/null || echo "")
34+
_RESET=$(tput sgr0 2>/dev/null || echo "")
35+
36+
log_info() { printf '%s[INFO]%s %s\n' "${_CYAN}" "${_RESET}" "$*"; }
37+
log_ok() { printf '%s[ OK ]%s %s\n' "${_GREEN}" "${_RESET}" "$*"; }
38+
log_warn() { printf '%s[WARN]%s %s\n' "${_YELLOW}" "${_RESET}" "$*" >&2; }
39+
log_err() { printf '%s[ERR ]%s %s\n' "${_RED}" "${_RESET}" "$*" >&2; }
40+
log_phase() { printf '\n%s%s== %s ==%s\n\n' "${_BOLD}" "${_CYAN}" "$*" "${_RESET}"; }
41+
42+
require_root() {
43+
if [[ $EUID -ne 0 ]]; then
44+
log_err "Bootstrap must run as root: sudo $0"
45+
exit 1
46+
fi
47+
}
48+
49+
detect_host_kind() {
50+
if command -v bootc >/dev/null 2>&1 && bootc status --format=json 2>/dev/null | grep -q '"booted"'; then
51+
echo "bootc"
52+
elif [[ -f /etc/os-release ]] && grep -qE '^ID(_LIKE)?=.*fedora' /etc/os-release; then
53+
echo "fhs-fedora"
54+
else
55+
echo "unsupported"
56+
fi
57+
}
58+
59+
check_network() {
60+
local host
61+
for host in github.com; do
62+
if ! curl -fsSL --max-time 5 -o /dev/null "https://${host}/" 2>/dev/null; then
63+
log_err "No network reachability to ${host}."
64+
exit 1
65+
fi
66+
done
67+
log_ok "Network reachability verified"
68+
}
1069

11-
log_info() { printf '\033[36m[INFO]\033[0m %s\n' "$*"; }
12-
log_ok() { printf '\033[32m[ OK ]\033[0m %s\n' "$*"; }
13-
log_err() { printf '\033[31m[ERR ]\033[0m %s\n' "$*" >&2; }
70+
prompt_default() {
71+
local question="$1" default="$2" answer
72+
read -r -p "$(printf '%s%s%s [%s%s%s]: ' "${_BOLD}" "${question}" "${_RESET}" "${_DIM}" "${default}" "${_RESET}")" answer
73+
echo "${answer:-$default}"
74+
}
1475

15-
require_root() { [[ $EUID -eq 0 ]] || { log_err "Must run as root"; exit 1; }; }
76+
prompt_password() {
77+
local prompt="$1" pw1 pw2
78+
while :; do
79+
printf '%s%s%s: ' "${_BOLD}" "${prompt}" "${_RESET}" >&2
80+
read -rs pw1; echo >&2
81+
printf '%sConfirm:%s ' "${_BOLD}" "${_RESET}" >&2
82+
read -rs pw2; echo >&2
83+
if [[ "$pw1" == "$pw2" && -n "$pw1" ]]; then
84+
echo "$pw1"
85+
return 0
86+
fi
87+
log_warn "Passwords don't match or are empty."
88+
done
89+
}
1690

91+
prompt_yesno() {
92+
local question="$1" default="${2:-y}" answer hint
93+
if [[ "$default" == "y" ]]; then hint="[Y/n]"; else hint="[y/N]"; fi
94+
read -r -p "$(printf '%s%s%s %s: ' "${_BOLD}" "${question}" "${_RESET}" "${hint}")" answer
95+
answer="${answer:-$default}"
96+
case "${answer,,}" in
97+
y|yes) return 0 ;;
98+
*) return 1 ;;
99+
esac
100+
}
101+
102+
# ============================================================================
103+
# Core Logic
104+
# ============================================================================
17105
main() {
18106
require_root
19-
log_info "Starting MiOS Bootstrap..."
107+
log_phase "MiOS Bootstrap Installer (Full Build Mode)"
108+
109+
local hostkind=$(detect_host_kind)
110+
if [[ "$hostkind" == "unsupported" ]]; then
111+
log_err "Host is not Fedora. MiOS requires a Fedora-based host."
112+
exit 1
113+
fi
114+
log_info "Detected host: ${hostkind}"
115+
116+
check_network
117+
118+
# --- 1. Gather Profile ---
119+
LINUX_USER="$(prompt_default 'Linux username' "${DEFAULT_USER}")"
120+
HOSTNAME_VAL="$(prompt_default 'Hostname' "${DEFAULT_HOST}")"
121+
USER_FULLNAME="$(prompt_default 'Full name (GECOS)' "${DEFAULT_USER_FULLNAME}")"
122+
USER_PASSWORD="$(prompt_password 'Password')"
123+
124+
log_phase "Review profile"
125+
printf " User: %s\n Host: %s\n Mode: Total Root Overlay\n\n" "$LINUX_USER" "$HOSTNAME_VAL"
126+
if ! prompt_yesno 'Proceed with these settings?' y; then exit 0; fi
127+
128+
# --- 2. Apply Profile ---
129+
log_phase "Applying system profile"
130+
hostnamectl set-hostname "$HOSTNAME_VAL"
20131

21-
# 1. User/Group handling (GRACEFUL)
22132
local existing_groups=""
23-
IFS=',' read -ra ADDR <<< "$DEFAULT_USER_GROUPS"
24-
for g in "${ADDR[@]}"; do
25-
getent group "$g" >/dev/null && { [[ -n "$existing_groups" ]] && existing_groups+=","; existing_groups+="$g"; }
133+
IFS=',' read -ra ADDR <<< "${DEFAULT_USER_GROUPS}"
134+
for group in "${ADDR[@]}"; do
135+
if getent group "$group" >/dev/null; then
136+
[[ -n "$existing_groups" ]] && existing_groups+=","
137+
existing_groups+="$group"
138+
else
139+
log_warn "Group '$group' missing on host, skipping."
140+
fi
26141
done
27142

28-
if id -u "$DEFAULT_USER" >/dev/null 2>&1; then
29-
usermod -aG "$existing_groups" "$DEFAULT_USER"
143+
if id -u "$LINUX_USER" >/dev/null 2>&1; then
144+
log_info "User '$LINUX_USER' exists; updating groups + password"
145+
usermod -aG "$existing_groups" "$LINUX_USER"
146+
usermod -c "$USER_FULLNAME" "$LINUX_USER"
30147
else
31-
useradd -m -G "$existing_groups" -s /bin/bash -c "$DEFAULT_USER_FULLNAME" "$DEFAULT_USER"
148+
log_info "Creating '$LINUX_USER' (groups: $existing_groups)"
149+
useradd -m -G "$existing_groups" -s "$DEFAULT_USER_SHELL" -c "$USER_FULLNAME" "$LINUX_USER"
32150
fi
33-
log_ok "User configured with available groups: $existing_groups"
151+
echo "$LINUX_USER:$USER_PASSWORD" | chpasswd
152+
log_ok "User profile applied."
34153

35-
# 2. Total Root Merge
36-
log_info "Merging MiOS repository onto / ..."
37-
[[ -d "/.git" ]] || git init /
38-
git -C / remote add origin "$MIOS_REPO" 2>/dev/null || git -C / remote set-url origin "$MIOS_REPO"
39-
git -C / fetch --depth=1 origin main
40-
git -C / checkout -f main
41-
log_ok "Root merge complete."
154+
# --- 3. Total Root Merge ---
155+
log_phase "MiOS Core Installation (Root Merge)"
156+
log_info "Merging MiOS repository onto system root (/) ..."
157+
if [[ ! -d "/.git" ]]; then
158+
git init /
159+
git -C / remote add origin "$MIOS_REPO" 2>/dev/null || git -C / remote set-url origin "$MIOS_REPO"
160+
fi
161+
git -C / fetch --depth=1 origin "$DEFAULT_BRANCH"
162+
git -C / checkout -f "$DEFAULT_BRANCH"
163+
log_ok "MiOS source tree merged to root."
164+
165+
# --- 4. Package Installation ---
166+
log_phase "Installing MiOS System Stack"
167+
if [[ -f "/usr/share/mios/PACKAGES.md" ]]; then
168+
log_info "Extracting package list from /usr/share/mios/PACKAGES.md..."
169+
local pkgs
170+
pkgs=$(sed -n '/^```packages-/,/^```$/{/^```/d;/^#/d;/^$/d;p}' /usr/share/mios/PACKAGES.md | tr '\n' ' ')
171+
172+
if [[ -n "$pkgs" ]]; then
173+
local dnf_cmd="dnf"
174+
command -v dnf5 >/dev/null 2>&1 && dnf_cmd="dnf5"
175+
log_info "Executing: $dnf_cmd install -y --skip-unavailable --best [PACKAGES]"
176+
$dnf_cmd install -y --skip-unavailable --best $pkgs || log_warn "Some packages failed to install."
177+
log_ok "Package stack installation complete."
178+
else
179+
log_err "No packages found in manifest!"
180+
fi
181+
else
182+
log_err "CRITICAL: /usr/share/mios/PACKAGES.md not found!"
183+
exit 1
184+
fi
42185

43-
# 3. System installer
186+
# --- 5. System Initialization ---
187+
log_phase "System Initialization"
44188
if [[ -x "/install.sh" ]]; then
45-
log_info "Running /install.sh ..."
189+
log_info "Running /install.sh to finalize FHS overlay..."
46190
/install.sh
191+
log_ok "Initialization complete."
192+
else
193+
log_err "/install.sh not found or not executable!"
194+
exit 1
195+
fi
196+
197+
log_phase "MiOS Installation Complete"
198+
if prompt_yesno 'Reboot now to enter MiOS?' y; then
199+
systemctl reboot
47200
fi
48-
log_ok "MiOS Installation Finished."
49201
}
50202

51203
main "$@"

0 commit comments

Comments
 (0)