Compare commits
113
Commits
No files matched your search
@@ -1 +1,2 @@
|
|||||||
release/**
|
release/**
|
||||||
|
vm-saves/**
|
||||||
@@ -1,21 +1,19 @@
|
|||||||
# Omarchy ISO
|
# Omarchy ISO
|
||||||
|
|
||||||
The Omarchy ISO streamlines [the installation of Omarchy](https://learn.omacom.io/2/the-omarchy-manual/50/getting-started). It includes the [Omarchy Configurator](https://github.com/omacom-io/omarchy-configurator) as a front-end to archinstall and automatically launches the [Omarchy Installer](https://github.com/basecamp/omarchy) after base arch has been setup.
|
The Omarchy ISO streamlines [the installation of Omarchy](https://learn.omacom.io/2/the-omarchy-manual/50/getting-started). It includes the Omarchy Configurator as a front-end to archinstall and automatically launches the [Omarchy Installer](https://github.com/basecamp/omarchy) after base arch has been setup.
|
||||||
|
|
||||||
## Downloading the latest ISO
|
## Downloading the latest ISO
|
||||||
|
|
||||||
[Download Omarchy Online ISO](https://iso.omarchy.org/omarchy-online.iso) (1.4GB)
|
See the ISO link on [omarchy.org](https://omarchy.org).
|
||||||
|
|
||||||
## Creating the ISO
|
## Creating the ISO
|
||||||
|
|
||||||
Run `./bin/omarchy-iso-make` and the output goes into `./release`.
|
Run `./bin/omarchy-iso-make` and the output goes into `./release`. You can build from your local $OMARCHY_PATH for testing by using `--local-source` or from a checkout of the dev branch (instead of master) by using `--dev`.
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
You can customize the repositories used during the build process by passing in variables:
|
You can customize the repositories used during the build process by passing in variables:
|
||||||
|
|
||||||
- `OMARCHY_CONFIGURATOR_REPO` - GitHub repository for the configurator (default: `omacom-io/omarchy-configurator`)
|
|
||||||
- `OMARCHY_CONFIGURATOR_REF` - Git ref (branch/tag) for the configurator (default: `master`)
|
|
||||||
- `OMARCHY_INSTALLER_REPO` - GitHub repository for the installer (default: `basecamp/omarchy`)
|
- `OMARCHY_INSTALLER_REPO` - GitHub repository for the installer (default: `basecamp/omarchy`)
|
||||||
- `OMARCHY_INSTALLER_REF` - Git ref (branch/tag) for the installer (default: `master`)
|
- `OMARCHY_INSTALLER_REF` - Git ref (branch/tag) for the installer (default: `master`)
|
||||||
|
|
||||||
@@ -38,4 +36,4 @@ Run `./bin/omarchy-iso-upload [release/omarchy.iso]`. This requires you've confi
|
|||||||
|
|
||||||
## Full release of the ISO
|
## Full release of the ISO
|
||||||
|
|
||||||
Run `./bin/omarchy-iso-make` to create, test, sign, and upload the ISO in one flow.
|
Run `./bin/omarchy-iso-release VERSION` to create, test, sign, and upload the ISO in one flow. Add `--rc` to release an RC build instead.
|
||||||
+1
-1
Submodule archiso updated: 69047bdc03...424e78130d.
+18
-8
@@ -2,18 +2,27 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
ISO="$1"
|
||||||
|
REUSE="$2"
|
||||||
|
|
||||||
if [ $# -eq 0 ]; then
|
if [ $# -eq 0 ]; then
|
||||||
|
ISO=$(ls -t release/*.iso 2>/dev/null | gum choose --header "Select ISO to boot")
|
||||||
|
if gum confirm --default=false "Reuse existing disk?"; then
|
||||||
|
REUSE="reuse"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$ISO" ]; then
|
||||||
echo "Usage: omarchy-iso-boot [release/omarchy.iso] [reuse]"
|
echo "Usage: omarchy-iso-boot [release/omarchy.iso] [reuse]"
|
||||||
|
echo " SSH available at: ssh -p 2222 root@localhost (after installing openssh)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! pacman -Q qemu-full >/dev/null || ! pacman -Q edk2-ovmf >/dev/null; then
|
omarchy-pkg-add qemu-full edk2-ovmf
|
||||||
sudo pacman -S --noconfirm --needed --quiet qemu-full edk2-ovmf
|
|
||||||
fi
|
|
||||||
|
|
||||||
DISK="/tmp/omarchy-iso-boot.qcow2"
|
DISK="/tmp/omarchy-iso-boot.qcow2"
|
||||||
if [[ ! -f $DISK || $2 != "reuse" ]]; then
|
if [[ ! -f $DISK || $REUSE != "reuse" ]]; then
|
||||||
qemu-img create -f qcow2 "$DISK" 20G
|
qemu-img create -f qcow2 "$DISK" 40G
|
||||||
cp /usr/share/edk2/x64/OVMF_VARS.4m.fd /tmp/OVMF_VARS.4m.fd
|
cp /usr/share/edk2/x64/OVMF_VARS.4m.fd /tmp/OVMF_VARS.4m.fd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -26,10 +35,11 @@ qemu-system-x86_64 \
|
|||||||
-drive if=pflash,format=raw,file=/tmp/OVMF_VARS.4m.fd \
|
-drive if=pflash,format=raw,file=/tmp/OVMF_VARS.4m.fd \
|
||||||
-drive file="$DISK",format=qcow2,if=none,id=drive0 \
|
-drive file="$DISK",format=qcow2,if=none,id=drive0 \
|
||||||
-device virtio-blk-pci,drive=drive0,bootindex=1 \
|
-device virtio-blk-pci,drive=drive0,bootindex=1 \
|
||||||
-drive file="$1",media=cdrom,if=none,format=raw,id=cdrom0 \
|
-drive file="$ISO",media=cdrom,if=none,format=raw,id=cdrom0 \
|
||||||
-device ide-cd,drive=cdrom0,bootindex=2 \
|
-device ide-cd,drive=cdrom0,bootindex=2 \
|
||||||
-device virtio-vga-gl \
|
-device virtio-vga-gl \
|
||||||
-display gtk,gl=on \
|
-display gtk,gl=on \
|
||||||
-usb -device usb-tablet \
|
-usb -device usb-tablet \
|
||||||
-netdev user,id=net0 \
|
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
|
||||||
-device virtio-net-pci,netdev=net0
|
-device virtio-net-pci,netdev=net0 \
|
||||||
|
-boot menu=on
|
||||||
+30
-21
@@ -4,18 +4,9 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
BUILD_MODE="offline"
|
|
||||||
NO_CACHE=""
|
NO_CACHE=""
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
--online)
|
|
||||||
BUILD_MODE="online"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--offline)
|
|
||||||
BUILD_MODE="offline"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--no-cache)
|
--no-cache)
|
||||||
NO_CACHE=1
|
NO_CACHE=1
|
||||||
shift
|
shift
|
||||||
@@ -24,14 +15,32 @@ while [[ $# -gt 0 ]]; do
|
|||||||
NO_BOOT_OFFER=1
|
NO_BOOT_OFFER=1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--local-source)
|
||||||
|
LOCAL_SOURCE=1
|
||||||
|
OMARCHY_MIRROR=edge
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--dev)
|
||||||
|
OMARCHY_INSTALLER_REF=dev
|
||||||
|
OMARCHY_MIRROR=edge
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--rc)
|
||||||
|
OMARCHY_MIRROR=rc
|
||||||
|
OMARCHY_INSTALLER_REF=rc
|
||||||
|
shift
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option: $1"
|
echo "Unknown option: $1"
|
||||||
echo "Usage: $0 [--online|--offline] [--no-cache] [--no-boot-offer]"
|
echo "Usage: $0 [--no-cache] [--no-boot-offer] [--local-source] [--dev] [--rc]"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Clear out old packages
|
||||||
|
sudo rm -rf /var/cache/pacman/pkg/*
|
||||||
|
|
||||||
# Ensure we have the submodule checked out
|
# Ensure we have the submodule checked out
|
||||||
git submodule update --init --recursive --jobs=8
|
git submodule update --init --recursive --jobs=8
|
||||||
|
|
||||||
@@ -41,22 +50,18 @@ BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
|||||||
BUILD_RELEASE_PATH="$BUILD_ROOT/release"
|
BUILD_RELEASE_PATH="$BUILD_ROOT/release"
|
||||||
mkdir -p "$BUILD_RELEASE_PATH"
|
mkdir -p "$BUILD_RELEASE_PATH"
|
||||||
|
|
||||||
OMARCHY_CONFIGURATOR_REPO="${OMARCHY_CONFIGURATOR_REPO:-omacom-io/omarchy-configurator}"
|
|
||||||
OMARCHY_CONFIGURATOR_REF="${OMARCHY_CONFIGURATOR_REF:-master}"
|
|
||||||
|
|
||||||
OMARCHY_INSTALLER_REPO="${OMARCHY_INSTALLER_REPO:-basecamp/omarchy}"
|
OMARCHY_INSTALLER_REPO="${OMARCHY_INSTALLER_REPO:-basecamp/omarchy}"
|
||||||
OMARCHY_INSTALLER_REF="${OMARCHY_INSTALLER_REF:-master}"
|
OMARCHY_INSTALLER_REF="${OMARCHY_INSTALLER_REF:-master}"
|
||||||
OMARCHY_INSTALLER_URL="${OMARCHY_INSTALLER_URL:-https://omarchy.org/install}"
|
OMARCHY_MIRROR="${OMARCHY_MIRROR:-stable}"
|
||||||
|
|
||||||
DOCKER_ARGS=(
|
DOCKER_ARGS=(
|
||||||
--rm
|
--rm
|
||||||
--privileged
|
--privileged
|
||||||
-e "OMARCHY_CONFIGURATOR_REPO=$OMARCHY_CONFIGURATOR_REPO"
|
|
||||||
-e "OMARCHY_CONFIGURATOR_REF=$OMARCHY_CONFIGURATOR_REF"
|
|
||||||
-e "OMARCHY_INSTALLER_REPO=$OMARCHY_INSTALLER_REPO"
|
-e "OMARCHY_INSTALLER_REPO=$OMARCHY_INSTALLER_REPO"
|
||||||
-e "OMARCHY_INSTALLER_REF=$OMARCHY_INSTALLER_REF"
|
-e "OMARCHY_INSTALLER_REF=$OMARCHY_INSTALLER_REF"
|
||||||
-e "OMARCHY_INSTALLER_URL=$OMARCHY_INSTALLER_URL"
|
-e "OMARCHY_MIRROR=$OMARCHY_MIRROR"
|
||||||
-e "OMARCHY_BUILD_MODE=$BUILD_MODE"
|
-e "HOST_UID=$(id -u)"
|
||||||
|
-e "HOST_GID=$(id -g)"
|
||||||
-v "$BUILD_RELEASE_PATH/:/out/"
|
-v "$BUILD_RELEASE_PATH/:/out/"
|
||||||
-v "$BUILD_ROOT/$BUILD_SCRIPT:/$BUILD_SCRIPT:ro"
|
-v "$BUILD_ROOT/$BUILD_SCRIPT:/$BUILD_SCRIPT:ro"
|
||||||
-v "$BUILD_ROOT/archiso:/archiso:ro"
|
-v "$BUILD_ROOT/archiso:/archiso:ro"
|
||||||
@@ -64,14 +69,18 @@ DOCKER_ARGS=(
|
|||||||
-v "$BUILD_ROOT/configs:/configs:ro"
|
-v "$BUILD_ROOT/configs:/configs:ro"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Use local source of Omarchy from $OMARCHY_PATH instead of git checkout
|
||||||
|
if [[ -n "${LOCAL_SOURCE-}" ]]; then
|
||||||
|
DOCKER_ARGS+=(-v "$OMARCHY_PATH:/omarchy:ro")
|
||||||
|
fi
|
||||||
|
|
||||||
# Use local pacman cache if you already have one on host to speed up repeat runs
|
# Use local pacman cache if you already have one on host to speed up repeat runs
|
||||||
if [ -d "/var/cache/pacman/pkg" ]; then
|
if [ -d "/var/cache/pacman/pkg" ]; then
|
||||||
DOCKER_ARGS+=(-v "/var/cache/pacman/pkg:/var/cache/pacman/pkg")
|
DOCKER_ARGS+=(-v "/var/cache/pacman/pkg:/var/cache/pacman/pkg")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Mount the build cache directory where packages are downloaded for the offline repo
|
# Mount the build cache directory where packages are downloaded
|
||||||
# Only applicable for offline builds and when --no-cache is not specified
|
if [[ -z "$NO_CACHE" ]]; then
|
||||||
if [[ "$BUILD_MODE" == "offline" && -z "$NO_CACHE" ]]; then
|
|
||||||
# using a dated dir on the host to refresh daily if building multiple times
|
# using a dated dir on the host to refresh daily if building multiple times
|
||||||
BUILD_DATE=$(date +%Y-%m-%d)
|
BUILD_DATE=$(date +%Y-%m-%d)
|
||||||
OFFLINE_REPO_BUILD_CACHE_DIR="$HOME/.cache/omarchy/iso_${BUILD_DATE}/airootfs/var/cache/omarchy"
|
OFFLINE_REPO_BUILD_CACHE_DIR="$HOME/.cache/omarchy/iso_${BUILD_DATE}/airootfs/var/cache/omarchy"
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
OMARCHY_INSTALLER_REF=dev \
|
|
||||||
OMARCHY_INSTALL_URL=https://omarchy.org/install-dev \
|
|
||||||
omarchy-iso-make
|
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
omarchy-pkg-add rclone
|
||||||
|
mkdir -p ~/.config/rclone
|
||||||
|
|
||||||
|
access_key=$(op read "op://Shared/Cloudflare Buckets/iso.omarchy.org/access_key_id" --account Omarchy)
|
||||||
|
secret_access_key=$(op read "op://Shared/Cloudflare Buckets/iso.omarchy.org/secret_access_key" --account Omarchy)
|
||||||
|
endpoint=$(op read "op://Shared/Cloudflare Buckets/iso.omarchy.org/endpoint" --account Omarchy)
|
||||||
|
|
||||||
|
cat > ~/.config/rclone/rclone.conf << EOF
|
||||||
|
[Omarchy]
|
||||||
|
type = s3
|
||||||
|
provider = Cloudflare
|
||||||
|
access_key_id = $access_key
|
||||||
|
secret_access_key = $secret_access_key
|
||||||
|
endpoint = $endpoint
|
||||||
|
EOF
|
||||||
+51
-19
@@ -1,30 +1,62 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
MAKE_ARGS=()
|
||||||
|
INSTALLER_REF=master
|
||||||
|
RELEASE_SUFFIX=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--no-make)
|
||||||
|
MAKE_ARGS+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--rc)
|
||||||
|
MAKE_ARGS+=("$1")
|
||||||
|
INSTALLER_REF=rc
|
||||||
|
RELEASE_SUFFIX="-rc"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
echo "Usage: omarchy-iso-release [--no-make] [--rc] [version]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ -n "${BUILD_VERSION-}" ]]; then
|
||||||
|
echo "Usage: omarchy-iso-release [--no-make] [--rc] [version]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
BUILD_VERSION="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "${BUILD_VERSION-}" ]]; then
|
||||||
|
echo "Usage: omarchy-iso-release [--no-make] [--rc] [version]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
||||||
BUILD_RELEASE_PATH="$BUILD_ROOT/release"
|
BUILD_RELEASE_PATH="$BUILD_ROOT/release"
|
||||||
|
|
||||||
# Make ISOs
|
# Make ISOs
|
||||||
if [[ $1 != "--no-make" ]]; then
|
if [[ ! " ${MAKE_ARGS[*]} " =~ " --no-make " ]]; then
|
||||||
echo -e "\e[32mMaking master ISO\e[0m"
|
echo -e "\e[32mMaking $INSTALLER_REF ISO\e[0m"
|
||||||
OMARCHY_INSTALLER_REF=master omarchy-iso-make --no-boot-offer
|
omarchy-iso-make --no-cache --no-boot-offer "${MAKE_ARGS[@]}"
|
||||||
echo -e "\e[32m\nMaking dev ISO\e[0m"
|
|
||||||
OMARCHY_INSTALLER_REF=dev OMARCHY_INSTALL_URL=https://omarchy.org/install-dev omarchy-iso-make --no-boot-offer
|
|
||||||
else
|
else
|
||||||
echo -e "\e[31mSkipping remaking ISOs\e[0m"
|
echo -e "\e[31mSkipping remaking ISOs\e[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Sign and upload master ISO
|
# Sign and upload ISO
|
||||||
latest_master_iso=$(\ls -t "$BUILD_RELEASE_PATH"/*x86_64-master.iso | head -n1)
|
latest_iso=$(\ls -t "$BUILD_RELEASE_PATH"/*x86_64-"$INSTALLER_REF".iso | head -n1)
|
||||||
release_master_iso="$BUILD_RELEASE_PATH/omarchy-online.iso"
|
release_iso="$BUILD_RELEASE_PATH/omarchy-$BUILD_VERSION$RELEASE_SUFFIX.iso"
|
||||||
cp "$latest_master_iso" "$release_master_iso"
|
cp "$latest_iso" "$release_iso"
|
||||||
echo -e "\e[32mSigning master ISO\e[0m"
|
|
||||||
omarchy-iso-sign "$release_master_iso"
|
|
||||||
omarchy-iso-upload "$release_master_iso"
|
|
||||||
|
|
||||||
# Sign and upload dev ISO
|
echo -e "\e[32mSigning $INSTALLER_REF ISO\e[0m"
|
||||||
latest_dev_iso=$(\ls -t "$BUILD_RELEASE_PATH"/*x86_64-dev.iso | head -n1)
|
omarchy-iso-sign "$release_iso"
|
||||||
release_dev_iso="$BUILD_RELEASE_PATH/omarchy-online-dev.iso"
|
|
||||||
cp "$latest_dev_iso" "$release_dev_iso"
|
iso_sha=$(sha256sum "$release_iso")
|
||||||
echo -e "\e[32mSigning dev ISO\e[0m"
|
echo -e "\e[32mSHA256 for $INSTALLER_REF ISO: $iso_sha\e[0m"
|
||||||
omarchy-iso-sign "$release_dev_iso"
|
|
||||||
omarchy-iso-upload "$release_dev_iso"
|
omarchy-iso-upload "$release_iso"
|
||||||
@@ -6,8 +6,8 @@ if [ $# -eq 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! pacman -Q gnupg >/dev/null; then
|
if ! pacman -Q gnupg >/dev/null; then
|
||||||
sudo pacman -s --noconfirm --needed --quiet gnupg
|
sudo pacman -S --noconfirm --needed --quiet gnupg
|
||||||
echo "you'll need to generate a new key with: gpg --full-generate-key"
|
echo "You'll need to import key with: gpg --import path/to/signing-key.asc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
gnupg_user_key=$(gpg --list-secret-keys --keyid-format=long | awk '/^[[:space:]]/{print $1; exit}')
|
gnupg_user_key=$(gpg --list-secret-keys --keyid-format=long | awk '/^[[:space:]]/{print $1; exit}')
|
||||||
|
|||||||
@@ -6,9 +6,12 @@ if [ $# -eq 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f ~/.config/rclone/rclone.conf ]]; then
|
if [[ ! -f ~/.config/rclone/rclone.conf ]]; then
|
||||||
echo "You must first configure rclone with the R2 credentials: rclone config"
|
echo "You must first configure rclone with the R2 credentials: omarchy-iso-rclone-config"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rclone copy $1 Omarchy:omarchy/ -P
|
rclone copy $1 Omarchy:omarchy/ -P
|
||||||
rclone copy $1.sig Omarchy:omarchy/ -P
|
|
||||||
|
if [[ -f $1.sig ]]; then
|
||||||
|
rclone copy $1.sig Omarchy:omarchy/ -P
|
||||||
|
fi
|
||||||
Executable
+111
@@ -0,0 +1,111 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
VM_DIR="$(dirname "$SCRIPT_DIR")/vm-saves"
|
||||||
|
TMP_DISK="/tmp/omarchy-iso-boot.qcow2"
|
||||||
|
TMP_OVMF="/tmp/OVMF_VARS.4m.fd"
|
||||||
|
|
||||||
|
mkdir -p "$VM_DIR"
|
||||||
|
|
||||||
|
save_vm() {
|
||||||
|
local name="$1"
|
||||||
|
|
||||||
|
if [[ -z "$name" ]]; then
|
||||||
|
name=$(gum input --placeholder "Enter VM snapshot name")
|
||||||
|
[[ -z "$name" ]] && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$TMP_DISK" || ! -f "$TMP_OVMF" ]]; then
|
||||||
|
echo "Error: No active VM found in /tmp"
|
||||||
|
echo "Boot a VM first with: omarchy-iso-boot [iso]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local vm_path="$VM_DIR/$name"
|
||||||
|
|
||||||
|
if [[ -d "$vm_path" ]]; then
|
||||||
|
if ! gum confirm "VM '$name' exists. Overwrite?"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$vm_path"
|
||||||
|
|
||||||
|
echo "Saving VM snapshot '$name'..."
|
||||||
|
cp "$TMP_DISK" "$vm_path/omarchy-iso-boot.qcow2"
|
||||||
|
cp "$TMP_OVMF" "$vm_path/OVMF_VARS.4m.fd"
|
||||||
|
|
||||||
|
gum style --foreground 212 "✓ Saved to $vm_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
list_vms() {
|
||||||
|
if [[ ! -d "$VM_DIR" ]] || [[ -z "$(ls -A "$VM_DIR")" ]]; then
|
||||||
|
echo "No VM snapshots found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Available VM snapshots:"
|
||||||
|
for vm in "$VM_DIR"/*; do
|
||||||
|
[[ -d "$vm" ]] && echo " • $(basename "$vm")"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_vm() {
|
||||||
|
local name="$1"
|
||||||
|
|
||||||
|
if [[ -z "$(ls -A "$VM_DIR" 2>/dev/null)" ]]; then
|
||||||
|
echo "No VM snapshots available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$name" ]]; then
|
||||||
|
name=$(ls -1 "$VM_DIR" | gum choose --header "Select VM to boot:")
|
||||||
|
[[ -z "$name" ]] && exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local vm_path="$VM_DIR/$name"
|
||||||
|
|
||||||
|
if [[ ! -d "$vm_path" ]]; then
|
||||||
|
echo "Error: VM '$name' not found"
|
||||||
|
list_vms
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$TMP_DISK" ]] && ! gum confirm "Override existing /tmp VM?"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copying VM '$name' to /tmp..."
|
||||||
|
cp "$vm_path/omarchy-iso-boot.qcow2" "$TMP_DISK"
|
||||||
|
cp "$vm_path/OVMF_VARS.4m.fd" "$TMP_OVMF"
|
||||||
|
|
||||||
|
gum style --foreground 212 "✓ VM ready. Booting..."
|
||||||
|
|
||||||
|
exec omarchy-iso-boot /dev/null reuse
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
save)
|
||||||
|
save_vm "$2"
|
||||||
|
;;
|
||||||
|
boot)
|
||||||
|
boot_vm "$2"
|
||||||
|
;;
|
||||||
|
list)
|
||||||
|
list_vms
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
gum style --border rounded --padding "0 1" --border-foreground 212 \
|
||||||
|
"$(gum style --bold 'omarchy-vm') - VM snapshot manager" \
|
||||||
|
"" \
|
||||||
|
"$(gum style --foreground 245 'Commands:')" \
|
||||||
|
" save [name] Save current VM from /tmp" \
|
||||||
|
" boot [name] Boot saved VM (interactive if no name)" \
|
||||||
|
" list List available VMs" \
|
||||||
|
"" \
|
||||||
|
"$(gum style --foreground 245 'Current VMs:')"
|
||||||
|
list_vms 2>/dev/null || echo " None"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
alsa-firmware
|
||||||
|
amd-ucode
|
||||||
|
base
|
||||||
|
base-devel
|
||||||
|
efibootmgr
|
||||||
|
intel-ucode
|
||||||
|
linux-firmware
|
||||||
|
linux
|
||||||
|
limine
|
||||||
|
omarchy-keyring
|
||||||
|
openssh
|
||||||
|
pipewire
|
||||||
|
snapper
|
||||||
|
sof-firmware
|
||||||
+64
-118
@@ -2,98 +2,43 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Build mode: offline (default) or online │ │
|
# Note that these are packages installed to the Arch container used to build the ISO.
|
||||||
OMARCHY_BUILD_MODE="${OMARCHY_BUILD_MODE:-offline}"
|
|
||||||
|
|
||||||
# Note that these are packages installed to the Arch container
|
|
||||||
# used to build the ISO.
|
|
||||||
pacman-key --init
|
pacman-key --init
|
||||||
pacman --noconfirm -Sy archlinux-keyring
|
pacman --noconfirm -Sy archlinux-keyring
|
||||||
pacman --noconfirm -Sy archiso git python-pip sudo base-devel jq
|
pacman --noconfirm -Sy archiso git sudo base-devel jq grub
|
||||||
|
|
||||||
|
# Install omarchy-keyring for package verification during build
|
||||||
|
# The [omarchy] repo is defined in /configs/pacman-online.conf with SigLevel = Optional TrustAll
|
||||||
|
pacman --config /configs/pacman-online-${OMARCHY_MIRROR}.conf --noconfirm -Sy omarchy-keyring
|
||||||
|
pacman-key --populate omarchy
|
||||||
|
|
||||||
|
# Setup build locations
|
||||||
build_cache_dir="/var/cache"
|
build_cache_dir="/var/cache"
|
||||||
offline_mirror_dir="$build_cache_dir/airootfs/var/cache/omarchy/mirror/offline"
|
offline_mirror_dir="$build_cache_dir/airootfs/var/cache/omarchy/mirror/offline"
|
||||||
offline_ruby_dir="$build_cache_dir/airootfs/var/cache/omarchy/ruby"
|
|
||||||
|
|
||||||
# We need to fiddle with pip settings
|
|
||||||
# in order to install to the correct place
|
|
||||||
# as well as ignore some errors to make this less verbose
|
|
||||||
export PIP_ROOT="$build_cache_dir/airootfs/"
|
|
||||||
export PIP_ROOT_USER_ACTION="ignore"
|
|
||||||
export PIP_NO_WARN_SCRIPT_LOCATION=1
|
|
||||||
export PIP_BREAK_SYSTEM_PACKAGES=1
|
|
||||||
|
|
||||||
# These packages will be installed **into** the ISO, and
|
|
||||||
# won't be available to either archinstall or omarchy installer.
|
|
||||||
python_packages=(
|
|
||||||
terminaltexteffects
|
|
||||||
)
|
|
||||||
arch_packages=(
|
|
||||||
git
|
|
||||||
gum
|
|
||||||
jq
|
|
||||||
openssl
|
|
||||||
plymouth
|
|
||||||
tzupdate # This is technically an AUR package
|
|
||||||
)
|
|
||||||
|
|
||||||
prepare_offline_mirror() {
|
|
||||||
# Certain packages in omarchy.packages are AUR packages.
|
|
||||||
# These needs to be pre-built and placed in https://pkgs.omarchy.org/$arch
|
|
||||||
echo "Reading and combining packages from all package files..."
|
|
||||||
|
|
||||||
# Combine all packages into one array
|
|
||||||
# Start with base ISO packages (including our arch_packages already appended)
|
|
||||||
all_packages=($(cat "$build_cache_dir/packages.x86_64"))
|
|
||||||
|
|
||||||
# Add packages from the omarchy installer's unified package list
|
|
||||||
all_packages+=($(grep -v '^#' "$build_cache_dir/airootfs/root/omarchy/install/omarchy-base.packages" | grep -v '^$'))
|
|
||||||
all_packages+=($(grep -v '^#' "$build_cache_dir/airootfs/root/omarchy/install/omarchy-other.packages" | grep -v '^$'))
|
|
||||||
|
|
||||||
# Add archinstall needed packages
|
|
||||||
all_packages+=($(grep -v '^#' /builder/packages/archinstall.packages | grep -v '^$'))
|
|
||||||
|
|
||||||
if [ ${#all_packages[@]} -gt 0 ]; then
|
|
||||||
mkdir -p /tmp/offlinedb
|
|
||||||
|
|
||||||
# Download all the packages to the offline mirror inside the ISO
|
|
||||||
echo "Downloading all packages (including AUR) to offline mirror: ${all_packages[@]}"
|
|
||||||
pacman --config /configs/pacman-online.conf \
|
|
||||||
--noconfirm -Syw "${all_packages[@]}" \
|
|
||||||
--cachedir $offline_mirror_dir/ \
|
|
||||||
--dbpath /tmp/offlinedb
|
|
||||||
|
|
||||||
repo-add --new "$offline_mirror_dir/offline.db.tar.gz" "$offline_mirror_dir/"*.pkg.tar.zst
|
|
||||||
|
|
||||||
rm "$build_cache_dir/airootfs/etc/pacman.d/hooks/uncomment-mirrors.hook"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
disable_reflector() {
|
|
||||||
# Avoid using reflector for mirror identification as we are relying on the global CDN
|
|
||||||
rm "$build_cache_dir/airootfs/etc/systemd/system/multi-user.target.wants/reflector.service"
|
|
||||||
rm -rf "$build_cache_dir/airootfs/etc/systemd/system/reflector.service.d"
|
|
||||||
rm -rf "$build_cache_dir/airootfs/etc/xdg/reflector"
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Build process start
|
|
||||||
#######################
|
|
||||||
|
|
||||||
mkdir -p $build_cache_dir/
|
mkdir -p $build_cache_dir/
|
||||||
mkdir -p $offline_mirror_dir/
|
mkdir -p $offline_mirror_dir/
|
||||||
mkdir -p $offline_ruby_dir/
|
|
||||||
|
|
||||||
# We base our ISO on the official arch ISO (releng) config
|
# We base our ISO on the official arch ISO (releng) config
|
||||||
cp -r /archiso/configs/releng/* $build_cache_dir/
|
cp -r /archiso/configs/releng/* $build_cache_dir/
|
||||||
rm "$build_cache_dir/airootfs/etc/motd"
|
rm "$build_cache_dir/airootfs/etc/motd"
|
||||||
disable_reflector
|
|
||||||
|
# Avoid using reflector for mirror identification as we are relying on the global CDN
|
||||||
|
rm -rf "$build_cache_dir/airootfs/etc/systemd/system/multi-user.target.wants/reflector.service"
|
||||||
|
rm -rf "$build_cache_dir/airootfs/etc/systemd/system/reflector.service.d"
|
||||||
|
rm -rf "$build_cache_dir/airootfs/etc/xdg/reflector"
|
||||||
|
|
||||||
# Bring in our configs
|
# Bring in our configs
|
||||||
cp -r /configs/* $build_cache_dir/
|
cp -r /configs/* $build_cache_dir/
|
||||||
|
|
||||||
# Clone Omarchy itself
|
# Persist OMARCHY_MIRROR so it's available at install time
|
||||||
git clone -b $OMARCHY_INSTALLER_REF https://github.com/$OMARCHY_INSTALLER_REPO.git "$build_cache_dir/airootfs/root/omarchy"
|
echo "$OMARCHY_MIRROR" > "$build_cache_dir/airootfs/root/omarchy_mirror"
|
||||||
|
|
||||||
|
# Setup Omarchy itself
|
||||||
|
if [[ -d /omarchy ]]; then
|
||||||
|
cp -rp /omarchy "$build_cache_dir/airootfs/root/omarchy"
|
||||||
|
else
|
||||||
|
git clone -b $OMARCHY_INSTALLER_REF https://github.com/$OMARCHY_INSTALLER_REPO.git "$build_cache_dir/airootfs/root/omarchy"
|
||||||
|
fi
|
||||||
|
|
||||||
# Make log uploader available in the ISO too
|
# Make log uploader available in the ISO too
|
||||||
mkdir -p "$build_cache_dir/airootfs/usr/local/bin/"
|
mkdir -p "$build_cache_dir/airootfs/usr/local/bin/"
|
||||||
@@ -103,55 +48,56 @@ cp "$build_cache_dir/airootfs/root/omarchy/bin/omarchy-upload-log" "$build_cache
|
|||||||
mkdir -p "$build_cache_dir/airootfs/usr/share/plymouth/themes/omarchy"
|
mkdir -p "$build_cache_dir/airootfs/usr/share/plymouth/themes/omarchy"
|
||||||
cp -r "$build_cache_dir/airootfs/root/omarchy/default/plymouth/"* "$build_cache_dir/airootfs/usr/share/plymouth/themes/omarchy/"
|
cp -r "$build_cache_dir/airootfs/root/omarchy/default/plymouth/"* "$build_cache_dir/airootfs/usr/share/plymouth/themes/omarchy/"
|
||||||
|
|
||||||
# Download the configurator
|
# Download and verify Node.js binary for offline installation
|
||||||
mkdir -p "$build_cache_dir/airootfs/root"
|
NODE_DIST_URL="https://nodejs.org/dist/latest"
|
||||||
curl -fsSL -o "$build_cache_dir/airootfs/root/configurator" \
|
|
||||||
"https://raw.githubusercontent.com/$OMARCHY_CONFIGURATOR_REPO/$OMARCHY_CONFIGURATOR_REF/configurator"
|
|
||||||
|
|
||||||
if [ "$OMARCHY_BUILD_MODE" = "online" ]; then
|
# Get checksums and parse filename and SHA
|
||||||
echo "$OMARCHY_INSTALLER_REPO" >$build_cache_dir/airootfs/root/omarchy_installer_repo.txt
|
NODE_SHASUMS=$(curl -fsSL "$NODE_DIST_URL/SHASUMS256.txt")
|
||||||
echo "$OMARCHY_INSTALLER_REF" >$build_cache_dir/airootfs/root/omarchy_installer_ref.txt
|
NODE_FILENAME=$(echo "$NODE_SHASUMS" | grep "linux-x64.tar.gz" | awk '{print $2}')
|
||||||
echo "$OMARCHY_INSTALLER_URL" >$build_cache_dir/airootfs/root/omarchy_installer_url.txt
|
NODE_SHA=$(echo "$NODE_SHASUMS" | grep "linux-x64.tar.gz" | awk '{print $1}')
|
||||||
echo "online" >$build_cache_dir/airootfs/root/omarchy_install_mode.txt
|
|
||||||
else
|
# Download the tarball
|
||||||
echo "offline" >$build_cache_dir/airootfs/root/omarchy_install_mode.txt
|
curl -fsSL "$NODE_DIST_URL/$NODE_FILENAME" -o "/tmp/$NODE_FILENAME"
|
||||||
fi
|
|
||||||
|
# Verify SHA256 checksum
|
||||||
|
echo "$NODE_SHA /tmp/$NODE_FILENAME" | sha256sum -c - || {
|
||||||
|
echo "ERROR: Node.js checksum verification failed!"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy to ISO
|
||||||
|
mkdir -p "$build_cache_dir/airootfs/opt/packages/"
|
||||||
|
cp "/tmp/$NODE_FILENAME" "$build_cache_dir/airootfs/opt/packages/"
|
||||||
|
|
||||||
# Add our additional packages to packages.x86_64
|
# Add our additional packages to packages.x86_64
|
||||||
|
arch_packages=(linux-t2 git gum jq openssl plymouth tzupdate omarchy-keyring)
|
||||||
printf '%s\n' "${arch_packages[@]}" >>"$build_cache_dir/packages.x86_64"
|
printf '%s\n' "${arch_packages[@]}" >>"$build_cache_dir/packages.x86_64"
|
||||||
|
|
||||||
if [ "$OMARCHY_BUILD_MODE" = "offline" ]; then
|
# Build list of all the packages needed for the offline mirror
|
||||||
prepare_offline_mirror
|
all_packages=($(cat "$build_cache_dir/packages.x86_64"))
|
||||||
|
all_packages+=($(grep -v '^#' "$build_cache_dir/airootfs/root/omarchy/install/omarchy-base.packages" | grep -v '^$'))
|
||||||
|
all_packages+=($(grep -v '^#' "$build_cache_dir/airootfs/root/omarchy/install/omarchy-other.packages" | grep -v '^$'))
|
||||||
|
all_packages+=($(grep -v '^#' /builder/archinstall.packages | grep -v '^$'))
|
||||||
|
|
||||||
# Download Ruby tarball if not already cached
|
# Download all the packages to the offline mirror inside the ISO
|
||||||
ruby_tarball="ruby-3.4.5-rails-8.0.2.1-x86_64.tar.gz"
|
mkdir -p /tmp/offlinedb
|
||||||
if [ ! -f "$offline_ruby_dir/$ruby_tarball" ]; then
|
pacman --config /configs/pacman-online-${OMARCHY_MIRROR}.conf --noconfirm -Syw "${all_packages[@]}" --cachedir $offline_mirror_dir/ --dbpath /tmp/offlinedb
|
||||||
echo "Downloading Ruby tarball..."
|
repo-add --new "$offline_mirror_dir/offline.db.tar.gz" "$offline_mirror_dir/"*.pkg.tar.zst
|
||||||
curl -fsSL -o "$offline_ruby_dir/$ruby_tarball" \
|
|
||||||
"https://pkgs.omarchy.org/ruby/$ruby_tarball"
|
|
||||||
else
|
|
||||||
echo "Ruby tarball already cached, skipping download"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create a symlink to the offline mirror instead of duplicating it.
|
# Create a symlink to the offline mirror instead of duplicating it.
|
||||||
# mkarchiso needs packages at /var/cache/omarchy/mirror/offline in the container,
|
# mkarchiso needs packages at /var/cache/omarchy/mirror/offline in the container,
|
||||||
# but they're actually in $build_cache_dir/airootfs/var/cache/omarchy/mirror/offline
|
# but they're actually in $build_cache_dir/airootfs/var/cache/omarchy/mirror/offline
|
||||||
mkdir -p /var/cache/omarchy/mirror
|
mkdir -p /var/cache/omarchy/mirror
|
||||||
ln -s "$offline_mirror_dir" "/var/cache/omarchy/mirror/offline"
|
ln -s "$offline_mirror_dir" "/var/cache/omarchy/mirror/offline"
|
||||||
fi
|
|
||||||
|
|
||||||
# Install Python packages for the installer into the ISO
|
# Copy the offline pacman.conf to the ISO's /etc directory so the live environment uses our
|
||||||
# file system.
|
# same config when booted.
|
||||||
pip install "${python_packages[@]}"
|
cp $build_cache_dir/pacman-offline.conf "$build_cache_dir/airootfs/etc/pacman.conf"
|
||||||
|
|
||||||
if [ "$OMARCHY_BUILD_MODE" = "online" ]; then
|
|
||||||
# Copy the online version so we use it for build and ISO boot
|
|
||||||
cp $build_cache_dir/pacman-online.conf $build_cache_dir/pacman.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Copy the pacman.conf to the ISO's /etc directory so the live environment uses our
|
|
||||||
# same config when booted
|
|
||||||
cp $build_cache_dir/pacman.conf "$build_cache_dir/airootfs/etc/pacman.conf"
|
|
||||||
|
|
||||||
# Finally, we assemble the entire ISO
|
# Finally, we assemble the entire ISO
|
||||||
mkarchiso -v -w "$build_cache_dir/work/" -o "/out/" "$build_cache_dir/"
|
mkarchiso -v -w "$build_cache_dir/work/" -o "/out/" "$build_cache_dir/"
|
||||||
|
|
||||||
|
# Fix ownership of output files to match host user
|
||||||
|
if [ -n "$HOST_UID" ] && [ -n "$HOST_GID" ]; then
|
||||||
|
chown -R "$HOST_UID:$HOST_GID" /out/
|
||||||
|
fi
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
nano
|
|
||||||
vim
|
|
||||||
openssh
|
|
||||||
htop
|
|
||||||
wireless_tools
|
|
||||||
wpa_supplicant
|
|
||||||
smartmontools
|
|
||||||
xdg-utils
|
|
||||||
dunst
|
|
||||||
kitty
|
|
||||||
dolphin
|
|
||||||
wofi
|
|
||||||
qt5-wayland
|
|
||||||
qt6-wayland
|
|
||||||
polkit-kde-agent
|
|
||||||
grim
|
|
||||||
xorg-server
|
|
||||||
xorg-xinit
|
|
||||||
mesa
|
|
||||||
xf86-video-amdgpu
|
|
||||||
xf86-video-ati
|
|
||||||
xf86-video-nouveau
|
|
||||||
libva-mesa-driver
|
|
||||||
libva-intel-driver
|
|
||||||
vulkan-radeon
|
|
||||||
vulkan-intel
|
|
||||||
vulkan-nouveau
|
|
||||||
sddm
|
|
||||||
efibootmgr
|
|
||||||
intel-media-driver
|
|
||||||
amd-ucode
|
|
||||||
intel-ucode
|
|
||||||
sof-firmware
|
|
||||||
base
|
|
||||||
base-devel
|
|
||||||
linux-firmware
|
|
||||||
linux
|
|
||||||
limine
|
|
||||||
pipewire
|
|
||||||
snapper
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
# Configuration for archiso with Plymouth
|
# Configuration for archiso with Plymouth
|
||||||
HOOKS=(base udev plymouth modconf archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_kms block filesystems keyboard)
|
HOOKS=(base udev microcode modconf kms memdisk archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs plymouth block filesystems keyboard)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# mkinitcpio preset file for the 'linux' package on archiso
|
||||||
|
|
||||||
|
PRESETS=('archiso')
|
||||||
|
|
||||||
|
ALL_kver='/boot/vmlinuz-linux-t2'
|
||||||
|
archiso_config='/etc/mkinitcpio.conf.d/archiso.conf'
|
||||||
|
|
||||||
|
archiso_image="/boot/initramfs-linux-t2.img"
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Fix Panther Lake audio: blacklist SOF modules that conflict with HDA drivers
|
||||||
|
# (prevents boot issues on Dell XPS 2026 and similar Panther Lake systems)
|
||||||
|
blacklist snd_sof_pci_intel_ptl
|
||||||
|
blacklist snd_sof_pci_intel_lnl
|
||||||
|
blacklist snd_sof_pci_intel_mtl
|
||||||
|
blacklist snd_sof_intel_hda_generic
|
||||||
|
blacklist snd_sof_intel_hda_common
|
||||||
|
blacklist snd_sof_intel_hda
|
||||||
|
blacklist snd_sof_pci
|
||||||
|
blacklist snd_sof
|
||||||
|
blacklist soundwire_intel
|
||||||
|
blacklist snd_soc_cs35l56_sdw
|
||||||
|
blacklist snd_soc_cs35l56
|
||||||
|
blacklist snd_soc_skl_hda_dsp
|
||||||
@@ -1,6 +1,46 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
use_omarchy_helpers() {
|
||||||
|
export OMARCHY_PATH="/root/omarchy"
|
||||||
|
export OMARCHY_INSTALL="/root/omarchy/install"
|
||||||
|
export OMARCHY_INSTALL_LOG_FILE="/var/log/omarchy-install.log"
|
||||||
|
export OMARCHY_MIRROR="$(cat /root/omarchy_mirror)"
|
||||||
|
source /root/omarchy/install/helpers/all.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
run_configurator() {
|
||||||
|
set_tokyo_night_colors
|
||||||
|
./configurator
|
||||||
|
export OMARCHY_USER="$(jq -r '.users[0].username' user_credentials.json)"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_arch() {
|
||||||
|
clear_logo
|
||||||
|
gum style --foreground 3 --padding "1 0 0 $PADDING_LEFT" "Installing..."
|
||||||
|
echo
|
||||||
|
|
||||||
|
touch /var/log/omarchy-install.log
|
||||||
|
|
||||||
|
start_log_output
|
||||||
|
|
||||||
|
# Set CURRENT_SCRIPT for the trap to display better when nothing is returned for some reason
|
||||||
|
CURRENT_SCRIPT="install_base_system"
|
||||||
|
install_base_system > >(sed -u 's/\x1b\[[0-9;]*[a-zA-Z]//g' >>/var/log/omarchy-install.log) 2>&1
|
||||||
|
unset CURRENT_SCRIPT
|
||||||
|
stop_log_output
|
||||||
|
}
|
||||||
|
|
||||||
|
install_omarchy() {
|
||||||
|
chroot_bash -lc "sudo pacman -S --noconfirm --needed gum" >/dev/null
|
||||||
|
chroot_bash -lc "source /home/$OMARCHY_USER/.local/share/omarchy/install.sh || bash"
|
||||||
|
|
||||||
|
# Reboot if requested by installer
|
||||||
|
if [[ -f /mnt/var/tmp/omarchy-install-completed ]]; then
|
||||||
|
reboot
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Set Tokyo Night color scheme for the terminal
|
# Set Tokyo Night color scheme for the terminal
|
||||||
set_tokyo_night_colors() {
|
set_tokyo_night_colors() {
|
||||||
if [[ $(tty) == "/dev/tty"* ]]; then
|
if [[ $(tty) == "/dev/tty"* ]]; then
|
||||||
@@ -28,26 +68,11 @@ set_tokyo_night_colors() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
run_configurator() {
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Check if this is an online or offline build
|
|
||||||
if [ "${OMARCHY_INSTALL_MODE:-offline}" = "online" ]; then
|
|
||||||
./configurator
|
|
||||||
else
|
|
||||||
NETWORK_NOT_NEEDED=true ./configurator
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get username from installer config for reliable error recovery
|
|
||||||
export OMARCHY_USER="$(jq -r '.users[0].username' user_credentials.json)"
|
|
||||||
}
|
|
||||||
|
|
||||||
install_base_system() {
|
install_base_system() {
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Initialize and populate the keyring
|
# Initialize and populate the keyring
|
||||||
pacman-key --init
|
pacman-key --init
|
||||||
pacman-key --populate archlinux
|
pacman-key --populate archlinux
|
||||||
|
pacman-key --populate omarchy
|
||||||
|
|
||||||
# Sync the offline database so pacman can find packages
|
# Sync the offline database so pacman can find packages
|
||||||
pacman -Sy --noconfirm
|
pacman -Sy --noconfirm
|
||||||
@@ -55,6 +80,19 @@ install_base_system() {
|
|||||||
# Ensure that no mounts exist from past install attempts
|
# Ensure that no mounts exist from past install attempts
|
||||||
findmnt -R /mnt >/dev/null && umount -R /mnt
|
findmnt -R /mnt >/dev/null && umount -R /mnt
|
||||||
|
|
||||||
|
# Workarounds for archinstall 4.2 regressions under Python 3.14:
|
||||||
|
# 1. sync_log_to_install_medium: `self.target / absolute_logfile` drops
|
||||||
|
# self.target because the RHS is absolute, so Path.copy() raises EINVAL
|
||||||
|
# (source == target).
|
||||||
|
# 2. _add_limine_bootloader: `Path.copy(efi_dir_path)` raises IsADirectoryError
|
||||||
|
# because 3.14's Path.copy treats target as a literal path, not a directory
|
||||||
|
# (shutil.copy used to auto-append the source filename).
|
||||||
|
sed -i \
|
||||||
|
-e 's|logfile_target = self\.target / absolute_logfile$|logfile_target = self.target / absolute_logfile.relative_to("/")|' \
|
||||||
|
-e 's|(limine_path / file)\.copy(efi_dir_path)|(limine_path / file).copy(efi_dir_path / file)|' \
|
||||||
|
-e "s|(limine_path / 'limine-bios.sys')\.copy(boot_limine_path)|(limine_path / 'limine-bios.sys').copy(boot_limine_path / 'limine-bios.sys')|" \
|
||||||
|
/usr/lib/python3.14/site-packages/archinstall/lib/installer.py
|
||||||
|
|
||||||
# Install using files generated by the ./configurator
|
# Install using files generated by the ./configurator
|
||||||
# Skip NTP and WKD sync since we're offline (keyring is pre-populated in ISO)
|
# Skip NTP and WKD sync since we're offline (keyring is pre-populated in ISO)
|
||||||
archinstall \
|
archinstall \
|
||||||
@@ -62,7 +100,8 @@ install_base_system() {
|
|||||||
--creds user_credentials.json \
|
--creds user_credentials.json \
|
||||||
--silent \
|
--silent \
|
||||||
--skip-ntp \
|
--skip-ntp \
|
||||||
--skip-wkd
|
--skip-wkd \
|
||||||
|
--skip-wifi-check
|
||||||
|
|
||||||
# After archinstall sets up the base system but before our installer runs,
|
# After archinstall sets up the base system but before our installer runs,
|
||||||
# we need to ensure the offline pacman.conf is in place
|
# we need to ensure the offline pacman.conf is in place
|
||||||
@@ -72,9 +111,9 @@ install_base_system() {
|
|||||||
mkdir -p /mnt/var/cache/omarchy/mirror/offline
|
mkdir -p /mnt/var/cache/omarchy/mirror/offline
|
||||||
mount --bind /var/cache/omarchy/mirror/offline /mnt/var/cache/omarchy/mirror/offline
|
mount --bind /var/cache/omarchy/mirror/offline /mnt/var/cache/omarchy/mirror/offline
|
||||||
|
|
||||||
# Mount the ruby directory so it's accessible in the chroot
|
# Mount the packages dir so it's accessible in the chroot
|
||||||
mkdir -p /mnt/var/cache/omarchy/ruby
|
mkdir -p /mnt/opt/packages
|
||||||
mount --bind /var/cache/omarchy/ruby /mnt/var/cache/omarchy/ruby
|
mount --bind /opt/packages /mnt/opt/packages
|
||||||
|
|
||||||
# No need to ask for sudo during the installation (omarchy itself responsible for removing after install)
|
# No need to ask for sudo during the installation (omarchy itself responsible for removing after install)
|
||||||
mkdir -p /mnt/etc/sudoers.d
|
mkdir -p /mnt/etc/sudoers.d
|
||||||
@@ -90,65 +129,30 @@ EOF
|
|||||||
cp -r /root/omarchy /mnt/home/$OMARCHY_USER/.local/share/
|
cp -r /root/omarchy /mnt/home/$OMARCHY_USER/.local/share/
|
||||||
|
|
||||||
chown -R 1000:1000 /mnt/home/$OMARCHY_USER/.local/
|
chown -R 1000:1000 /mnt/home/$OMARCHY_USER/.local/
|
||||||
# Ensure all scripts in bin directories are executable
|
|
||||||
|
# Ensure all necessary scripts are executable
|
||||||
find /mnt/home/$OMARCHY_USER/.local/share/omarchy -type f -path "*/bin/*" -exec chmod +x {} \;
|
find /mnt/home/$OMARCHY_USER/.local/share/omarchy -type f -path "*/bin/*" -exec chmod +x {} \;
|
||||||
# Ensure boot.sh is executable
|
|
||||||
chmod +x /mnt/home/$OMARCHY_USER/.local/share/omarchy/boot.sh 2>/dev/null || true
|
chmod +x /mnt/home/$OMARCHY_USER/.local/share/omarchy/boot.sh 2>/dev/null || true
|
||||||
|
chmod +x /mnt/home/$OMARCHY_USER/.local/share/omarchy/default/waybar/indicators/screen-recording.sh 2>/dev/null || true
|
||||||
|
chmod +x /mnt/home/$OMARCHY_USER/.local/share/omarchy/default/waybar/indicators/idle.sh 2>/dev/null || true
|
||||||
|
chmod +x /mnt/home/$OMARCHY_USER/.local/share/omarchy/default/waybar/indicators/notification-silencing.sh 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
chroot_bash() {
|
chroot_bash() {
|
||||||
HOME=/home/$OMARCHY_USER \
|
HOME=/home/$OMARCHY_USER \
|
||||||
arch-chroot -u $OMARCHY_USER /mnt/ \
|
arch-chroot -u $OMARCHY_USER /mnt/ \
|
||||||
env OMARCHY_CHROOT_INSTALL=1 \
|
env OMARCHY_CHROOT_INSTALL=1 \
|
||||||
OMARCHY_INSTALL_MODE="${OMARCHY_INSTALL_MODE:-offline}" \
|
|
||||||
OMARCHY_USER_NAME="$(<user_full_name.txt)" \
|
OMARCHY_USER_NAME="$(<user_full_name.txt)" \
|
||||||
OMARCHY_USER_EMAIL="$(<user_email_address.txt)" \
|
OMARCHY_USER_EMAIL="$(<user_email_address.txt)" \
|
||||||
|
OMARCHY_MIRROR="$OMARCHY_MIRROR" \
|
||||||
USER="$OMARCHY_USER" \
|
USER="$OMARCHY_USER" \
|
||||||
HOME="/home/$OMARCHY_USER" \
|
HOME="/home/$OMARCHY_USER" \
|
||||||
OMARCHY_REPO="$(<omarchy_installer_repo.txt)" \
|
|
||||||
OMARCHY_REF="$(<omarchy_installer_ref.txt)" \
|
|
||||||
/bin/bash "$@"
|
/bin/bash "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $(tty) == "/dev/tty1" ]]; then
|
if [[ $(tty) == "/dev/tty1" ]]; then
|
||||||
# Set log file to pull from in trap
|
use_omarchy_helpers
|
||||||
export OMARCHY_INSTALL_LOG_FILE="/var/log/omarchy-install.log"
|
|
||||||
export OMARCHY_PATH="/root/omarchy"
|
|
||||||
export OMARCHY_INSTALL="/root/omarchy/install"
|
|
||||||
|
|
||||||
# Set install mode based on build mode file, default to offline
|
|
||||||
if [ -f /root/omarchy_install_mode.txt ]; then
|
|
||||||
export OMARCHY_INSTALL_MODE="$(cat /root/omarchy_install_mode.txt)"
|
|
||||||
else
|
|
||||||
export OMARCHY_INSTALL_MODE="offline"
|
|
||||||
fi
|
|
||||||
|
|
||||||
source "$OMARCHY_INSTALL/preflight/set-size-vars.sh"
|
|
||||||
source "$OMARCHY_INSTALL/helpers/logo.sh"
|
|
||||||
source "$OMARCHY_INSTALL/preflight/gum.sh"
|
|
||||||
source "$OMARCHY_INSTALL/helpers/tail-log-output.sh"
|
|
||||||
source "$OMARCHY_INSTALL/helpers/trap-errors.sh"
|
|
||||||
|
|
||||||
set_tokyo_night_colors
|
|
||||||
|
|
||||||
run_configurator
|
run_configurator
|
||||||
|
install_arch
|
||||||
clear_logo
|
install_omarchy
|
||||||
|
|
||||||
gum style --foreground 3 --padding "1 0 0 $PADDING_LEFT" "Installing Omarchy..."
|
|
||||||
|
|
||||||
touch "$OMARCHY_INSTALL_LOG_FILE"
|
|
||||||
|
|
||||||
start_log_output
|
|
||||||
install_base_system 2>&1 | sed -u 's/\x1b\[[0-9;]*[a-zA-Z]//g' >>"$OMARCHY_INSTALL_LOG_FILE"
|
|
||||||
cleanup
|
|
||||||
|
|
||||||
# Get username from the config file after installation
|
|
||||||
OMARCHY_USER="$(jq -r '.users[0].username' user_credentials.json)"
|
|
||||||
|
|
||||||
# Install gum early so we have it for formatting
|
|
||||||
chroot_bash -lc "sudo pacman -S --noconfirm --needed gum" >/dev/null
|
|
||||||
|
|
||||||
# Run Omarchy installer directly (skip boot.sh since it would try to clone again)
|
|
||||||
chroot_bash -lc "source /home/$OMARCHY_USER/.local/share/omarchy/install.sh || bash"
|
|
||||||
fi
|
fi
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Rely on Omarchy for styling and error handling
|
||||||
|
source "$OMARCHY_INSTALL/helpers/all.sh"
|
||||||
|
|
||||||
|
# Ensure tzupdate is available for guessing timezone
|
||||||
|
command -v tzupdate >/dev/null || sudo pacman -Sy --noconfirm tzupdate
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
gum style "${1:-Aborted installation}"
|
||||||
|
echo
|
||||||
|
gum style "You can retry later by running: ./.automated_script.sh"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
step() {
|
||||||
|
clear_logo
|
||||||
|
echo
|
||||||
|
gum style "$1"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
notice() {
|
||||||
|
clear_logo
|
||||||
|
echo
|
||||||
|
gum spin --spinner "pulse" --title "$1" -- sleep "${2:-2}"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# STEP 1: KEYBOARD LAYOUT
|
||||||
|
|
||||||
|
keyboard_form() {
|
||||||
|
step "Let's setup your machine..."
|
||||||
|
keyboards=$'Azerbaijani|azerty
|
||||||
|
Belarusian|by
|
||||||
|
Belgian|be-latin1
|
||||||
|
Bosnian|ba
|
||||||
|
Bulgarian|bg-cp1251
|
||||||
|
Croatian|croat
|
||||||
|
Czech|cz
|
||||||
|
Danish|dk-latin1
|
||||||
|
Dutch|nl
|
||||||
|
English (UK)|uk
|
||||||
|
English (US)|us
|
||||||
|
English (US, Dvorak)|dvorak
|
||||||
|
Estonian|et
|
||||||
|
Finnish|fi
|
||||||
|
French|fr
|
||||||
|
French (Canada)|cf
|
||||||
|
French (Switzerland)|fr_CH
|
||||||
|
Georgian|ge
|
||||||
|
German|de
|
||||||
|
German (Switzerland)|de_CH-latin1
|
||||||
|
Greek|gr
|
||||||
|
Hebrew|il
|
||||||
|
Hungarian|hu
|
||||||
|
Icelandic|is-latin1
|
||||||
|
Irish|ie
|
||||||
|
Italian|it
|
||||||
|
Japanese|jp106
|
||||||
|
Kazakh|kazakh
|
||||||
|
Khmer (Cambodia)|khmer
|
||||||
|
Kyrgyz|kyrgyz
|
||||||
|
Lao|la-latin1
|
||||||
|
Latvian|lv
|
||||||
|
Lithuanian|lt
|
||||||
|
Macedonian|mk-utf
|
||||||
|
Norwegian|no-latin1
|
||||||
|
Polish|pl
|
||||||
|
Portuguese|pt-latin1
|
||||||
|
Portuguese (Brazil)|br-abnt2
|
||||||
|
Romanian|ro
|
||||||
|
Russian|ru
|
||||||
|
Serbian|sr-latin
|
||||||
|
Slovak|sk-qwertz
|
||||||
|
Slovenian|slovene
|
||||||
|
Spanish|es
|
||||||
|
Spanish (Latin American)|la-latin1
|
||||||
|
Swedish|sv-latin1
|
||||||
|
Tajik|tj_alt-UTF8
|
||||||
|
Turkish|trq
|
||||||
|
Ukrainian|ua'
|
||||||
|
choice=$(printf '%s\n' "$keyboards" | cut -d'|' -f1 | gum choose --height 10 --selected "English (US)" --header "Select keyboard layout") || abort
|
||||||
|
keyboard=$(printf '%s\n' "$keyboards" | awk -F'|' -v c="$choice" '$1==c{print $2; exit}')
|
||||||
|
|
||||||
|
# Only attempt to load keyboard layout if we're on a real console
|
||||||
|
# loadkeys only works on Linux virtual consoles (tty), not in terminal emulators
|
||||||
|
if [[ $(tty 2>/dev/null) == "/dev/tty"* ]]; then
|
||||||
|
loadkeys "$keyboard" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
keyboard_form
|
||||||
|
|
||||||
|
# STEP 2: USER
|
||||||
|
|
||||||
|
user_form() {
|
||||||
|
step "Let's setup your user account..."
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
username=$(gum input --placeholder "Alphanumeric without spaces (like dhh)" --prompt.foreground="#845DF9" --prompt "Username> ") || abort
|
||||||
|
|
||||||
|
if [[ "$username" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
notice "Username must be alphanumeric with no spaces" 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
password=$(gum input --placeholder "Used for user + root + encryption" --prompt.foreground="#845DF9" --password --prompt "Password> ") || abort
|
||||||
|
password_confirmation=$(gum input --placeholder "Must match the password you just typed" --prompt.foreground="#845DF9" --password --prompt "Confirm> ") || abort
|
||||||
|
|
||||||
|
if [[ -n "$password" && "$password" == "$password_confirmation" ]]; then
|
||||||
|
break
|
||||||
|
elif [[ -z "$password" ]]; then
|
||||||
|
notice "Your password can't be blank!" 1
|
||||||
|
else
|
||||||
|
notice "Passwords didn't match!" 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Hash the password using yescrypt
|
||||||
|
password_hash=$(printf '%s' "$password" | openssl passwd -6 -stdin)
|
||||||
|
|
||||||
|
full_name=$(gum input --placeholder "Used for git authentication (hit return to skip)" --prompt.foreground="#845DF9" --prompt "Full name> ")
|
||||||
|
email_address=$(gum input --placeholder "Used for git authentication (hit return to skip)" --prompt.foreground="#845DF9" --prompt "Email address> ")
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
hostname=$(gum input --placeholder "Alphanumeric without spaces (or return for 'omarchy')" --prompt.foreground="#845DF9" --prompt "Hostname> ")
|
||||||
|
|
||||||
|
if [[ "$hostname" =~ ^[A-Za-z_][A-Za-z0-9_-]*\$?$ ]]; then
|
||||||
|
break
|
||||||
|
elif [[ -z $hostname ]]; then
|
||||||
|
hostname="omarchy"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
notice "Hostname must be alphanumeric using dashes or underscores but no spaces" 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Pick timezone
|
||||||
|
geo_guessed_timezone=$(tzupdate -p 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ -n $geo_guessed_timezone ]]; then
|
||||||
|
timezone=$(timedatectl list-timezones | gum choose --height 10 --selected "$geo_guessed_timezone" --header "Timezone") || abort
|
||||||
|
else
|
||||||
|
timezone=$(timedatectl list-timezones | gum filter --height 10 --header "Timezone") || abort
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
user_form
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Add manual padding since gum table -p doesn't respect padding
|
||||||
|
echo -e "Field,Value
|
||||||
|
Username,$username
|
||||||
|
Password,$(printf "%${#password}s" | tr ' ' '*')
|
||||||
|
Full name,${full_name:-[Skipped]}
|
||||||
|
Email address,${email_address:-[Skipped]}
|
||||||
|
Hostname,$hostname
|
||||||
|
Timezone,$timezone
|
||||||
|
Keyboard,$keyboard" |
|
||||||
|
gum table -s "," -p | sed "s/^/${PADDING_LEFT_SPACES}/"
|
||||||
|
|
||||||
|
echo
|
||||||
|
if gum confirm --negative "No, change it" "Does this look right?"; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
keyboard_form
|
||||||
|
user_form
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# STEP 3: DISK
|
||||||
|
|
||||||
|
get_disk_info() {
|
||||||
|
local device="$1"
|
||||||
|
local size vendor model label
|
||||||
|
|
||||||
|
# Get basic disk information
|
||||||
|
size=$(lsblk -dno SIZE "$device" 2>/dev/null)
|
||||||
|
vendor=$(lsblk -dno VENDOR "$device" 2>/dev/null | sed 's/ *$//')
|
||||||
|
model=$(lsblk -dno MODEL "$device" 2>/dev/null | sed 's/ *$//')
|
||||||
|
|
||||||
|
# Combine vendor and model, avoiding duplication
|
||||||
|
label=""
|
||||||
|
if [[ -n $vendor && -n $model ]]; then
|
||||||
|
if [[ $model == *$vendor* ]]; then
|
||||||
|
label="$model"
|
||||||
|
else
|
||||||
|
label="$vendor $model"
|
||||||
|
fi
|
||||||
|
elif [[ -n $model ]]; then
|
||||||
|
label="$model"
|
||||||
|
elif [[ -n $vendor ]]; then
|
||||||
|
label="$vendor"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Format display string
|
||||||
|
local display="$device"
|
||||||
|
[[ -n $size ]] && display="$display ($size)"
|
||||||
|
[[ -n $label ]] && display="$display - $label"
|
||||||
|
|
||||||
|
# Append compact partition summary
|
||||||
|
local part_summary
|
||||||
|
part_summary=$(lsblk -nro TYPE,NAME,FSTYPE,MOUNTPOINT "$device" 2>/dev/null | \
|
||||||
|
awk '$1=="part" { printf "%s%s%s", s, ($3==""?"unknown":$3), ($4==""?"":"("$4")"); s=", " }')
|
||||||
|
[[ -n $part_summary ]] && display+=" [$part_summary]"
|
||||||
|
|
||||||
|
echo "$display"
|
||||||
|
}
|
||||||
|
|
||||||
|
disk_form() {
|
||||||
|
step "Let's select where to install Omarchy..."
|
||||||
|
|
||||||
|
# Don't offer the install media as an option (Arch ISO mounts it here)
|
||||||
|
local exclude_disk
|
||||||
|
exclude_disk=$(findmnt -no SOURCE /run/archiso/bootmnt 2>/dev/null || true)
|
||||||
|
|
||||||
|
# List all installable disks, excluding the boot device if present
|
||||||
|
local available_disks
|
||||||
|
available_disks=$(
|
||||||
|
lsblk -dpno NAME,TYPE |
|
||||||
|
awk '$2=="disk"{print $1}' |
|
||||||
|
grep -E '/dev/(sd|hd|vd|nvme|mmcblk|xv)' |
|
||||||
|
{ if [[ -n "$exclude_disk" ]]; then grep -Fvx "$exclude_disk"; else cat; fi; }
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get available disks and format them with info
|
||||||
|
local disk_options=""
|
||||||
|
while IFS= read -r device; do
|
||||||
|
if [[ -n "$device" ]]; then
|
||||||
|
disk_info=$(get_disk_info "$device")
|
||||||
|
disk_options="$disk_options$disk_info"$'\n'
|
||||||
|
fi
|
||||||
|
done <<<"$available_disks"
|
||||||
|
|
||||||
|
selected_display=$(echo "$disk_options" | gum choose --header "Select install disk") || abort
|
||||||
|
disk=$(echo "$selected_display" | awk '{print $1}')
|
||||||
|
}
|
||||||
|
|
||||||
|
disk_form
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
gum style "Everything will be overwritten. There is no recovery possible."
|
||||||
|
|
||||||
|
echo
|
||||||
|
if gum confirm --affirmative "Yes, format disk" --negative "No, change it" "Confirm overwriting ${disk}"; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
disk_form
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
# Save user full name and email address, so the autostart can
|
||||||
|
# set them as OMARCHY_USER_NAME and OMARCHY_USER_EMAIL
|
||||||
|
echo "$full_name" >user_full_name.txt
|
||||||
|
echo "$email_address" >user_email_address.txt
|
||||||
|
|
||||||
|
# Escape username and password for safe inclusion
|
||||||
|
password_escaped=$(echo -n "$password" | jq -Rsa)
|
||||||
|
password_hash_escaped=$(echo -n "$password_hash" | jq -Rsa)
|
||||||
|
username_escaped=$(echo -n "$username" | jq -Rsa)
|
||||||
|
|
||||||
|
cat <<-_EOF_ >user_credentials.json
|
||||||
|
{
|
||||||
|
"encryption_password": $password_escaped,
|
||||||
|
"root_enc_password": $password_hash_escaped,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"enc_password": $password_hash_escaped,
|
||||||
|
"groups": [],
|
||||||
|
"sudo": true,
|
||||||
|
"username": $username_escaped
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
_EOF_
|
||||||
|
|
||||||
|
# Setup partition layout
|
||||||
|
disk_size=$(lsblk -bdno SIZE "$disk")
|
||||||
|
mib=$((1024 * 1024))
|
||||||
|
gib=$((mib * 1024))
|
||||||
|
disk_size_in_mib=$((disk_size / mib * mib)) # Rounds to nearest MiB
|
||||||
|
|
||||||
|
gpt_backup_reserve=$((mib))
|
||||||
|
boot_partition_start=$((mib))
|
||||||
|
boot_partition_size=$((2 * gib))
|
||||||
|
|
||||||
|
main_partition_start=$((boot_partition_size + boot_partition_start))
|
||||||
|
main_partition_size=$((disk_size_in_mib - main_partition_start - gpt_backup_reserve))
|
||||||
|
|
||||||
|
# Detect T2 Mac and set appropriate kernel
|
||||||
|
if lspci -nn 2>/dev/null | grep -q "106b:180[12]"; then
|
||||||
|
kernel_choice="linux-t2"
|
||||||
|
else
|
||||||
|
kernel_choice="linux"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<-_EOF_ >user_configuration.json
|
||||||
|
{
|
||||||
|
"app_config": null,
|
||||||
|
"archinstall-language": "English",
|
||||||
|
"auth_config": {},
|
||||||
|
"audio_config": { "audio": "pipewire" },
|
||||||
|
"bootloader": "Limine",
|
||||||
|
"custom_commands": [],
|
||||||
|
"disk_config": {
|
||||||
|
"btrfs_options": {
|
||||||
|
"snapshot_config": {
|
||||||
|
"type": "Snapper"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config_type": "default_layout",
|
||||||
|
"device_modifications": [
|
||||||
|
{
|
||||||
|
"device": "$disk",
|
||||||
|
"partitions": [
|
||||||
|
{
|
||||||
|
"btrfs": [],
|
||||||
|
"dev_path": null,
|
||||||
|
"flags": [ "boot", "esp" ],
|
||||||
|
"fs_type": "fat32",
|
||||||
|
"mount_options": [],
|
||||||
|
"mountpoint": "/boot",
|
||||||
|
"obj_id": "ea21d3f2-82bb-49cc-ab5d-6f81ae94e18d",
|
||||||
|
"size": {
|
||||||
|
"sector_size": { "unit": "B", "value": 512 },
|
||||||
|
"unit": "B",
|
||||||
|
"value": $boot_partition_size
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"sector_size": { "unit": "B", "value": 512 },
|
||||||
|
"unit": "B",
|
||||||
|
"value": $boot_partition_start
|
||||||
|
},
|
||||||
|
"status": "create",
|
||||||
|
"type": "primary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"btrfs": [
|
||||||
|
{ "mountpoint": "/", "name": "@" },
|
||||||
|
{ "mountpoint": "/home", "name": "@home" },
|
||||||
|
{ "mountpoint": "/var/log", "name": "@log" },
|
||||||
|
{ "mountpoint": "/var/cache/pacman/pkg", "name": "@pkg" }
|
||||||
|
],
|
||||||
|
"dev_path": null,
|
||||||
|
"flags": [],
|
||||||
|
"fs_type": "btrfs",
|
||||||
|
"mount_options": [ "compress=zstd" ],
|
||||||
|
"mountpoint": null,
|
||||||
|
"obj_id": "8c2c2b92-1070-455d-b76a-56263bab24aa",
|
||||||
|
"size": {
|
||||||
|
"sector_size": { "unit": "B", "value": 512 },
|
||||||
|
"unit": "B",
|
||||||
|
"value": $main_partition_size
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"sector_size": { "unit": "B", "value": 512 },
|
||||||
|
"unit": "B",
|
||||||
|
"value": $main_partition_start
|
||||||
|
},
|
||||||
|
"status": "create",
|
||||||
|
"type": "primary"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"wipe": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"disk_encryption": {
|
||||||
|
"encryption_type": "luks",
|
||||||
|
"lvm_volumes": [],
|
||||||
|
"iter_time": 2000,
|
||||||
|
"partitions": [ "8c2c2b92-1070-455d-b76a-56263bab24aa" ],
|
||||||
|
"encryption_password": $password_escaped
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hostname": "$hostname",
|
||||||
|
"kernels": [ "$kernel_choice" ],
|
||||||
|
"network_config": { "type": "iso" },
|
||||||
|
"ntp": true,
|
||||||
|
"parallel_downloads": 8,
|
||||||
|
"script": null,
|
||||||
|
"services": [],
|
||||||
|
"swap": true,
|
||||||
|
"timezone": "$timezone",
|
||||||
|
"locale_config": {
|
||||||
|
"kb_layout": "$keyboard",
|
||||||
|
"sys_enc": "UTF-8",
|
||||||
|
"sys_lang": "en_US.UTF-8"
|
||||||
|
},
|
||||||
|
"mirror_config": {
|
||||||
|
"custom_repositories": [],
|
||||||
|
"custom_servers": [
|
||||||
|
{"url": "https://mirror.omarchy.org/\$repo/os/\$arch"},
|
||||||
|
{"url": "https://mirror.rackspace.com/archlinux/\$repo/os/\$arch"},
|
||||||
|
{"url": "https://geo.mirror.pkgbuild.com/\$repo/os/\$arch"}
|
||||||
|
],
|
||||||
|
"mirror_regions": {},
|
||||||
|
"optional_repositories": []
|
||||||
|
},
|
||||||
|
"packages": [
|
||||||
|
"base-devel",
|
||||||
|
"git",
|
||||||
|
"omarchy-keyring"
|
||||||
|
],
|
||||||
|
"profile_config": {
|
||||||
|
"gfx_driver": null,
|
||||||
|
"greeter": null,
|
||||||
|
"profile": {}
|
||||||
|
},
|
||||||
|
"version": "3.0.9"
|
||||||
|
}
|
||||||
|
_EOF_
|
||||||
|
|
||||||
|
if [[ $1 == "dry" ]]; then
|
||||||
|
echo -e "User Configuration:"
|
||||||
|
cat user_configuration.json
|
||||||
|
|
||||||
|
echo -e "\n\nUser Credentials:"
|
||||||
|
cat user_credentials.json
|
||||||
|
|
||||||
|
echo -e "\n\nUser Full Name:"
|
||||||
|
cat user_full_name.txt
|
||||||
|
|
||||||
|
echo -e "\nUser Email Address:"
|
||||||
|
cat user_email_address.txt
|
||||||
|
|
||||||
|
rm user_configuration.json user_credentials.json user_full_name.txt user_email_address.txt
|
||||||
|
fi
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
title Arch Linux install medium (x86_64, UEFI)
|
title Omarchy (x86_64, UEFI)
|
||||||
sort-key 01
|
sort-key 01
|
||||||
linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
|
linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-t2
|
||||||
initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux-t2.img
|
||||||
options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% quiet splash
|
options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% quiet splash xe.enable_panel_replay=0
|
||||||
@@ -9,11 +9,12 @@ insmod exfat
|
|||||||
insmod udf
|
insmod udf
|
||||||
|
|
||||||
# Use graphics-mode output
|
# Use graphics-mode output
|
||||||
|
insmod font
|
||||||
if loadfont "${prefix}/fonts/unicode.pf2" ; then
|
if loadfont "${prefix}/fonts/unicode.pf2" ; then
|
||||||
insmod all_video
|
insmod all_video
|
||||||
set gfxmode="auto"
|
set gfxmode="auto"
|
||||||
terminal_input console
|
terminal_input console
|
||||||
terminal_output console
|
terminal_output gfxterm
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Enable serial console
|
# Enable serial console
|
||||||
@@ -51,16 +52,16 @@ timeout_style=hidden
|
|||||||
|
|
||||||
# Menu entries
|
# Menu entries
|
||||||
|
|
||||||
menuentry "Arch Linux install medium (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
menuentry "Omarchy (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
||||||
set gfxpayload=keep
|
set gfxpayload=keep
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% quiet splash
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-t2 archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% quiet splash xe.enable_panel_replay=0
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-t2.img
|
||||||
}
|
}
|
||||||
|
|
||||||
menuentry "Arch Linux install medium with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
menuentry "Omarchy with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
||||||
set gfxpayload=keep
|
set gfxpayload=keep
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-t2 archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on xe.enable_panel_replay=0
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-t2.img
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# https://www.supergrubdisk.org/wiki/Loopback.cfg
|
||||||
|
|
||||||
|
# Search for the ISO volume
|
||||||
|
search --no-floppy --set=archiso_img_dev --file "${iso_path}"
|
||||||
|
probe --set archiso_img_dev_uuid --fs-uuid "${archiso_img_dev}"
|
||||||
|
|
||||||
|
# Get a human readable platform identifier
|
||||||
|
if [ "${grub_platform}" == 'efi' ]; then
|
||||||
|
archiso_platform='UEFI'
|
||||||
|
if [ "${grub_cpu}" == 'x86_64' ]; then
|
||||||
|
archiso_platform="x64 ${archiso_platform}"
|
||||||
|
elif [ "${grub_cpu}" == 'i386' ]; then
|
||||||
|
archiso_platform="IA32 ${archiso_platform}"
|
||||||
|
else
|
||||||
|
archiso_platform="${grub_cpu} ${archiso_platform}"
|
||||||
|
fi
|
||||||
|
elif [ "${grub_platform}" == 'pc' ]; then
|
||||||
|
archiso_platform='BIOS'
|
||||||
|
else
|
||||||
|
archiso_platform="${grub_cpu} ${grub_platform}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set default menu entry
|
||||||
|
default=archlinux
|
||||||
|
timeout=0
|
||||||
|
timeout_style=hidden
|
||||||
|
|
||||||
|
|
||||||
|
# Menu entries
|
||||||
|
|
||||||
|
menuentry "Omarchy (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
||||||
|
set gfxpayload=keep
|
||||||
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-t2 archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}" quiet splash xe.enable_panel_replay=0
|
||||||
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-t2.img
|
||||||
|
}
|
||||||
|
|
||||||
|
menuentry "Omarchy with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
||||||
|
set gfxpayload=keep
|
||||||
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-t2 archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}" accessibility=on xe.enable_panel_replay=0
|
||||||
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-t2.img
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if [ "${grub_platform}" == 'efi' -a "${grub_cpu}" == 'x86_64' -a -f '/boot/memtest86+/memtest.efi' ]; then
|
||||||
|
menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool {
|
||||||
|
set gfxpayload=800x600,1024x768
|
||||||
|
linux /boot/memtest86+/memtest.efi
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
if [ "${grub_platform}" == 'pc' -a -f '/boot/memtest86+/memtest' ]; then
|
||||||
|
menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool {
|
||||||
|
set gfxpayload=800x600,1024x768
|
||||||
|
linux /boot/memtest86+/memtest
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
if [ "${grub_platform}" == 'efi' ]; then
|
||||||
|
if [ "${grub_cpu}" == 'x86_64' -a -f '/shellx64.efi' ]; then
|
||||||
|
menuentry 'UEFI Shell' --class efi {
|
||||||
|
chainloader /shellx64.efi
|
||||||
|
}
|
||||||
|
elif [ "${grub_cpu}" == "i386" -a -f '/shellia32.efi' ]; then
|
||||||
|
menuentry 'UEFI Shell' --class efi {
|
||||||
|
chainloader /shellia32.efi
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' {
|
||||||
|
fwsetup
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
menuentry 'System shutdown' --class shutdown --class poweroff {
|
||||||
|
echo 'System shutting down...'
|
||||||
|
halt
|
||||||
|
}
|
||||||
|
|
||||||
|
menuentry 'System restart' --class reboot --class restart {
|
||||||
|
echo 'System rebooting...'
|
||||||
|
reboot
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -15,26 +15,20 @@ LocalFileSigLevel = Optional
|
|||||||
|
|
||||||
[core]
|
[core]
|
||||||
Server = https://mirror.omarchy.org/$repo/os/$arch
|
Server = https://mirror.omarchy.org/$repo/os/$arch
|
||||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
|
||||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
|
||||||
Include = /etc/pacman.d/mirrorlist
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
Server = https://mirror.omarchy.org/$repo/os/$arch
|
Server = https://mirror.omarchy.org/$repo/os/$arch
|
||||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
|
||||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
|
||||||
Include = /etc/pacman.d/mirrorlist
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
[multilib]
|
[multilib]
|
||||||
Server = https://mirror.omarchy.org/$repo/os/$arch
|
Server = https://mirror.omarchy.org/$repo/os/$arch
|
||||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
|
||||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
|
||||||
Include = /etc/pacman.d/mirrorlist
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
[omarchy]
|
[omarchy]
|
||||||
SigLevel = Optional TrustAll
|
SigLevel = Optional TrustAll
|
||||||
Server = https://pkgs.omarchy.org/$arch
|
Server = https://pkgs.omarchy.org/edge/$arch
|
||||||
|
|
||||||
[arch-mact2]
|
[arch-mact2]
|
||||||
Server = https://mirror.omarchy.org/$repo/$arch
|
Server = https://github.com/NoaHimesaka1873/arch-mact2-mirror/releases/download/release
|
||||||
SigLevel = Never
|
SigLevel = Never
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# /etc/pacman.conf
|
||||||
|
#
|
||||||
|
# See the pacman.conf(5) manpage for option and repository directives
|
||||||
|
|
||||||
|
[options]
|
||||||
|
HoldPkg = pacman glibc
|
||||||
|
Architecture = auto
|
||||||
|
ParallelDownloads = 5
|
||||||
|
|
||||||
|
# By default, pacman accepts packages signed by keys that its local keyring
|
||||||
|
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||||
|
SigLevel = Required DatabaseOptional
|
||||||
|
LocalFileSigLevel = Optional
|
||||||
|
|
||||||
|
[core]
|
||||||
|
Server = https://rc-mirror.omarchy.org/$repo/os/$arch
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
Server = https://rc-mirror.omarchy.org/$repo/os/$arch
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[multilib]
|
||||||
|
Server = https://rc-mirror.omarchy.org/$repo/os/$arch
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[omarchy]
|
||||||
|
SigLevel = Optional TrustAll
|
||||||
|
Server = https://pkgs.omarchy.org/edge/$arch
|
||||||
|
|
||||||
|
[arch-mact2]
|
||||||
|
Server = https://github.com/NoaHimesaka1873/arch-mact2-mirror/releases/download/release
|
||||||
|
SigLevel = Never
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# /etc/pacman.conf
|
||||||
|
#
|
||||||
|
# See the pacman.conf(5) manpage for option and repository directives
|
||||||
|
|
||||||
|
[options]
|
||||||
|
HoldPkg = pacman glibc
|
||||||
|
Architecture = auto
|
||||||
|
ParallelDownloads = 5
|
||||||
|
|
||||||
|
# By default, pacman accepts packages signed by keys that its local keyring
|
||||||
|
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||||
|
SigLevel = Required DatabaseOptional
|
||||||
|
LocalFileSigLevel = Optional
|
||||||
|
|
||||||
|
[core]
|
||||||
|
Server = https://stable-mirror.omarchy.org/$repo/os/$arch
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
Server = https://stable-mirror.omarchy.org/$repo/os/$arch
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[multilib]
|
||||||
|
Server = https://stable-mirror.omarchy.org/$repo/os/$arch
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[omarchy]
|
||||||
|
SigLevel = Optional TrustAll
|
||||||
|
Server = https://pkgs.omarchy.org/stable/$arch
|
||||||
|
|
||||||
|
[arch-mact2]
|
||||||
|
Server = https://github.com/NoaHimesaka1873/arch-mact2-mirror/releases/download/release
|
||||||
|
SigLevel = Never
|
||||||
@@ -2,17 +2,15 @@
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
|
|
||||||
iso_name="omarchy"
|
iso_name="omarchy"
|
||||||
iso_label="ARCH_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m)"
|
iso_label="OMARCHY_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m)"
|
||||||
iso_publisher="Omarchy <https://omarchy.org>"
|
iso_publisher="Omarchy <https://omarchy.org>"
|
||||||
iso_application="Omarchy Installer"
|
iso_application="Omarchy Installer"
|
||||||
iso_version="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y.%m.%d)"
|
iso_version="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y.%m.%d)"
|
||||||
install_dir="arch"
|
install_dir="arch"
|
||||||
buildmodes=('iso')
|
buildmodes=('iso')
|
||||||
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito'
|
bootmodes=('bios.syslinux' 'uefi.grub')
|
||||||
'uefi-ia32.systemd-boot.esp' 'uefi-x64.systemd-boot.esp'
|
|
||||||
'uefi-ia32.systemd-boot.eltorito' 'uefi-x64.systemd-boot.eltorito')
|
|
||||||
arch="x86_64"
|
arch="x86_64"
|
||||||
pacman_conf="pacman.conf"
|
pacman_conf="pacman-offline.conf"
|
||||||
airootfs_image_type="squashfs"
|
airootfs_image_type="squashfs"
|
||||||
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
|
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
|
||||||
bootstrap_tarball_compression=('zstd' '-c' '-T0' '--auto-threads=logical' '--long' '-19')
|
bootstrap_tarball_compression=('zstd' '-c' '-T0' '--auto-threads=logical' '--long' '-19')
|
||||||
@@ -24,6 +22,5 @@ file_permissions=(
|
|||||||
["/usr/local/bin/choose-mirror"]="0:0:755"
|
["/usr/local/bin/choose-mirror"]="0:0:755"
|
||||||
["/root/configurator"]="0:0:755"
|
["/root/configurator"]="0:0:755"
|
||||||
["/var/cache/omarchy/mirror/offline/"]="0:0:775"
|
["/var/cache/omarchy/mirror/offline/"]="0:0:775"
|
||||||
["/usr/bin/tte"]="0:0:755"
|
|
||||||
["/usr/local/bin/omarchy-upload-log"]="0:0:755"
|
["/usr/local/bin/omarchy-upload-log"]="0:0:755"
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
SERIAL 0 115200
|
||||||
|
UI vesamenu.c32
|
||||||
|
MENU TITLE Omarchy
|
||||||
|
MENU BACKGROUND splash.png
|
||||||
|
|
||||||
|
MENU WIDTH 78
|
||||||
|
MENU MARGIN 4
|
||||||
|
MENU ROWS 7
|
||||||
|
MENU VSHIFT 10
|
||||||
|
MENU TABMSGROW 14
|
||||||
|
MENU CMDLINEROW 14
|
||||||
|
MENU HELPMSGROW 16
|
||||||
|
MENU HELPMSGENDROW 29
|
||||||
|
|
||||||
|
# Refer to https://wiki.syslinux.org/wiki/index.php/Comboot/menu.c32
|
||||||
|
|
||||||
|
MENU COLOR border 30;44 #40ffffff #a0000000 std
|
||||||
|
MENU COLOR title 1;36;44 #9033ccff #a0000000 std
|
||||||
|
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
|
||||||
|
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
|
||||||
|
MENU COLOR help 37;40 #c0ffffff #a0000000 std
|
||||||
|
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
|
||||||
|
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
|
||||||
|
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
|
||||||
|
MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
|
||||||
|
|
||||||
|
MENU CLEAR
|
||||||
|
MENU IMMEDIATE
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
LABEL arch64_nbd
|
||||||
|
TEXT HELP
|
||||||
|
Boot the Omarchy install medium using NBD.
|
||||||
|
It allows you to install Omarchy or perform system maintenance.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Omarchy install medium (x86_64, NBD)
|
||||||
|
LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-t2
|
||||||
|
INITRD ::/%INSTALL_DIR%/boot/x86_64/initramfs-linux-t2.img
|
||||||
|
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% archiso_nbd_srv=${pxeserver} cms_verify=y
|
||||||
|
SYSAPPEND 3
|
||||||
|
|
||||||
|
LABEL arch64_nfs
|
||||||
|
TEXT HELP
|
||||||
|
Boot the Omarchy live medium using NFS.
|
||||||
|
It allows you to install Omarchy or perform system maintenance.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Omarchy install medium (x86_64, NFS)
|
||||||
|
LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-t2
|
||||||
|
INITRD ::/%INSTALL_DIR%/boot/x86_64/initramfs-linux-t2.img
|
||||||
|
APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt cms_verify=y
|
||||||
|
SYSAPPEND 3
|
||||||
|
|
||||||
|
LABEL arch64_http
|
||||||
|
TEXT HELP
|
||||||
|
Boot the Omarchy live medium using HTTP.
|
||||||
|
It allows you to install Omarchy or perform system maintenance.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Omarchy install medium (x86_64, HTTP)
|
||||||
|
LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-t2
|
||||||
|
INITRD ::/%INSTALL_DIR%/boot/x86_64/initramfs-linux-t2.img
|
||||||
|
APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ cms_verify=y
|
||||||
|
SYSAPPEND 3
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
INCLUDE archiso_head.cfg
|
||||||
|
|
||||||
|
INCLUDE archiso_pxe-linux.cfg
|
||||||
|
|
||||||
|
INCLUDE archiso_tail.cfg
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
LABEL arch64
|
||||||
|
TEXT HELP
|
||||||
|
Boot the Omarchy install medium on BIOS.
|
||||||
|
It allows you to install Omarchy or perform system maintenance.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Omarchy install medium (x86_64, BIOS)
|
||||||
|
LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-t2
|
||||||
|
INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-t2.img
|
||||||
|
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% quiet splash xe.enable_panel_replay=0
|
||||||
|
|
||||||
|
# Accessibility boot option
|
||||||
|
LABEL arch64speech
|
||||||
|
TEXT HELP
|
||||||
|
Boot the Omarchy install medium on BIOS with speakup screen reader.
|
||||||
|
It allows you to install Omarchy or perform system maintenance with speech feedback.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Omarchy install medium (x86_64, BIOS) with ^speech
|
||||||
|
LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux-t2
|
||||||
|
INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux-t2.img
|
||||||
|
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on xe.enable_panel_replay=0
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
INCLUDE archiso_head.cfg
|
||||||
|
|
||||||
|
DEFAULT arch64
|
||||||
|
TIMEOUT 150
|
||||||
|
|
||||||
|
INCLUDE archiso_sys-linux.cfg
|
||||||
|
|
||||||
|
INCLUDE archiso_tail.cfg
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
LABEL existing
|
||||||
|
TEXT HELP
|
||||||
|
Boot an existing operating system.
|
||||||
|
Press TAB to edit the disk and partition number to boot.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Boot existing OS
|
||||||
|
COM32 chain.c32
|
||||||
|
APPEND hd0 0
|
||||||
|
|
||||||
|
# https://www.memtest.org/
|
||||||
|
LABEL memtest
|
||||||
|
MENU LABEL Run Memtest86+ (RAM test)
|
||||||
|
LINUX /boot/memtest86+/memtest
|
||||||
|
|
||||||
|
# https://wiki.syslinux.org/wiki/index.php/Hdt_(Hardware_Detection_Tool)
|
||||||
|
LABEL hdt
|
||||||
|
MENU LABEL Hardware Information (HDT)
|
||||||
|
COM32 hdt.c32
|
||||||
|
APPEND modules_alias=hdt/modalias.gz pciids=hdt/pciids.gz
|
||||||
|
|
||||||
|
LABEL reboot
|
||||||
|
TEXT HELP
|
||||||
|
Reboot computer.
|
||||||
|
The computer's firmware must support APM.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Reboot
|
||||||
|
COM32 reboot.c32
|
||||||
|
|
||||||
|
LABEL poweroff
|
||||||
|
TEXT HELP
|
||||||
|
Power off computer.
|
||||||
|
The computer's firmware must support APM.
|
||||||
|
ENDTEXT
|
||||||
|
MENU LABEL Power Off
|
||||||
|
COM32 poweroff.c32
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
DEFAULT select
|
||||||
|
|
||||||
|
LABEL select
|
||||||
|
COM32 whichsys.c32
|
||||||
|
APPEND -pxe- pxe -sys- sys -iso- sys
|
||||||
|
|
||||||
|
LABEL pxe
|
||||||
|
CONFIG archiso_pxe.cfg
|
||||||
|
|
||||||
|
LABEL sys
|
||||||
|
CONFIG archiso_sys.cfg
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
# Dual-Boot Installation Support for Omarchy ISO
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Currently, the Omarchy installer wipes the entire selected disk (`"wipe": true`) and creates two partitions: a 2GB FAT32 ESP and a LUKS-encrypted Btrfs root. This means users must dedicate an entire disk to Omarchy. Adding dual-boot support lets users install alongside an existing OS (typically Windows) while keeping the Omarchy partition encrypted.
|
||||||
|
|
||||||
|
## Core Approach: `pre_mounted_config`
|
||||||
|
|
||||||
|
**Do our own partitioning, then hand off to archinstall for package installation only.**
|
||||||
|
|
||||||
|
archinstall's `manual_partitioning` mode has a long history of bugs with existing partitions and LUKS (archinstall issues #998, #2072, #2444). Instead, we:
|
||||||
|
|
||||||
|
1. Detect existing partitions and free space ourselves (with `sgdisk`/`parted`)
|
||||||
|
2. Create the LUKS partition and Btrfs subvolumes ourselves (with `cryptsetup`/`mkfs.btrfs`)
|
||||||
|
3. Mount everything at `/mnt/archinstall`
|
||||||
|
4. Tell archinstall to use `"config_type": "pre_mounted_config"` — it installs packages into our pre-mounted tree and does zero disk operations
|
||||||
|
5. Handle encryption config (crypttab, mkinitcpio hooks, bootloader cmdline) in post-install
|
||||||
|
|
||||||
|
The existing full-disk path stays completely unchanged. Dual-boot is a parallel code path.
|
||||||
|
|
||||||
|
## Implementation Guardrails
|
||||||
|
|
||||||
|
- **Run target changes in chroot** — all target-system commands (`mkinitcpio -P`, `limine-scan`, bootloader config updates) must run via `arch-chroot "$INSTALL_ROOT" ...`
|
||||||
|
- **Edit target files under `$INSTALL_ROOT` only** — write `mkinitcpio` hook config, `limine.conf`, `crypttab`, and related files in `$INSTALL_ROOT/etc` and `$INSTALL_ROOT/boot` (never in the live environment root)
|
||||||
|
- **Settle kernel partition state** — after creating the new partition, run `partprobe "$DISK"` and `udevadm settle` before `cryptsetup` to avoid device-node races
|
||||||
|
- **Deterministic fstab** — always generate `/etc/fstab` for dual-boot with overwrite semantics (e.g., `genfstab -U "$INSTALL_ROOT" > "$INSTALL_ROOT/etc/fstab"`) to avoid duplicate entries on retries
|
||||||
|
- **Hook compatibility** — when updating mkinitcpio hooks, add `encrypt` for busybox initramfs or `sd-encrypt` for systemd initramfs; never assume one universally
|
||||||
|
- **Safe rollback on failure** — on any dual-boot setup failure: unmount mounts, close LUKS mapping, and surface recovery guidance; optionally delete the just-created partition only if it was created in this run
|
||||||
|
|
||||||
|
## Scope Constraints
|
||||||
|
|
||||||
|
- **UEFI/GPT only** — dual-boot on MBR/BIOS is too fragile; those users get full-disk only
|
||||||
|
- **No auto-shrinking** — users must free up space from their existing OS first (e.g., Windows Disk Management). Too risky to shrink partitions automatically
|
||||||
|
- **Minimum 20GB free space** required for Omarchy
|
||||||
|
|
||||||
|
## User Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Select disk → Detect layout →
|
||||||
|
|
||||||
|
If disk has existing OS + ESP + ≥20GB free space:
|
||||||
|
"How would you like to install?"
|
||||||
|
→ "Install alongside Windows (use 85GB free space)"
|
||||||
|
→ "Erase entire disk"
|
||||||
|
|
||||||
|
If disk is empty or no free space:
|
||||||
|
Existing "Confirm overwriting" flow (unchanged)
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Changes
|
||||||
|
|
||||||
|
### 1. `configs/airootfs/root/configurator`
|
||||||
|
|
||||||
|
**Add after disk selection (line 233), before config generation:**
|
||||||
|
|
||||||
|
- `detect_disk_layout()` — examines selected disk for:
|
||||||
|
- GPT partition table (required for dual-boot)
|
||||||
|
- Existing ESP partition (via `lsblk` PARTTYPE matching EFI GUID)
|
||||||
|
- Free unallocated space (via `sgdisk -F`/`-E` or `parted print free`)
|
||||||
|
- OS detection for installer UX warnings/prompts (not boot correctness): mount ESP read-only, check common vendor paths like `EFI/Microsoft`, `EFI/systemd`, `EFI/ubuntu`, `EFI/fedora`, `EFI/GRUB`
|
||||||
|
|
||||||
|
- `install_mode_form()` — shows gum choose with dual-boot vs erase options when conditions are met. Sets `DUAL_BOOT=true/false`.
|
||||||
|
|
||||||
|
**Generate different JSON when `DUAL_BOOT=true`:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"disk_config": {
|
||||||
|
"config_type": "pre_mounted_config",
|
||||||
|
"mountpoint": "/mnt/archinstall"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
No `device_modifications`, no `disk_encryption`, no `btrfs_options` — we handle all of that ourselves. Everything else (hostname, kernels, packages, etc.) stays the same.
|
||||||
|
|
||||||
|
**Write `install_mode.sh`** alongside the other config files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DUAL_BOOT=true
|
||||||
|
DISK=/dev/nvme0n1
|
||||||
|
ESP_PARTITION=/dev/nvme0n1p1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. `configs/airootfs/root/.automated_script.sh`
|
||||||
|
|
||||||
|
**Source `install_mode.sh`** in `run_configurator()` if it exists.
|
||||||
|
|
||||||
|
**Add `setup_dual_boot_partitions()`** — runs before archinstall when `DUAL_BOOT=true`:
|
||||||
|
|
||||||
|
1. Select the largest contiguous free region and run `sgdisk` to create new partition there (type 8309 = Linux LUKS)
|
||||||
|
2. `partprobe "$DISK"` + `udevadm settle` so new partition node is present
|
||||||
|
3. `cryptsetup luksFormat` + `luksOpen` with user's password
|
||||||
|
4. `mkfs.btrfs` on `/dev/mapper/omarchy_root`
|
||||||
|
5. Create Btrfs subvolumes: `@`, `@home`, `@log`, `@pkg`
|
||||||
|
6. Mount subvolumes at `/mnt/archinstall` with `compress=zstd`
|
||||||
|
7. Mount existing ESP (untouched) at `/mnt/archinstall/boot`
|
||||||
|
8. Generate target `/etc/fstab` from mounted filesystems before post-install steps
|
||||||
|
|
||||||
|
**Add `configure_dual_boot_post_install()`** — runs after archinstall:
|
||||||
|
|
||||||
|
1. Write `/etc/crypttab` entry using LUKS UUID/PARTUUID (stable identifier), e.g. `omarchy_root UUID=<luks-uuid> none luks,discard`
|
||||||
|
2. Update mkinitcpio hooks before `filesystems`: `encrypt` (busybox) or `sd-encrypt` (systemd)
|
||||||
|
3. Regenerate initramfs with `arch-chroot "$INSTALL_ROOT" mkinitcpio -P`
|
||||||
|
4. Configure Limine kernel cmdline to match initramfs mode:
|
||||||
|
- busybox `encrypt`: `cryptdevice=UUID=<uuid>:omarchy_root root=/dev/mapper/omarchy_root`
|
||||||
|
- systemd `sd-encrypt`: `rd.luks.name=<uuid>=omarchy_root root=/dev/mapper/omarchy_root` (or equivalent `rd.luks.uuid=` form)
|
||||||
|
5. Run `arch-chroot "$INSTALL_ROOT" limine-scan` to detect other OS boot entries (Windows, etc.)
|
||||||
|
6. Preserve current firmware default boot order unless user explicitly chooses to make Limine first (capture and restore `BootOrder` if `efibootmgr` side effects reorder entries)
|
||||||
|
|
||||||
|
**Use `$INSTALL_ROOT` variable** — defaults to `/mnt` for full-disk, `/mnt/archinstall` for dual-boot. Post-install steps (offline mirror bind-mount, sudoers, omarchy copy) reference this instead of hardcoded `/mnt`.
|
||||||
|
|
||||||
|
### 3. `builder/build-iso.sh` + `builder/archinstall.packages`
|
||||||
|
|
||||||
|
Add `parted` to packages available in the live ISO (needed for free space detection).
|
||||||
|
|
||||||
|
## Bootloader Coexistence
|
||||||
|
|
||||||
|
Limine installs to `ESP/EFI/arch-limine/` and registers via `efibootmgr`. This sits alongside:
|
||||||
|
- Windows Boot Manager at `ESP/EFI/Microsoft/Boot/bootmgfw.efi`
|
||||||
|
- Any other bootloader in its own ESP subdirectory
|
||||||
|
|
||||||
|
`limine-scan` auto-detects other UEFI boot entries and adds them to `limine.conf`. Users can choose OS at boot.
|
||||||
|
|
||||||
|
**Boot order policy**: creating a new EFI entry must not silently change the current default boot target. Keep existing firmware boot order by default and only promote Limine when user opts in.
|
||||||
|
|
||||||
|
Implementation note: when registering Limine with `efibootmgr`, do not pass reorder flags by default; if firmware still changes order, explicitly restore prior `BootOrder` unless the user opted to promote Limine.
|
||||||
|
|
||||||
|
**ESP size note**: Windows typically creates a 100-260MB ESP. This is enough for Limine + kernel + initramfs, but Snapper boot snapshots (which copy kernels to ESP) will be limited or disabled.
|
||||||
|
|
||||||
|
**ESP free-space threshold**:
|
||||||
|
- If ESP has `<100MB` free at install time: show a strong warning (do not block install)
|
||||||
|
- If ESP has `<64MB` free: hide dual-boot option and require full-disk install (or user frees space first)
|
||||||
|
|
||||||
|
**BitLocker warning**: If Windows is detected, show a warning about having the BitLocker recovery key ready, since modifying ESP/UEFI entries can trigger recovery.
|
||||||
|
|
||||||
|
## Edge Cases
|
||||||
|
|
||||||
|
| Scenario | Behavior |
|
||||||
|
|----------|----------|
|
||||||
|
| Disk is empty | Full-disk install only (current behavior) |
|
||||||
|
| Existing OS but no free space | Full-disk install only, with note to free space first |
|
||||||
|
| Free space < 20GB | Dual-boot option not shown |
|
||||||
|
| MBR/BIOS disk | Dual-boot option not shown |
|
||||||
|
| ESP < 100MB free after mount | Warn user; continue allowed |
|
||||||
|
| ESP < 64MB free after mount | Dual-boot option not shown |
|
||||||
|
| Multiple free regions | Use largest contiguous region |
|
||||||
|
| Partitioning/setup failure mid-run | Cleanup mounts/LUKS and abort safely |
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
1. **Regression**: Full-disk install in VM with empty disk — must work identically to today
|
||||||
|
2. **Dual-boot with Windows**: VM with Windows installed + 40GB free space — detect Windows, install alongside, both OSes boot
|
||||||
|
3. **Dual-boot with Linux**: VM with another Linux + free space — similar test
|
||||||
|
4. **No free space**: VM with fully partitioned disk — dual-boot option should not appear
|
||||||
|
5. **Encryption**: After dual-boot install, verify LUKS unlock prompt at boot and encrypted root
|
||||||
|
6. **Initramfs mode**: Validate both busybox and systemd hook paths boot correctly (`encrypt` vs `sd-encrypt`)
|
||||||
|
7. **Boot order**: Verify existing default UEFI entry remains unchanged unless user opted to promote Limine
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
# OEM Install + First-Boot Setup Plan
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Create a second ISO flavor for OEM preloading that is installed to internal storage at factory time, then boots into customer setup on first power-on (no external media required), and ends in a fully encrypted Omarchy install.
|
||||||
|
|
||||||
|
## Product Requirements
|
||||||
|
|
||||||
|
- Factory can preload one image to internal disk.
|
||||||
|
- Customer first boot launches setup flow automatically (already works: `.automated_script.sh` runs configurator on tty1).
|
||||||
|
- Customer chooses credentials/settings.
|
||||||
|
- Final installed OS uses full-disk encryption (LUKS) with customer password (already works: configurator collects password and passes it to archinstall as `encryption_password`).
|
||||||
|
- Existing consumer ISO behavior remains unchanged.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Chosen Architecture
|
||||||
|
|
||||||
|
### Bootstrapping model
|
||||||
|
- OEM devices ship with an OEM bootstrap ISO image written to internal disk.
|
||||||
|
- On first boot, `copytoram=y` kernel arg loads the live environment into RAM, freeing the internal disk.
|
||||||
|
- Bootstrap environment launches existing configurator + installer.
|
||||||
|
- Installer performs a fresh install to internal disk with LUKS encryption enabled.
|
||||||
|
- Bootstrap environment is overwritten during install.
|
||||||
|
|
||||||
|
### Recovery model: zero-recovery
|
||||||
|
- No permanent recovery partition.
|
||||||
|
- Simplest and strongest security story.
|
||||||
|
- Recovery requires external reinstall media.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
- No on-device recovery workflow.
|
||||||
|
- No changes to normal installer UX outside explicit OEM mode checks and warnings.
|
||||||
|
- No factory credential provisioning.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repo Implementation Plan
|
||||||
|
|
||||||
|
## 1) Add OEM build mode
|
||||||
|
|
||||||
|
### Files
|
||||||
|
- `bin/omarchy-iso-make`
|
||||||
|
- `builder/build-iso.sh`
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Add CLI flag `--oem` to `bin/omarchy-iso-make`.
|
||||||
|
- Pass `OMARCHY_MODE=oem` into Docker build env (default `normal`).
|
||||||
|
- In `builder/build-iso.sh`, write mode marker `/root/omarchy_mode` containing `oem` or `normal` (same pattern as `omarchy_mirror`).
|
||||||
|
- Keep OEM on current boot stack (`uefi.grub` + `bios.syslinux`); do not add or depend on systemd-boot paths.
|
||||||
|
- When `OMARCHY_MODE=oem`, inject `copytoram=y` into all shipped OEM boot entry points before `mkarchiso` runs:
|
||||||
|
- `grub/grub.cfg`: append to `linux` cmdline entries.
|
||||||
|
- `grub/loopback.cfg`: append to `linux` cmdline entries.
|
||||||
|
- `syslinux/archiso_sys-linux.cfg`: append to `APPEND` lines.
|
||||||
|
- When `OMARCHY_MODE=oem`, remove accessibility/speakup boot entries:
|
||||||
|
- `grub/grub.cfg`: remove `archlinux-accessibility` menuentry.
|
||||||
|
- `grub/loopback.cfg`: remove `archlinux-accessibility` menuentry.
|
||||||
|
- `syslinux/archiso_sys-linux.cfg`: remove `arch64speech` label block.
|
||||||
|
- When `OMARCHY_MODE=oem`, override `iso_application` in `profiledef.sh` to `"Omarchy OEM Installer"`.
|
||||||
|
- Rename output ISO with `-oem` suffix (in addition to existing `-$OMARCHY_INSTALLER_REF` suffix).
|
||||||
|
|
||||||
|
### Hardening
|
||||||
|
- Add post-injection build assertion that fails build if any expected boot config does not contain `copytoram=y`.
|
||||||
|
- Add post-injection build assertion that fails build if any OEM boot config still contains accessibility/speakup entries.
|
||||||
|
- Make injection idempotent (do not duplicate `copytoram=y` if already present).
|
||||||
|
|
||||||
|
### Acceptance criteria
|
||||||
|
- `./bin/omarchy-iso-make --oem` builds successfully.
|
||||||
|
- OEM ISO boot entries contain `copytoram=y` in all supported boot paths.
|
||||||
|
- OEM ISO does not expose accessibility/speakup boot entries.
|
||||||
|
- Normal build output and behavior remain unchanged.
|
||||||
|
|
||||||
|
### Suggested verification commands
|
||||||
|
- `bsdtar -xOf out/<iso>.iso boot/grub/grub.cfg | rg copytoram=y`
|
||||||
|
- `bsdtar -xOf out/<iso>.iso boot/grub/loopback.cfg | rg copytoram=y`
|
||||||
|
- `bsdtar -xOf out/<iso>.iso boot/syslinux/archiso_sys-linux.cfg | rg copytoram=y`
|
||||||
|
- `bsdtar -xOf out/<iso>.iso boot/grub/grub.cfg | rg 'accessibility|speakup'` (should return no matches)
|
||||||
|
- `bsdtar -xOf out/<iso>.iso boot/syslinux/archiso_sys-linux.cfg | rg 'speech|accessibility'` (should return no matches)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2) Add OEM safety guardrails
|
||||||
|
|
||||||
|
### Why
|
||||||
|
OEM image boots from internal disk and later wipes that same disk. Live environment must be fully in RAM before install begins.
|
||||||
|
|
||||||
|
### File
|
||||||
|
- `configs/airootfs/root/.automated_script.sh`
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Before `run_configurator`, if `/root/omarchy_mode` is `oem`:
|
||||||
|
- Verify `/proc/cmdline` contains `copytoram=y`; abort with clear actionable error if missing.
|
||||||
|
- Verify factory hardware minimum using `MemTotal`:
|
||||||
|
- Require `MemTotal >= 8 GiB`.
|
||||||
|
- Abort with clear error if below minimum.
|
||||||
|
- Verify runtime memory safety using `MemAvailable`:
|
||||||
|
- Minimum threshold: `1.5 x ISO size + 1 GiB`.
|
||||||
|
- Abort with clear error if below threshold.
|
||||||
|
- Verify runtime state indicates live root is in RAM (for example, expected archiso runtime mounts present and boot media not actively mounted as install target path).
|
||||||
|
|
||||||
|
### Acceptance criteria
|
||||||
|
- OEM mode aborts safely if `copytoram=y` missing from cmdline.
|
||||||
|
- OEM mode aborts safely if `MemTotal < 8 GiB`.
|
||||||
|
- OEM mode aborts safely if `MemAvailable` below threshold.
|
||||||
|
- OEM mode aborts safely if runtime state does not confirm RAM-backed live environment.
|
||||||
|
|
||||||
|
### Error message requirements
|
||||||
|
- State exactly what failed.
|
||||||
|
- State why install is blocked.
|
||||||
|
- Provide next step (reboot using proper OEM media or use external recovery media).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3) OEM disk warning
|
||||||
|
|
||||||
|
### Why
|
||||||
|
With `copytoram=y`, archiso copies squashfs to RAM and releases boot device. Existing configurator call `findmnt -no SOURCE /run/archiso/bootmnt` may return empty, so exclusion filter is skipped and all physical disks are shown, including former boot disk. No disk selection logic change is required.
|
||||||
|
|
||||||
|
OEM mode still needs an unmistakable warning before destructive install proceeds.
|
||||||
|
|
||||||
|
### File
|
||||||
|
- `configs/airootfs/root/configurator`
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Read mode from `/root/omarchy_mode`.
|
||||||
|
- If mode is `oem`, add OEM-specific warning text before existing destructive confirmation.
|
||||||
|
- Upgrade confirmation in OEM mode to explicit typed confirmation (for example: `YES, WIPE DISK`) while preserving existing normal-mode flow.
|
||||||
|
|
||||||
|
### Acceptance criteria
|
||||||
|
- Normal ISO behavior is unchanged.
|
||||||
|
- OEM ISO shows OEM-specific warning before disk wipe confirmation.
|
||||||
|
- OEM typed confirmation is required before destructive action.
|
||||||
|
- In VM with `copytoram=y`, former boot disk appears in disk list without exclusion-logic changes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4) Documentation
|
||||||
|
|
||||||
|
### File
|
||||||
|
- `README.md`
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Document `--oem` build flag and resulting artifact naming.
|
||||||
|
- Document factory workflow: writing OEM ISO to internal disk and expected first-boot UX.
|
||||||
|
- Document failure and recovery behavior:
|
||||||
|
- Missing `copytoram=y`, `MemTotal < 8 GiB`, or low `MemAvailable` causes safe abort.
|
||||||
|
- Interrupted/failed install requires external reinstall media.
|
||||||
|
- Add short operator checklist for manufacturing line validation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5) Validation
|
||||||
|
|
||||||
|
### VM test matrix
|
||||||
|
1. Build OEM ISO.
|
||||||
|
2. Write OEM ISO to virtual disk (not external media emulation).
|
||||||
|
3. Boot from virtual disk and verify:
|
||||||
|
- `/proc/cmdline` contains `copytoram=y`.
|
||||||
|
- Guardrail checks pass in healthy case.
|
||||||
|
- OEM boot menu does not include accessibility/speech entries.
|
||||||
|
4. Complete setup flow on first boot.
|
||||||
|
5. Install to same disk.
|
||||||
|
6. Reboot into installed OS.
|
||||||
|
7. Verify encryption:
|
||||||
|
- `lsblk` shows crypt mapping.
|
||||||
|
- `cryptsetup status` reports active LUKS device.
|
||||||
|
- Boot requires unlock passphrase.
|
||||||
|
8. Validate OEM warning + typed confirmation appears and gates destructive action.
|
||||||
|
|
||||||
|
### Boot path coverage
|
||||||
|
- UEFI + GRUB path.
|
||||||
|
- BIOS/syslinux path (if still shipped).
|
||||||
|
|
||||||
|
### Hardware test matrix
|
||||||
|
- UEFI test on at least two hardware families (Intel + AMD).
|
||||||
|
- Confirm no external media required.
|
||||||
|
- Confirm first boot starts setup automatically.
|
||||||
|
|
||||||
|
### Negative tests
|
||||||
|
- OEM boot without `copytoram=y` -> safe abort with clear error.
|
||||||
|
- `MemTotal < 8 GiB` -> safe abort with clear error.
|
||||||
|
- Low `MemAvailable` -> safe abort with clear error.
|
||||||
|
- Runtime state not RAM-backed -> safe abort with clear error.
|
||||||
|
- Power interruption before installer starts -> deterministic reboot behavior.
|
||||||
|
- Power interruption during install -> recovery requires external media (documented).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6) Security hardening checklist
|
||||||
|
|
||||||
|
- No factory credentials exist; customer sets all passwords at first boot.
|
||||||
|
- Clear shell history and transient setup artifacts at end of install.
|
||||||
|
- Verify no secrets in logs shipped to customer.
|
||||||
|
- Regenerate host identity on first installed boot as needed:
|
||||||
|
- `machine-id`
|
||||||
|
- SSH host keys (if installed/enabled)
|
||||||
|
- Keep package signature verification and keyring handling intact.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollout Plan
|
||||||
|
|
||||||
|
1. Implement OEM build flag, mode marker, boot config injection, and build assertions.
|
||||||
|
2. Implement copytoram, memory, and runtime-state guardrails in `.automated_script.sh`.
|
||||||
|
3. Add OEM warning text and typed destructive confirmation in configurator.
|
||||||
|
4. Add docs and operator checklist.
|
||||||
|
5. Run VM matrix, including negative tests.
|
||||||
|
6. Run hardware matrix.
|
||||||
|
7. Cut first OEM preproduction release for manufacturing pilot.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Definition of Done
|
||||||
|
|
||||||
|
- `--oem` build exists and is documented.
|
||||||
|
- Device preloaded with OEM image boots directly to setup.
|
||||||
|
- Setup installs to internal disk without external media.
|
||||||
|
- Final installed system is LUKS-encrypted with customer-owned passphrase.
|
||||||
|
- OEM safety guardrails fail closed with actionable errors.
|
||||||
|
- Existing non-OEM ISO behavior remains unchanged.
|
||||||
|
- VM and hardware QA matrix pass.
|
||||||
Reference in new issue
Block a user