Compare commits
No commits in common. "91e1d32f1c6e0973ef50b29aae983871a476dd7b" and "eeee7ace7db1bf6596802041ebf4d6e1571a685a" have entirely different histories.
91e1d32f1c
...
eeee7ace7d
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1 @@
|
||||
/download
|
||||
/vm
|
||||
.claude
|
||||
|
||||
@ -16,8 +16,3 @@ See `docs/yino-fsd.md` for the full functional specification and changelog.
|
||||
- Minimize dependencies, less is more; discuss with owner before adding any
|
||||
- Never install global Python packages; use a venv in this repository when Python dependencies are needed (e.g.
|
||||
`python3 -m venv venv && source venv/bin/activate && pip install ...`)
|
||||
|
||||
## Upstream tracking
|
||||
|
||||
- When re-analyzing or updating `docs/Omarchy.md`, always update the "Last analyzed" line at the top of the
|
||||
document with the current date and the latest commit hash from `basecamp/omarchy` (`dev` branch).
|
||||
|
||||
28
README.md
28
README.md
@ -1,28 +0,0 @@
|
||||
# Yino
|
||||
|
||||
**Yino Is Not Omarchy** — an opinionated Debian-based desktop OS, ported from [Omarchy](https://github.com/basecamp/omarchy).
|
||||
|
||||
## Docs
|
||||
|
||||
- [Functional Specification](docs/yino-fsd.md)
|
||||
- [Omarchy Analysis](docs/Omarchy.md)
|
||||
|
||||
## TODO
|
||||
|
||||
- [x] Set up development environment (QEMU VM for testing)
|
||||
- [ ] Create ISO generation pipeline (Debian ISO with unattended install). See item "6. Offline installation ISO" in
|
||||
`docs/yino-fsd.md` for full specification.
|
||||
- [ ] Port Omarchy installer to Debian (runs post-install, equivalent of Omarchy's phase 2-5 scripts)
|
||||
- [ ] Get Hyprland running via the installer with essential dotfiles
|
||||
|
||||
### Unsorted pool (future work, not yet prioritized)
|
||||
|
||||
- Set up custom Debian package repository (replaces Omarchy's OPR/AUR)
|
||||
- Port package management layer (pacman to apt, adapt install scripts)
|
||||
- Build and package full Hyprland ecosystem (Hypridle, Hyprlock, Hyprsunset, UWSM)
|
||||
- Port desktop environment stack (Waybar, Walker, Mako, SwayOSD)
|
||||
- Build and package applications not in Debian repos (Ghostty, etc.)
|
||||
- Port configuration and dotfiles system (3-layer: Default, Theme, User)
|
||||
- Port theming system
|
||||
- Port security configuration (UFW firewall, GPG setup)
|
||||
- Set up upstream tracking workflow for basecamp/omarchy
|
||||
201
bin/yino-iso
201
bin/yino-iso
@ -1,201 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
ISO_DIR="$REPO_DIR/iso"
|
||||
DOWNLOAD_DIR="$REPO_DIR/download"
|
||||
BASE_URL="https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd"
|
||||
|
||||
# --- Subcommands ---
|
||||
|
||||
cmd_download() {
|
||||
mkdir -p "$DOWNLOAD_DIR"
|
||||
|
||||
echo "Fetching SHA256SUMS..."
|
||||
local sums_file="$DOWNLOAD_DIR/SHA256SUMS"
|
||||
curl -fsSL -o "$sums_file" "$BASE_URL/SHA256SUMS"
|
||||
|
||||
local iso_name expected_hash
|
||||
iso_name=$(grep 'debian-.*-amd64-DVD-1\.iso' "$sums_file" | awk '{print $2}')
|
||||
expected_hash=$(grep 'debian-.*-amd64-DVD-1\.iso' "$sums_file" | awk '{print $1}')
|
||||
|
||||
if [[ -z "$iso_name" || -z "$expected_hash" ]]; then
|
||||
echo "Error: Could not find DVD-1 ISO in SHA256SUMS." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local iso_path="$DOWNLOAD_DIR/$iso_name"
|
||||
|
||||
if [[ -f "$iso_path" ]]; then
|
||||
echo "ISO already exists, verifying checksum..."
|
||||
local actual_hash
|
||||
actual_hash=$(shasum -a 256 "$iso_path" | awk '{print $1}')
|
||||
if [[ "$actual_hash" == "$expected_hash" ]]; then
|
||||
echo "Checksum OK. Skipping download."
|
||||
echo " $iso_path"
|
||||
return
|
||||
fi
|
||||
echo "Checksum mismatch, re-downloading..."
|
||||
fi
|
||||
|
||||
echo "Downloading $iso_name..."
|
||||
curl -C - -fL -o "$iso_path" "$BASE_URL/$iso_name"
|
||||
|
||||
echo "Verifying checksum..."
|
||||
local actual_hash
|
||||
actual_hash=$(shasum -a 256 "$iso_path" | awk '{print $1}')
|
||||
if [[ "$actual_hash" != "$expected_hash" ]]; then
|
||||
echo "Error: Checksum verification failed." >&2
|
||||
echo " Expected: $expected_hash" >&2
|
||||
echo " Got: $actual_hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checksum OK."
|
||||
echo " $iso_path"
|
||||
}
|
||||
|
||||
cmd_build() {
|
||||
if ! command -v xorriso &>/dev/null; then
|
||||
echo "Error: xorriso not found." >&2
|
||||
echo "Install it with: brew install xorriso" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Find source ISO
|
||||
local src_iso
|
||||
src_iso=$(find "$DOWNLOAD_DIR" -maxdepth 1 -name 'debian-*-amd64-DVD-1.iso' -print -quit 2>/dev/null || true)
|
||||
if [[ -z "$src_iso" || ! -f "$src_iso" ]]; then
|
||||
echo "Error: No Debian DVD-1 ISO found in $DOWNLOAD_DIR" >&2
|
||||
echo "Run 'yino-iso download' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Source ISO: $src_iso"
|
||||
|
||||
# Create temp working directory (not local — trap needs access after function returns)
|
||||
work_dir=$(mktemp -d "${TMPDIR:-/tmp}/yino-iso.XXXXXX")
|
||||
trap 'rm -rf "$work_dir"' EXIT
|
||||
|
||||
local extract_dir="$work_dir/iso"
|
||||
|
||||
# Extract ISO
|
||||
echo "Extracting ISO..."
|
||||
xorriso -osirrox on -indev "$src_iso" -extract / "$extract_dir"
|
||||
chmod -R u+w "$extract_dir"
|
||||
|
||||
# Inject preseed into initrd
|
||||
echo "Injecting preseed into initrd..."
|
||||
gunzip "$extract_dir/install.amd/initrd.gz"
|
||||
(cd "$ISO_DIR" && echo preseed.cfg | cpio -o --format newc) >> "$extract_dir/install.amd/initrd"
|
||||
gzip "$extract_dir/install.amd/initrd"
|
||||
|
||||
# Modify boot configs — add preseed boot parameters
|
||||
local boot_params="auto=true priority=critical locale=en_US.UTF-8 keymap=us console=ttyS0,115200n8"
|
||||
|
||||
echo "Modifying boot configuration..."
|
||||
|
||||
# Insert preseed params before the "---" separator in boot entries
|
||||
if [[ -f "$extract_dir/isolinux/txt.cfg" ]]; then
|
||||
sed -i.bak "s|--- |${boot_params} --- |" "$extract_dir/isolinux/txt.cfg"
|
||||
rm -f "$extract_dir/isolinux/txt.cfg.bak"
|
||||
# Set text installer as default boot entry (prepend with proper newline)
|
||||
{ echo "default install"; cat "$extract_dir/isolinux/txt.cfg"; } > "$extract_dir/isolinux/txt.cfg.tmp"
|
||||
mv "$extract_dir/isolinux/txt.cfg.tmp" "$extract_dir/isolinux/txt.cfg"
|
||||
fi
|
||||
|
||||
# Fix isolinux: enable serial console, disable graphical menu, set short timeout
|
||||
if [[ -f "$extract_dir/isolinux/isolinux.cfg" ]]; then
|
||||
# Prepend serial directive (BSD sed '1i' doesn't insert newlines reliably)
|
||||
{ echo "serial 0 115200"; cat "$extract_dir/isolinux/isolinux.cfg"; } > "$extract_dir/isolinux/isolinux.cfg.tmp"
|
||||
mv "$extract_dir/isolinux/isolinux.cfg.tmp" "$extract_dir/isolinux/isolinux.cfg"
|
||||
sed -i.bak 's|^default vesamenu.c32|#default vesamenu.c32|' "$extract_dir/isolinux/isolinux.cfg"
|
||||
rm -f "$extract_dir/isolinux/isolinux.cfg.bak"
|
||||
sed -i.bak 's|^timeout .*|timeout 50|' "$extract_dir/isolinux/isolinux.cfg"
|
||||
rm -f "$extract_dir/isolinux/isolinux.cfg.bak"
|
||||
fi
|
||||
|
||||
if [[ -f "$extract_dir/boot/grub/grub.cfg" ]]; then
|
||||
sed -i.bak "s|--- |${boot_params} --- |" "$extract_dir/boot/grub/grub.cfg"
|
||||
rm -f "$extract_dir/boot/grub/grub.cfg.bak"
|
||||
# Add serial console support to GRUB and select text "Install" entry (index 1)
|
||||
sed -i.bak 's|terminal_output gfxterm|terminal_output gfxterm serial|' "$extract_dir/boot/grub/grub.cfg"
|
||||
rm -f "$extract_dir/boot/grub/grub.cfg.bak"
|
||||
{ printf 'serial --unit=0 --speed=115200\nterminal_input serial console\nterminal_output serial console\nset timeout=5\nset default=1\n'; cat "$extract_dir/boot/grub/grub.cfg"; } > "$extract_dir/boot/grub/grub.cfg.tmp"
|
||||
mv "$extract_dir/boot/grub/grub.cfg.tmp" "$extract_dir/boot/grub/grub.cfg"
|
||||
fi
|
||||
|
||||
# Extract MBR template for hybrid boot
|
||||
echo "Extracting MBR template..."
|
||||
local mbr_template="$work_dir/isohdpfx.bin"
|
||||
dd if="$src_iso" bs=1 count=432 of="$mbr_template" 2>/dev/null
|
||||
|
||||
# Regenerate checksums
|
||||
echo "Regenerating checksums..."
|
||||
(cd "$extract_dir" && find . -type f ! -name 'md5sum.txt' -exec md5sum {} + > md5sum.txt)
|
||||
|
||||
# Rebuild ISO
|
||||
local output_iso="$DOWNLOAD_DIR/yino-$(date +%Y%m%d).iso"
|
||||
echo "Building ISO..."
|
||||
xorriso -as mkisofs \
|
||||
-r -V "Yino" \
|
||||
-o "$output_iso" \
|
||||
-J -joliet-long \
|
||||
-isohybrid-mbr "$mbr_template" \
|
||||
-partition_offset 16 \
|
||||
-b isolinux/isolinux.bin \
|
||||
-c isolinux/boot.cat \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
-eltorito-alt-boot \
|
||||
-e boot/grub/efi.img \
|
||||
-no-emul-boot \
|
||||
-isohybrid-gpt-basdat \
|
||||
"$extract_dir"
|
||||
|
||||
echo "Done."
|
||||
echo " $output_iso"
|
||||
}
|
||||
|
||||
cmd_clean() {
|
||||
local yino_isos
|
||||
yino_isos=$(find "$DOWNLOAD_DIR" -maxdepth 1 -name 'yino-*.iso' 2>/dev/null || true)
|
||||
|
||||
if [[ -z "$yino_isos" ]]; then
|
||||
echo "Nothing to clean."
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Removing built ISOs:"
|
||||
while read -r f; do
|
||||
echo " $f"
|
||||
rm "$f"
|
||||
done <<< "$yino_isos"
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
cat <<'EOF'
|
||||
Usage: yino-iso <command>
|
||||
|
||||
Commands:
|
||||
download Download Debian 13 DVD-1 ISO and verify checksum
|
||||
build Build custom Yino ISO with preseed
|
||||
clean Remove built ISOs
|
||||
help Show this help
|
||||
|
||||
Dependencies (macOS):
|
||||
brew install xorriso
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
|
||||
case "${1:-help}" in
|
||||
download) cmd_download ;;
|
||||
build) cmd_build ;;
|
||||
clean) cmd_clean ;;
|
||||
help|--help|-h) cmd_help ;;
|
||||
*)
|
||||
echo "Error: Unknown command: $1" >&2
|
||||
cmd_help >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
306
bin/yino-vm
306
bin/yino-vm
@ -1,306 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
VM_DIR="$(cd "$(dirname "$0")/.." && pwd)/vm"
|
||||
DISK_IMAGE="$VM_DIR/yino-vm.qcow2"
|
||||
UEFI_VARS="$VM_DIR/yino-vm-vars.fd"
|
||||
HOST_OS=$(uname -s) # Darwin or Linux
|
||||
HOST_ARCH=$(uname -m) # arm64 or x86_64
|
||||
|
||||
# --- Platform-aware install hints ---
|
||||
|
||||
install_hint() {
|
||||
if [[ "$HOST_OS" == "Darwin" ]]; then
|
||||
echo "Install it with: brew install qemu" >&2
|
||||
else
|
||||
echo "Install it with: sudo apt install qemu-system-x86 ovmf" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# --- OVMF firmware discovery ---
|
||||
|
||||
find_ovmf_code() {
|
||||
local paths=()
|
||||
if [[ "$HOST_OS" == "Darwin" ]]; then
|
||||
paths=(
|
||||
/opt/homebrew/share/qemu/edk2-x86_64-code.fd
|
||||
/usr/local/share/qemu/edk2-x86_64-code.fd
|
||||
)
|
||||
else
|
||||
paths=(
|
||||
/usr/share/OVMF/OVMF_CODE_4M.fd
|
||||
/usr/share/OVMF/OVMF_CODE.fd
|
||||
/usr/share/qemu/OVMF_CODE_4M.fd
|
||||
/usr/share/qemu/OVMF_CODE.fd
|
||||
/usr/share/edk2/x64/OVMF_CODE.fd
|
||||
)
|
||||
fi
|
||||
for p in "${paths[@]}"; do
|
||||
[[ -f "$p" ]] && echo "$p" && return
|
||||
done
|
||||
if [[ "$HOST_OS" == "Darwin" ]]; then
|
||||
local cellar_dirs=(/opt/homebrew/Cellar/qemu /usr/local/Cellar/qemu)
|
||||
for d in "${cellar_dirs[@]}"; do
|
||||
if [[ -d "$d" ]]; then
|
||||
local found
|
||||
found=$(find "$d" -name 'edk2-x86_64-code.fd' -print -quit 2>/dev/null)
|
||||
[[ -n "$found" ]] && echo "$found" && return
|
||||
fi
|
||||
done
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
find_ovmf_vars_template() {
|
||||
local paths=()
|
||||
if [[ "$HOST_OS" == "Darwin" ]]; then
|
||||
paths=(
|
||||
/opt/homebrew/share/qemu/edk2-i386-vars.fd
|
||||
/usr/local/share/qemu/edk2-i386-vars.fd
|
||||
)
|
||||
else
|
||||
paths=(
|
||||
/usr/share/OVMF/OVMF_VARS_4M.fd
|
||||
/usr/share/OVMF/OVMF_VARS.fd
|
||||
/usr/share/qemu/OVMF_VARS_4M.fd
|
||||
/usr/share/qemu/OVMF_VARS.fd
|
||||
/usr/share/edk2/x64/OVMF_VARS.fd
|
||||
)
|
||||
fi
|
||||
for p in "${paths[@]}"; do
|
||||
[[ -f "$p" ]] && echo "$p" && return
|
||||
done
|
||||
if [[ "$HOST_OS" == "Darwin" ]]; then
|
||||
local cellar_dirs=(/opt/homebrew/Cellar/qemu /usr/local/Cellar/qemu)
|
||||
for d in "${cellar_dirs[@]}"; do
|
||||
if [[ -d "$d" ]]; then
|
||||
local found
|
||||
found=$(find "$d" -name 'edk2-i386-vars.fd' -print -quit 2>/dev/null)
|
||||
[[ -n "$found" ]] && echo "$found" && return
|
||||
fi
|
||||
done
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# --- CPU/accelerator auto-detection ---
|
||||
|
||||
detect_accel() {
|
||||
if [[ "$HOST_OS" == "Linux" && "$HOST_ARCH" == "x86_64" ]]; then
|
||||
if [[ -w /dev/kvm ]]; then
|
||||
echo "kvm"
|
||||
else
|
||||
echo "Warning: /dev/kvm not accessible. Install KVM and check permissions." >&2
|
||||
echo " sudo apt install qemu-kvm && sudo usermod -aG kvm \$USER" >&2
|
||||
echo "tcg"
|
||||
fi
|
||||
elif [[ "$HOST_OS" == "Darwin" && "$HOST_ARCH" == "x86_64" ]]; then
|
||||
echo "hvf"
|
||||
else
|
||||
echo "tcg"
|
||||
fi
|
||||
}
|
||||
|
||||
detect_cpu() {
|
||||
local accel="$1"
|
||||
if [[ "$accel" == "kvm" || "$accel" == "hvf" ]]; then
|
||||
echo "host"
|
||||
else
|
||||
echo "qemu64"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Subcommands ---
|
||||
|
||||
cmd_create() {
|
||||
if ! command -v qemu-system-x86_64 &>/dev/null; then
|
||||
echo "Error: qemu-system-x86_64 not found." >&2
|
||||
install_hint
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "$DISK_IMAGE" ]]; then
|
||||
echo "Error: Disk image already exists: $DISK_IMAGE" >&2
|
||||
echo "Run 'yino-vm delete' first to remove it." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local vars_template
|
||||
if ! vars_template=$(find_ovmf_vars_template); then
|
||||
echo "Error: OVMF vars template not found." >&2
|
||||
install_hint
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating 30G sparse disk image..."
|
||||
qemu-img create -f qcow2 "$DISK_IMAGE" 30G
|
||||
|
||||
echo "Copying UEFI vars template..."
|
||||
cp "$vars_template" "$UEFI_VARS"
|
||||
|
||||
echo "VM created:"
|
||||
echo " Disk: $DISK_IMAGE"
|
||||
echo " UEFI vars: $UEFI_VARS"
|
||||
}
|
||||
|
||||
cmd_boot() {
|
||||
if ! command -v qemu-system-x86_64 &>/dev/null; then
|
||||
echo "Error: qemu-system-x86_64 not found." >&2
|
||||
install_hint
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$DISK_IMAGE" ]]; then
|
||||
echo "Error: Disk image not found: $DISK_IMAGE" >&2
|
||||
echo "Run 'yino-vm create' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local ovmf_code
|
||||
if ! ovmf_code=$(find_ovmf_code); then
|
||||
echo "Error: OVMF firmware not found." >&2
|
||||
install_hint
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$UEFI_VARS" ]]; then
|
||||
echo "Error: UEFI vars not found: $UEFI_VARS" >&2
|
||||
echo "Run 'yino-vm create' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local accel cpu
|
||||
accel=$(detect_accel)
|
||||
cpu=$(detect_cpu "$accel")
|
||||
|
||||
if [[ "$accel" == "tcg" ]]; then
|
||||
echo "Warning: Running x86_64 VM under TCG emulation — significantly slower"
|
||||
echo "than hardware virtualization (KVM on Linux, HVF on Intel Mac)."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
local iso_args=()
|
||||
local serial=false
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--serial)
|
||||
serial=true
|
||||
shift
|
||||
;;
|
||||
--iso)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
echo "Error: --iso requires a path argument." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$2" ]]; then
|
||||
echo "Error: ISO file not found: $2" >&2
|
||||
exit 1
|
||||
fi
|
||||
iso_args=(-drive "file=$2,media=cdrom,readonly=on" -boot d)
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown option: $1" >&2
|
||||
echo "Usage: yino-vm boot [--serial] [--iso PATH]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local display_args
|
||||
if [[ "$serial" == true ]]; then
|
||||
display_args=(-serial mon:stdio -nographic -display none)
|
||||
elif [[ "$HOST_OS" == "Darwin" ]]; then
|
||||
display_args=(-display cocoa -vga virtio)
|
||||
else
|
||||
display_args=(-display gtk -vga virtio)
|
||||
fi
|
||||
|
||||
echo "Booting VM (accel=$accel, cpu=$cpu)..."
|
||||
if [[ "$serial" != true ]]; then
|
||||
echo "SSH available at: ssh -p 2222 localhost"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
qemu-system-x86_64 \
|
||||
-machine q35 \
|
||||
-accel "$accel" \
|
||||
-cpu "$cpu" \
|
||||
-m 4G \
|
||||
-smp 2 \
|
||||
-drive "file=$DISK_IMAGE,if=virtio,cache=writeback" \
|
||||
-drive "if=pflash,format=raw,readonly=on,file=$ovmf_code" \
|
||||
-drive "if=pflash,format=raw,file=$UEFI_VARS" \
|
||||
-device virtio-net-pci,netdev=net0 \
|
||||
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
|
||||
"${display_args[@]}" \
|
||||
"${iso_args[@]}"
|
||||
}
|
||||
|
||||
cmd_delete() {
|
||||
if [[ ! -f "$DISK_IMAGE" && ! -f "$UEFI_VARS" ]]; then
|
||||
echo "Nothing to delete — no VM files found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "This will delete:"
|
||||
[[ -f "$DISK_IMAGE" ]] && echo " $DISK_IMAGE"
|
||||
[[ -f "$UEFI_VARS" ]] && echo " $UEFI_VARS"
|
||||
echo ""
|
||||
read -rp "Are you sure? [y/N] " confirm
|
||||
if [[ "$confirm" != [yY] ]]; then
|
||||
echo "Cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[[ -f "$DISK_IMAGE" ]] && rm "$DISK_IMAGE" && echo "Removed $DISK_IMAGE"
|
||||
[[ -f "$UEFI_VARS" ]] && rm "$UEFI_VARS" && echo "Removed $UEFI_VARS"
|
||||
echo "VM deleted."
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
echo "VM directory: $VM_DIR"
|
||||
echo ""
|
||||
if [[ -f "$DISK_IMAGE" ]]; then
|
||||
local size
|
||||
size=$(qemu-img info --output=json "$DISK_IMAGE" 2>/dev/null \
|
||||
| python3 -c "import sys,json; d=json.load(sys.stdin); print(f\"virtual: {d['virtual-size']/(1<<30):.0f}G, actual: {d['actual-size']/(1<<20):.1f}M\")" 2>/dev/null \
|
||||
|| echo "present")
|
||||
echo "Disk image: $size"
|
||||
else
|
||||
echo "Disk image: not created"
|
||||
fi
|
||||
if [[ -f "$UEFI_VARS" ]]; then
|
||||
echo "UEFI vars: present"
|
||||
else
|
||||
echo "UEFI vars: not created"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
cat <<'EOF'
|
||||
Usage: yino-vm <command> [options]
|
||||
|
||||
Commands:
|
||||
create Create VM disk image and UEFI vars
|
||||
boot [opts] Boot the VM (--serial for console, --iso P for installer)
|
||||
delete Delete VM disk image and UEFI vars
|
||||
status Show VM status
|
||||
help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
|
||||
case "${1:-help}" in
|
||||
create) cmd_create ;;
|
||||
boot) shift; cmd_boot "$@" ;;
|
||||
delete) cmd_delete ;;
|
||||
status) cmd_status ;;
|
||||
help|--help|-h) cmd_help ;;
|
||||
*)
|
||||
echo "Error: Unknown command: $1" >&2
|
||||
cmd_help >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@ -1,7 +1,5 @@
|
||||
# Omarchy Analysis
|
||||
|
||||
> **Last analyzed:** 2026-02-16 · basecamp/omarchy @ `463417a` (`dev` branch)
|
||||
|
||||
A comprehensive reference document analyzing the upstream Omarchy project and its ecosystem, serving as a
|
||||
blueprint for the Yino (Debian-based) port.
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
| Version | 1.0 |
|
||||
| Status | Draft |
|
||||
| Created | 2026-02-15 |
|
||||
| Updated | 2026-02-20 |
|
||||
| Updated | 2026-02-15 |
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
@ -23,11 +23,10 @@ instead of Arch Linux.
|
||||
- Remove anything that can be removed that has been added to Omarchy in order to deal with its possibly unstable,
|
||||
rolling release base of Arch Linux
|
||||
- Just like Omarchy, produce an ISO image that can perform a complete offline installation of Yino
|
||||
- Maintain ongoing feature parity by tracking upstream Omarchy development and porting relevant changes
|
||||
|
||||
## 3. Architecture
|
||||
|
||||
This should match Omarchy's architecture (see [Omarchy Analysis](Omarchy.md) for a comprehensive reference)
|
||||
This should match Omarchy's architecture
|
||||
|
||||
- Debian Linux as a base
|
||||
- Btrfs filesystem
|
||||
@ -40,9 +39,6 @@ This should match Omarchy's architecture (see [Omarchy Analysis](Omarchy.md) for
|
||||
|
||||
## 4. Design principles
|
||||
|
||||
- **Match upstream Omarchy** — Yino should replicate Omarchy's architecture, component choices, and conventions as
|
||||
closely as possible, substituting only what is strictly necessary for Debian compatibility. When multiple approaches
|
||||
exist, prefer the one Omarchy uses. When in doubt, ask the owner before deviating.
|
||||
- Version control (git) must be used
|
||||
- Less is more, minimize dependencies, avoid pulling in extra dependencies, always talk through with owner first
|
||||
- Keep it simple, KISS principle applies
|
||||
@ -53,23 +49,4 @@ This should match Omarchy's architecture (see [Omarchy Analysis](Omarchy.md) for
|
||||
- QEMU should be used for testing and demo virtual machines
|
||||
- Keep a cache of downloaded assets (e.g. Debian installation ISO) in this repository's `download` directory
|
||||
|
||||
## 6. Offline installation ISO
|
||||
|
||||
This project should generate the tooling necessary to create a modified, offline installation ISO.
|
||||
It should do this by downloading and caching the Debian iso-dvd image, extract it and apply the necessary
|
||||
modifications to enable an unattended installation with the following characteristics (similiar to
|
||||
how archinstall doest it):
|
||||
|
||||
- LUKS + btrfs
|
||||
- System for a single user, automatic login because full disk decryption already authenticates user
|
||||
- Graphical Wayland environment, no X11
|
||||
|
||||
## 7. Upstream tracking
|
||||
|
||||
- Track the upstream [basecamp/omarchy](https://github.com/basecamp/omarchy) repository for new releases and changes
|
||||
- Omarchy's `dev` branch is where active development happens; `master` is the stable branch
|
||||
- Evaluate new Omarchy releases and port applicable changes to Yino
|
||||
- Keep the [Omarchy Analysis](Omarchy.md) document up to date as upstream evolves
|
||||
- Translate Arch-specific changes to their Debian equivalents per the package and command mapping in [Omarchy Analysis](Omarchy.md) section 14
|
||||
|
||||
## 7. Changelog
|
||||
## 6. Changelog
|
||||
|
||||
120
iso/preseed.cfg
120
iso/preseed.cfg
@ -1,120 +0,0 @@
|
||||
# Yino preseed configuration for Debian 13 (Trixie)
|
||||
# Fully unattended install with hardcoded test credentials.
|
||||
# TODO: For production, remove hardcoded passwords and prompt interactively.
|
||||
|
||||
# Locale and keyboard
|
||||
d-i debian-installer/locale string en_US.UTF-8
|
||||
d-i keyboard-configuration/xkb-keymap select us
|
||||
|
||||
# Network — DHCP (needed to pull Hyprland from sid)
|
||||
d-i netcfg/enable boolean true
|
||||
d-i netcfg/choose_interface select auto
|
||||
d-i netcfg/get_hostname string yino
|
||||
d-i netcfg/get_domain string local
|
||||
d-i netcfg/hostname string yino
|
||||
|
||||
# Mirror — Debian archive (needed for Hyprland from sid)
|
||||
d-i apt-setup/use_mirror boolean true
|
||||
d-i mirror/country string manual
|
||||
d-i mirror/http/hostname string deb.debian.org
|
||||
d-i mirror/http/directory string /debian
|
||||
d-i mirror/http/proxy string
|
||||
|
||||
# Clock
|
||||
d-i clock-setup/utc boolean true
|
||||
d-i time/zone string UTC
|
||||
|
||||
# LUKS encryption passphrase (hardcoded for dev/test)
|
||||
d-i partman-crypto/passphrase string yinoyino
|
||||
d-i partman-crypto/passphrase-again string yinoyino
|
||||
d-i partman-crypto/weak_passphrase boolean true
|
||||
|
||||
# Partitioning — encrypted LVM with btrfs root
|
||||
d-i partman-auto/method string crypto
|
||||
d-i partman-lvm/device_remove_lvm boolean true
|
||||
d-i partman-md/device_remove_md boolean true
|
||||
d-i partman-lvm/confirm boolean true
|
||||
d-i partman-lvm/confirm_nooverwrite boolean true
|
||||
d-i partman-auto-lvm/guided_size string max
|
||||
d-i partman-auto-crypto/erase_disks boolean false
|
||||
d-i partman/default_filesystem string btrfs
|
||||
d-i partman-auto/choose_recipe select atomic
|
||||
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||
d-i partman/choose_partition select finish
|
||||
d-i partman/confirm boolean true
|
||||
d-i partman/confirm_nooverwrite boolean true
|
||||
|
||||
# User account (hardcoded for dev/test)
|
||||
d-i passwd/root-login boolean false
|
||||
d-i passwd/user-fullname string Yino User
|
||||
d-i passwd/username string yino
|
||||
d-i passwd/user-password string yinoyino
|
||||
d-i passwd/user-password-again string yinoyino
|
||||
d-i user-setup/allow-password-weak boolean true
|
||||
|
||||
# Packages — minimal base + essentials
|
||||
tasksel tasksel/first multiselect standard
|
||||
d-i pkgsel/include string sudo btrfs-progs
|
||||
|
||||
# Don't eject CD (fails in QEMU, causes prompt loop)
|
||||
d-i cdrom-detect/eject boolean false
|
||||
|
||||
# Skip upgrade check (offline install, nothing to upgrade)
|
||||
d-i pkgsel/upgrade select none
|
||||
|
||||
# No security/updates services (offline)
|
||||
d-i apt-setup/services-select multiselect
|
||||
|
||||
# No popularity contest
|
||||
popularity-contest popularity-contest/participate boolean false
|
||||
|
||||
# GRUB
|
||||
d-i grub-installer/only_debian boolean true
|
||||
d-i grub-installer/bootdev string default
|
||||
|
||||
# Skip additional media scan
|
||||
d-i apt-setup/cdrom/set-first boolean false
|
||||
d-i apt-setup/cdrom/set-next boolean false
|
||||
d-i apt-setup/cdrom/set-failed boolean false
|
||||
|
||||
# Skip media integrity check (blocks unattended install)
|
||||
d-i cdrom-checker/start boolean false
|
||||
|
||||
# Finish
|
||||
d-i finish-install/reboot_in_progress note
|
||||
|
||||
# Post-install: configure serial console, SDDM + UWSM + Hyprland desktop
|
||||
d-i preseed/late_command string \
|
||||
USER=$(grep ':x:1000:' /target/etc/passwd | cut -d: -f1); \
|
||||
LOG=/target/var/log/yino-late-command.log; \
|
||||
echo "=== Yino late_command start ===" > $LOG; \
|
||||
echo "USER=$USER" >> $LOG; \
|
||||
echo "--- GRUB serial console ---" >> $LOG; \
|
||||
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="quiet"/' /target/etc/default/grub; \
|
||||
sed -i 's/^GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty0"/' /target/etc/default/grub; \
|
||||
echo 'GRUB_TERMINAL="serial console"' >> /target/etc/default/grub; \
|
||||
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >> /target/etc/default/grub; \
|
||||
in-target update-grub >> $LOG 2>&1; \
|
||||
echo "--- DNS setup ---" >> $LOG; \
|
||||
echo "nameserver 1.1.1.1" > /target/etc/resolv.conf; \
|
||||
echo "--- sid repo ---" >> $LOG; \
|
||||
echo 'deb http://deb.debian.org/debian sid main contrib non-free-firmware' > /target/etc/apt/sources.list.d/sid.list; \
|
||||
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 100\n' > /target/etc/apt/preferences.d/sid-low-priority; \
|
||||
echo "--- apt-get update ---" >> $LOG; \
|
||||
in-target apt-get update >> $LOG 2>&1 || echo "FAILED: apt-get update (exit $?)" >> $LOG; \
|
||||
echo "--- install sddm ---" >> $LOG; \
|
||||
in-target env DEBIAN_FRONTEND=noninteractive apt-get -y install sddm >> $LOG 2>&1 || echo "FAILED: install sddm (exit $?)" >> $LOG; \
|
||||
echo "--- install hyprland uwsm foot ---" >> $LOG; \
|
||||
in-target env DEBIAN_FRONTEND=noninteractive apt-get -y -t unstable install hyprland uwsm foot >> $LOG 2>&1 || echo "FAILED: install hyprland (exit $?)" >> $LOG; \
|
||||
echo "--- SDDM config ---" >> $LOG; \
|
||||
mkdir -p /target/etc/sddm.conf.d; \
|
||||
printf '[Autologin]\nUser=%s\nSession=hyprland-uwsm\n\n[Theme]\nCurrent=breeze\n' "$USER" > /target/etc/sddm.conf.d/autologin.conf; \
|
||||
in-target systemctl enable sddm >> $LOG 2>&1 || echo "FAILED: enable sddm" >> $LOG; \
|
||||
mkdir -p /target/usr/share/wayland-sessions; \
|
||||
printf '[Desktop Entry]\nName=Hyprland (UWSM)\nComment=Hyprland via Universal Wayland Session Manager\nExec=uwsm start hyprland.desktop\nType=Application\nDesktopNames=Hyprland\n' > /target/usr/share/wayland-sessions/hyprland-uwsm.desktop; \
|
||||
echo "--- Hyprland config ---" >> $LOG; \
|
||||
UHOME=/target/home/$USER; \
|
||||
mkdir -p $UHOME/.config/hyprland; \
|
||||
printf 'monitor = ,preferred,auto,1\n\nenv = WLR_NO_HARDWARE_CURSORS,1\nenv = WLR_RENDERER_ALLOW_SOFTWARE,1\n\nexec-once = foot --server\n\n$mainMod = SUPER\n\nbind = $mainMod, Return, exec, foot\nbind = $mainMod SHIFT, Q, killactive\nbind = $mainMod SHIFT, E, exit\n\nbind = $mainMod, 1, workspace, 1\nbind = $mainMod, 2, workspace, 2\nbind = $mainMod, 3, workspace, 3\nbind = $mainMod, 4, workspace, 4\nbind = $mainMod, 5, workspace, 5\n\nbind = $mainMod, left, movefocus, l\nbind = $mainMod, right, movefocus, r\nbind = $mainMod, up, movefocus, u\nbind = $mainMod, down, movefocus, d\n' > $UHOME/.config/hyprland/hyprland.conf; \
|
||||
chown -R 1000:1000 $UHOME/.config; \
|
||||
echo "=== Yino late_command done ===" >> $LOG
|
||||
Loading…
x
Reference in New Issue
Block a user