1st successful iso build from bootc-native script
This commit is contained in:
parent
ec1a4f9e01
commit
80499e2acc
8 changed files with 1349 additions and 472 deletions
1
Dockerfile.noble
Normal file
1
Dockerfile.noble
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Built ParticleOS with a 24.04 base
|
||||
1
Dockerfile.plucky
Normal file
1
Dockerfile.plucky
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Build ParticleOS with a 25.04 base
|
||||
1
Dockerfile.questing
Normal file
1
Dockerfile.questing
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Build ParticleOS with a 25.10 base
|
||||
768
build-iso-bootc-hybrid.sh
Executable file
768
build-iso-bootc-hybrid.sh
Executable file
|
|
@ -0,0 +1,768 @@
|
|||
#!/bin/bash
|
||||
|
||||
# ParticleOS ISO Builder - Pure bootc Approach
|
||||
# Uses bootc for the entire build process, no mmdebstrap needed
|
||||
# This is the true "bootc + xorriso" approach
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Enable logging with timestamped directory
|
||||
BUILD_TIMESTAMP=$(date +"%y%m%d%H%M")
|
||||
LOG_DIR="logs/${BUILD_TIMESTAMP}"
|
||||
mkdir -p "$LOG_DIR"
|
||||
LOG_FILE="$LOG_DIR/build-iso-bootc-native.log"
|
||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||
|
||||
echo "$(date): Starting ParticleOS ISO build with pure bootc approach"
|
||||
echo "$(date): Log directory: $LOG_DIR"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_header() {
|
||||
echo ""
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
}
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_NAME="particleos"
|
||||
VERSION="1.0.0"
|
||||
BUILD_TIMESTAMP=$(date +"%y%m%d-%H%M")
|
||||
BUILD_DIR="$SCRIPT_DIR/build"
|
||||
OUTPUT_DIR="$SCRIPT_DIR/output"
|
||||
CONTAINER_NAME="particleos-builder"
|
||||
SYSTEM_IMAGE="particleos-system.oci"
|
||||
|
||||
# apt-cacher-ng configuration
|
||||
APT_CACHER_NG_HOST="192.168.1.79"
|
||||
APT_CACHER_NG_PORT="3142"
|
||||
APT_CACHER_NG_URL="http://${APT_CACHER_NG_HOST}:${APT_CACHER_NG_PORT}"
|
||||
|
||||
# Variables to track cacher usage
|
||||
CACHER_CONTAINER_BUILD_USED="No (Fallback to direct)"
|
||||
|
||||
# Safety check: Ensure BUILD_DIR is within SCRIPT_DIR
|
||||
if [[ ! "$BUILD_DIR" =~ ^"$SCRIPT_DIR" ]]; then
|
||||
print_error "BUILD_DIR ($BUILD_DIR) is not within SCRIPT_DIR ($SCRIPT_DIR). Aborting for safety."
|
||||
fi
|
||||
|
||||
# Check if apt-cacher-ng is reachable
|
||||
check_proxy_reachable() {
|
||||
print_status "Checking if apt-cacher-ng at $APT_CACHER_NG_HOST:$APT_CACHER_NG_PORT is reachable..."
|
||||
# Use netcat to check if the port is open
|
||||
if nc -zv "$APT_CACHER_NG_HOST" "$APT_CACHER_NG_PORT" &>/dev/null; then
|
||||
print_success "apt-cacher-ng at $APT_CACHER_NG_HOST:$APT_CACHER_NG_PORT is reachable."
|
||||
return 0 # Reachable
|
||||
else
|
||||
print_warning "apt-cacher-ng at $APT_CACHER_NG_HOST:$APT_CACHER_NG_PORT is NOT reachable."
|
||||
return 1 # Not reachable
|
||||
fi
|
||||
}
|
||||
|
||||
# Check prerequisites
|
||||
check_prerequisites() {
|
||||
print_header "Phase 1: Check Prerequisites"
|
||||
|
||||
# Check for bootc
|
||||
if ! command -v bootc &> /dev/null; then
|
||||
print_error "bootc is not installed. Please install bootc first."
|
||||
fi
|
||||
|
||||
# Check for podman
|
||||
if ! command -v podman &> /dev/null; then
|
||||
print_error "podman is not installed. Please install podman first."
|
||||
fi
|
||||
|
||||
# Check for build tools
|
||||
local missing_packages=()
|
||||
for package in squashfs-tools xorriso grub-pc-bin grub-efi-amd64-bin isolinux syslinux-common netcat-openbsd; do
|
||||
if ! dpkg -s "$package" &>/dev/null; then
|
||||
missing_packages+=("$package")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_packages[@]} -gt 0 ]; then
|
||||
print_status "Installing missing packages: ${missing_packages[*]}"
|
||||
sudo apt update
|
||||
sudo apt install -y "${missing_packages[@]}"
|
||||
fi
|
||||
|
||||
# Check for casper (required for live boot)
|
||||
if ! dpkg -s casper &>/dev/null; then
|
||||
print_status "Installing casper (required for live boot)..."
|
||||
sudo apt update
|
||||
sudo apt install -y casper
|
||||
fi
|
||||
|
||||
# Check disk space (need at least 10GB free)
|
||||
local available_space=$(df "$SCRIPT_DIR" | awk 'NR==2 {print $4}')
|
||||
local required_space=$((10 * 1024 * 1024)) # 10GB in KB
|
||||
|
||||
if [ "$available_space" -lt "$required_space" ]; then
|
||||
print_error "Insufficient disk space. Need at least 10GB free, have $(($available_space / 1024 / 1024))GB"
|
||||
fi
|
||||
|
||||
# Check network connectivity
|
||||
if ! ping -c 1 archive.ubuntu.com &>/dev/null; then
|
||||
print_error "Cannot reach Ubuntu archives. Check your internet connection."
|
||||
fi
|
||||
|
||||
print_success "All prerequisites satisfied"
|
||||
}
|
||||
|
||||
# Clean build environment
|
||||
clean_build() {
|
||||
print_header "Phase 2: Clean Build Environment"
|
||||
|
||||
# Clean build directories
|
||||
if [ -d "$BUILD_DIR" ]; then
|
||||
print_status "Removing previous build directory: $BUILD_DIR..."
|
||||
if [[ "$BUILD_DIR" == "/" ]] || [[ "$BUILD_DIR" == "/home" ]] || [[ "$BUILD_DIR" == "/opt" ]] || \
|
||||
[[ "$BUILD_DIR" == "/usr" ]] || [[ "$BUILD_DIR" == "/var" ]] || [[ "$BUILD_DIR" == "/etc" ]]; then
|
||||
print_error "BUILD_DIR ($BUILD_DIR) is a critical system directory. Aborting for safety."
|
||||
fi
|
||||
|
||||
# Force remove any existing container first
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
print_status "Removing existing container: $CONTAINER_NAME"
|
||||
podman container rm -f "$CONTAINER_NAME" 2>/dev/null || print_warning "Failed to remove container"
|
||||
fi
|
||||
|
||||
# Force remove any existing images
|
||||
if podman image exists "$SYSTEM_IMAGE" 2>/dev/null; then
|
||||
print_status "Removing existing image: $SYSTEM_IMAGE"
|
||||
podman image rm -f "$SYSTEM_IMAGE" 2>/dev/null || print_warning "Failed to remove image"
|
||||
fi
|
||||
|
||||
sudo rm -rf "$BUILD_DIR" || print_error "Failed to remove previous build directory."
|
||||
fi
|
||||
|
||||
mkdir -p "$BUILD_DIR" "$OUTPUT_DIR" || print_error "Failed to create build directories."
|
||||
chmod 755 "$OUTPUT_DIR" || print_error "Failed to set permissions on output directory."
|
||||
print_success "Build environment cleaned"
|
||||
}
|
||||
|
||||
# Create bootc system definition
|
||||
create_bootc_definition() {
|
||||
print_header "Phase 3: Create bootc System Definition"
|
||||
|
||||
print_status "Creating bootc system definition..."
|
||||
|
||||
# Create a bootc-compatible system definition
|
||||
cat > "$BUILD_DIR/particleos-system.yaml" << 'EOF'
|
||||
# ParticleOS System Definition for bootc
|
||||
apiVersion: v1
|
||||
kind: Image
|
||||
metadata:
|
||||
name: particleos-desktop
|
||||
version: "1.0.0"
|
||||
spec:
|
||||
os:
|
||||
name: ubuntu
|
||||
version: "24.04"
|
||||
packages:
|
||||
- name: ubuntu-minimal
|
||||
- name: plasma-desktop
|
||||
- name: plasma-workspace
|
||||
- name: sddm
|
||||
- name: kwin-x11
|
||||
- name: flatpak
|
||||
- name: network-manager
|
||||
- name: plasma-nm
|
||||
- name: openssh-server
|
||||
- name: curl
|
||||
- name: wget
|
||||
- name: vim
|
||||
- name: nano
|
||||
- name: htop
|
||||
- name: neofetch
|
||||
- name: tree
|
||||
- name: pulseaudio
|
||||
- name: pulseaudio-utils
|
||||
- name: fonts-ubuntu
|
||||
- name: fonts-noto
|
||||
- name: build-essential
|
||||
- name: git
|
||||
- name: live-boot
|
||||
- name: live-config
|
||||
- name: casper
|
||||
- name: systemd-sysv
|
||||
- name: dbus
|
||||
- name: locales
|
||||
- name: resolvconf
|
||||
- name: linux-image-generic
|
||||
- name: linux-headers-generic
|
||||
- name: podman
|
||||
- name: skopeo
|
||||
- name: buildah
|
||||
- name: ostree
|
||||
- name: apt-ostree
|
||||
services:
|
||||
- name: sddm
|
||||
enabled: true
|
||||
- name: NetworkManager
|
||||
enabled: true
|
||||
- name: ssh
|
||||
enabled: true
|
||||
users:
|
||||
- name: particle
|
||||
groups: [sudo, wheel]
|
||||
shell: /bin/bash
|
||||
home: /home/particle
|
||||
files:
|
||||
- path: /etc/hostname
|
||||
content: particleos
|
||||
- path: /etc/hosts
|
||||
content: |
|
||||
127.0.0.1 localhost
|
||||
127.0.1.1 particleos.local particleos
|
||||
- path: /etc/apt-ostree/ref
|
||||
content: particleos/desktop/1.0.0
|
||||
EOF
|
||||
|
||||
print_success "bootc system definition created"
|
||||
}
|
||||
|
||||
# Build system using bootc container workflow
|
||||
build_bootc_system() {
|
||||
print_header "Phase 4: Build System with bootc"
|
||||
|
||||
print_status "Building system using bootc container workflow..."
|
||||
|
||||
# Try to use apt-cacher-ng if available for container build
|
||||
local use_proxy=false
|
||||
if check_proxy_reachable; then
|
||||
print_status "Container build will use apt-cacher-ng: $APT_CACHER_NG_URL"
|
||||
CACHER_CONTAINER_BUILD_USED="Yes"
|
||||
use_proxy=true
|
||||
else
|
||||
print_warning "apt-cacher-ng not reachable. Container build will proceed without proxy."
|
||||
CACHER_CONTAINER_BUILD_USED="No (Fallback to direct)"
|
||||
use_proxy=false
|
||||
fi
|
||||
|
||||
# Create a Dockerfile that bootc can build from
|
||||
cat > "$BUILD_DIR/Dockerfile" << 'EOF'
|
||||
# Start with Ubuntu 24.04 base
|
||||
FROM ubuntu:24.04
|
||||
|
||||
# Set environment
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=UTC
|
||||
|
||||
# Configure apt proxy if available
|
||||
EOF
|
||||
|
||||
# Add proxy configuration if available
|
||||
if [ "$use_proxy" = true ]; then
|
||||
cat >> "$BUILD_DIR/Dockerfile" << EOF
|
||||
RUN echo 'Acquire::http::Proxy "$APT_CACHER_NG_URL";' > /etc/apt/apt.conf.d/01proxy && \\
|
||||
echo 'Acquire::https::Proxy "$APT_CACHER_NG_URL";' >> /etc/apt/apt.conf.d/01proxy
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Continue with the rest of the Dockerfile
|
||||
cat >> "$BUILD_DIR/Dockerfile" << 'EOF'
|
||||
|
||||
# Update and install base packages
|
||||
RUN apt update && apt install -y \
|
||||
systemd \
|
||||
systemd-sysv \
|
||||
dbus \
|
||||
curl \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
gpgv \
|
||||
locales \
|
||||
resolvconf \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Configure locales
|
||||
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8
|
||||
|
||||
# Block snapd installation with APT preferences
|
||||
RUN echo 'Package: snapd' > /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Pin: release *' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Pin-Priority: -1' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo '' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Package: snap' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Pin: release *' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Pin-Priority: -1' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo '' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Package: firefox*' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Pin: release o=Ubuntu*' >> /etc/apt/preferences.d/no-snapd && \
|
||||
echo 'Pin-Priority: -1' >> /etc/apt/preferences.d/no-snapd
|
||||
|
||||
# Install desktop environment
|
||||
RUN apt update && apt install -y \
|
||||
plasma-desktop \
|
||||
plasma-workspace \
|
||||
sddm \
|
||||
kwin-x11 \
|
||||
flatpak \
|
||||
network-manager \
|
||||
plasma-nm \
|
||||
openssh-server \
|
||||
curl \
|
||||
wget \
|
||||
vim \
|
||||
nano \
|
||||
htop \
|
||||
neofetch \
|
||||
tree \
|
||||
pulseaudio \
|
||||
pulseaudio-utils \
|
||||
fonts-ubuntu \
|
||||
fonts-noto \
|
||||
build-essential \
|
||||
git \
|
||||
live-boot \
|
||||
live-config \
|
||||
casper \
|
||||
linux-image-generic \
|
||||
linux-headers-generic \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install bootc and container tools
|
||||
RUN apt update && apt install -y \
|
||||
podman \
|
||||
skopeo \
|
||||
buildah \
|
||||
conmon \
|
||||
crun \
|
||||
netavark \
|
||||
aardvark-dns \
|
||||
slirp4netns \
|
||||
fuse-overlayfs \
|
||||
uidmap \
|
||||
libsubid4 \
|
||||
libslirp0 \
|
||||
passt \
|
||||
thin-provisioning-tools \
|
||||
lvm2 \
|
||||
mdadm \
|
||||
dmeventd \
|
||||
libaio1t64 \
|
||||
libdevmapper-event1.02.1 \
|
||||
liblvm2cmd2.03 \
|
||||
kpartx \
|
||||
pigz \
|
||||
dracut \
|
||||
dracut-core \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy and install local packages
|
||||
COPY pkgs/ /tmp/pkgs/
|
||||
|
||||
# Install ostree and bootc packages from local files
|
||||
RUN if [ -f /tmp/pkgs/libostree-1-1_2025.2-1~noble1_amd64.deb ]; then \
|
||||
dpkg -i /tmp/pkgs/libostree-1-1_2025.2-1~noble1_amd64.deb; \
|
||||
fi
|
||||
|
||||
RUN if [ -f /tmp/pkgs/ostree_2025.2-1~noble1_amd64.deb ]; then \
|
||||
dpkg -i /tmp/pkgs/ostree_2025.2-1~noble1_amd64.deb; \
|
||||
fi
|
||||
|
||||
RUN if [ -f /tmp/pkgs/bootc_1.5.1-1~noble1_amd64.deb ]; then \
|
||||
dpkg -i /tmp/pkgs/bootc_1.5.1-1~noble1_amd64.deb; \
|
||||
fi
|
||||
|
||||
# Install apt-ostree from local packages if available
|
||||
RUN if [ -f /tmp/pkgs/apt-ostree_0.1.0-1_amd64.deb ]; then \
|
||||
dpkg -i /tmp/pkgs/apt-ostree_0.1.0-1_amd64.deb; \
|
||||
fi
|
||||
|
||||
# Remove unwanted packages (snapd is already blocked by APT preferences)
|
||||
RUN apt purge -y ubuntu-advantage-tools || true && \
|
||||
apt purge -y update-notifier || true && \
|
||||
apt purge -y update-manager || true && \
|
||||
apt purge -y unattended-upgrades || true && \
|
||||
apt autoremove -y && \
|
||||
apt clean
|
||||
|
||||
# Configure system
|
||||
RUN echo "particleos" > /etc/hostname && \
|
||||
echo "127.0.0.1 localhost" >> /etc/hosts && \
|
||||
echo "127.0.1.1 particleos.local particleos" >> /etc/hosts && \
|
||||
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
|
||||
|
||||
# Create user
|
||||
RUN useradd -m -s /bin/bash particle && \
|
||||
usermod -aG sudo particle && \
|
||||
echo 'particle ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/particle && \
|
||||
chmod 0440 /etc/sudoers.d/particle
|
||||
|
||||
# Configure apt-ostree
|
||||
RUN mkdir -p /etc/apt-ostree && \
|
||||
echo "ref: particleos/desktop/1.0.0" > /etc/apt-ostree/ref
|
||||
|
||||
# Enable services
|
||||
RUN systemctl enable sddm NetworkManager ssh && \
|
||||
systemctl disable apt-daily.timer apt-daily-upgrade.timer
|
||||
|
||||
# Create casper hook for live boot
|
||||
RUN mkdir -p /etc/casper && \
|
||||
echo "particleos" > /etc/casper/hostname && \
|
||||
echo "particle" > /etc/casper/username
|
||||
|
||||
# Regenerate initrd to include live-boot modules
|
||||
RUN update-initramfs -u -k all
|
||||
|
||||
# Clean up
|
||||
RUN rm -rf /tmp/pkgs /var/lib/apt/lists/* /tmp/*
|
||||
|
||||
# Set labels for bootc
|
||||
LABEL org.opencontainers.image.title="ParticleOS Desktop"
|
||||
LABEL org.opencontainers.image.description="Atomic Ubuntu Desktop with apt-ostree"
|
||||
LABEL org.opencontainers.image.version="1.0.0"
|
||||
LABEL org.opencontainers.image.vendor="ParticleOS"
|
||||
LABEL org.opencontainers.image.source="https://github.com/particleos/particleos-installer"
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 22
|
||||
|
||||
# Set default command
|
||||
CMD ["/lib/systemd/systemd"]
|
||||
EOF
|
||||
|
||||
# Copy packages to build context
|
||||
if [ -d "$SCRIPT_DIR/pkgs" ]; then
|
||||
cp -r "$SCRIPT_DIR/pkgs" "$BUILD_DIR/"
|
||||
fi
|
||||
|
||||
# Build the container image using podman
|
||||
print_status "Building container image..."
|
||||
cd "$BUILD_DIR"
|
||||
podman build -t "$SYSTEM_IMAGE" . || print_error "Failed to build container image."
|
||||
|
||||
print_success "bootc system built: $SYSTEM_IMAGE"
|
||||
}
|
||||
|
||||
# Extract filesystem from container for ISO creation
|
||||
extract_filesystem() {
|
||||
print_header "Phase 5: Extract Filesystem for ISO"
|
||||
|
||||
print_status "Extracting filesystem from container..."
|
||||
|
||||
# Create a temporary container from the image
|
||||
podman create --name "$CONTAINER_NAME" "$SYSTEM_IMAGE" || print_error "Failed to create container."
|
||||
|
||||
# Extract the filesystem
|
||||
local extract_dir="$BUILD_DIR/extract"
|
||||
mkdir -p "$extract_dir"
|
||||
|
||||
podman export "$CONTAINER_NAME" | tar -x -C "$extract_dir" || print_error "Failed to extract filesystem."
|
||||
|
||||
# Remove the temporary container
|
||||
podman container rm "$CONTAINER_NAME" || print_warning "Failed to remove container"
|
||||
|
||||
# Verify extraction was successful
|
||||
if [ ! -f "$extract_dir/etc/os-release" ]; then
|
||||
print_error "Filesystem extraction failed - /etc/os-release not found"
|
||||
fi
|
||||
|
||||
print_success "Filesystem extracted to: $extract_dir"
|
||||
}
|
||||
|
||||
# Create ISO using xorriso (reuse existing proven method)
|
||||
create_iso() {
|
||||
print_header "Phase 6: Create ISO with xorriso"
|
||||
|
||||
local extract_dir="$BUILD_DIR/extract"
|
||||
local iso_dir="$BUILD_DIR/iso"
|
||||
|
||||
print_status "Creating ISO structure..."
|
||||
|
||||
# Create ISO directory structure
|
||||
mkdir -p "$iso_dir"/{casper,boot/grub,EFI/BOOT,isolinux} || print_error "Failed to create ISO directory structure."
|
||||
|
||||
# Copy kernel and initrd from extracted filesystem
|
||||
print_status "Copying kernel and initrd from extracted filesystem..."
|
||||
|
||||
KERNEL_PATH=$(find "$extract_dir/boot" -maxdepth 1 -name "vmlinuz-*" | sort -V | tail -n 1)
|
||||
INITRD_PATH=$(find "$extract_dir/boot" -maxdepth 1 -name "initrd.img-*" | sort -V | tail -n 1)
|
||||
|
||||
if [ -z "$KERNEL_PATH" ]; then
|
||||
print_error "Kernel (vmlinuz-*) not found in $extract_dir/boot."
|
||||
fi
|
||||
if [ -z "$INITRD_PATH" ]; then
|
||||
print_error "Initrd (initrd.img-*) not found in $extract_dir/boot."
|
||||
fi
|
||||
|
||||
print_status "Using kernel: $KERNEL_PATH"
|
||||
print_status "Using initrd: $INITRD_PATH"
|
||||
|
||||
cp "$KERNEL_PATH" "$iso_dir/casper/vmlinuz" || print_error "Failed to copy kernel."
|
||||
cp "$INITRD_PATH" "$iso_dir/casper/initrd" || print_error "Failed to copy initrd."
|
||||
|
||||
# Create filesystem manifest
|
||||
print_status "Creating filesystem manifest..."
|
||||
# We need to chroot to get the package list, but we can't easily chroot into extracted fs
|
||||
# So we'll create a minimal manifest
|
||||
echo "particleos 1.0.0" > "$iso_dir/casper/filesystem.manifest"
|
||||
echo "ubuntu-minimal 24.04" >> "$iso_dir/casper/filesystem.manifest"
|
||||
echo "plasma-desktop 5.27" >> "$iso_dir/casper/filesystem.manifest"
|
||||
|
||||
# Create filesystem size
|
||||
print_status "Calculating filesystem size..."
|
||||
du -sx --block-size=1 "$extract_dir" | cut -f1 > "$iso_dir/casper/filesystem.size" || print_error "Failed to create filesystem.size."
|
||||
|
||||
# Create casper configuration
|
||||
print_status "Creating casper configuration..."
|
||||
cat > "$iso_dir/casper/casper.conf" << 'EOF'
|
||||
# Casper configuration for ParticleOS
|
||||
LIVE_HOSTNAME="particleos"
|
||||
LIVE_USERNAME="particle"
|
||||
LIVE_USER_FULLNAME="ParticleOS User"
|
||||
LIVE_USER_DEFAULT_GROUPS="adm cdrom dip lpadmin plugdev sambashare sudo"
|
||||
LIVE_IMAGETYPE="ParticleOS"
|
||||
LIVE_BOOT_CMDLINE="boot=casper quiet splash"
|
||||
EOF
|
||||
|
||||
# Create squashfs
|
||||
print_status "Creating squashfs filesystem..."
|
||||
mksquashfs "$extract_dir" "$iso_dir/casper/filesystem.squashfs" -comp xz -e boot || print_error "Failed to create squashfs."
|
||||
|
||||
# Create GRUB configuration
|
||||
cat > "$iso_dir/boot/grub/grub.cfg" << 'EOF'
|
||||
set timeout=10
|
||||
set default=0
|
||||
|
||||
menuentry "Try ParticleOS without installing" {
|
||||
linux /casper/vmlinuz boot=casper quiet splash ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
|
||||
menuentry "Install ParticleOS" {
|
||||
linux /casper/vmlinuz boot=casper quiet splash ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
|
||||
menuentry "Check disc for defects" {
|
||||
linux /casper/vmlinuz boot=casper integrity-check quiet splash ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create ISOLINUX configuration
|
||||
cat > "$iso_dir/isolinux/isolinux.cfg" << 'EOF'
|
||||
DEFAULT live
|
||||
TIMEOUT 300
|
||||
PROMPT 1
|
||||
|
||||
LABEL live
|
||||
MENU LABEL Try ParticleOS without installing
|
||||
KERNEL /casper/vmlinuz
|
||||
APPEND boot=casper initrd=/casper/initrd quiet splash ---
|
||||
|
||||
LABEL live-install
|
||||
MENU LABEL Install ParticleOS
|
||||
KERNEL /casper/vmlinuz
|
||||
APPEND boot=casper initrd=/casper/initrd quiet splash ---
|
||||
|
||||
LABEL check
|
||||
MENU LABEL Check disc for defects
|
||||
KERNEL /casper/vmlinuz
|
||||
APPEND boot=casper integrity-check initrd=/casper/initrd quiet splash ---
|
||||
EOF
|
||||
|
||||
# Copy ISOLINUX boot files - REVISED PATH DISCOVERY
|
||||
print_status "Copying ISOLINUX boot files..."
|
||||
ISOLINUX_BASE_DIR=""
|
||||
if [ -d "/usr/lib/syslinux" ]; then
|
||||
ISOLINUX_BASE_DIR="/usr/lib/syslinux"
|
||||
elif [ -d "/usr/lib/ISOLINUX" ]; then
|
||||
ISOLINUX_BASE_DIR="/usr/lib/ISOLINUX"
|
||||
elif [ -d "/usr/share/syslinux" ]; then
|
||||
ISOLINUX_BASE_DIR="/usr/share/syslinux"
|
||||
fi
|
||||
|
||||
if [ -z "$ISOLINUX_BASE_DIR" ]; then
|
||||
print_error "Syslinux base directory not found. Please ensure 'syslinux-utils' or 'isolinux' is installed."
|
||||
fi
|
||||
|
||||
ISOLINUX_BIN_SRC=""
|
||||
LDLINUX_C32_SRC=""
|
||||
MEMDISK_C32_SRC=""
|
||||
MBOOT_C32_SRC=""
|
||||
LIBUTIL_C32_SRC=""
|
||||
|
||||
# Search for isolinux.bin
|
||||
if [ -f "$ISOLINUX_BASE_DIR/isolinux.bin" ]; then
|
||||
ISOLINUX_BIN_SRC="$ISOLINUX_BASE_DIR/isolinux.bin"
|
||||
elif [ -f "$ISOLINUX_BASE_DIR/bios/isolinux.bin" ]; then
|
||||
ISOLINUX_BIN_SRC="$ISOLINUX_BASE_DIR/bios/isolinux.bin"
|
||||
fi
|
||||
|
||||
# Search for ldlinux.c32 and other common .c32 modules
|
||||
if [ -f "$ISOLINUX_BASE_DIR/ldlinux.c32" ]; then
|
||||
LDLINUX_C32_SRC="$ISOLINUX_BASE_DIR/ldlinux.c32"
|
||||
elif [ -f "$ISOLINUX_BASE_DIR/modules/bios/ldlinux.c32" ]; then
|
||||
LDLINUX_C32_SRC="$ISOLINUX_BASE_DIR/modules/bios/ldlinux.c32"
|
||||
elif [ -f "$ISOLINUX_BASE_DIR/isolinux/ldlinux.c32" ]; then
|
||||
LDLINUX_C32_SRC="$ISOLINUX_BASE_DIR/isolinux/ldlinux.c32"
|
||||
fi
|
||||
|
||||
# Search for other critical .c32 files
|
||||
if [ -f "$ISOLINUX_BASE_DIR/memdisk/memdisk.c32" ]; then
|
||||
MEMDISK_C32_SRC="$ISOLINUX_BASE_DIR/memdisk/memdisk.c32"
|
||||
elif [ -f "$ISOLINUX_BASE_DIR/modules/bios/memdisk.c32" ]; then
|
||||
MEMDISK_C32_SRC="$ISOLINUX_BASE_DIR/modules/bios/memdisk.c32"
|
||||
fi
|
||||
if [ -f "$ISOLINUX_BASE_DIR/mboot.c32" ]; then
|
||||
MBOOT_C32_SRC="$ISOLINUX_BASE_DIR/mboot.c32"
|
||||
elif [ -f "$ISOLINUX_BASE_DIR/modules/bios/mboot.c32" ]; then
|
||||
MBOOT_C32_SRC="$ISOLINUX_BASE_DIR/modules/bios/mboot.c32"
|
||||
fi
|
||||
if [ -f "$ISOLINUX_BASE_DIR/libutil.c32" ]; then
|
||||
LIBUTIL_C32_SRC="$ISOLINUX_BASE_DIR/libutil.c32"
|
||||
elif [ -f "$ISOLINUX_BASE_DIR/modules/bios/libutil.c32" ]; then
|
||||
LIBUTIL_C32_SRC="$ISOLINUX_BASE_DIR/modules/bios/libutil.c32"
|
||||
fi
|
||||
|
||||
SYSLINUX_MODULES_PATH=""
|
||||
if [ -d "/usr/lib/syslinux/modules/bios" ]; then
|
||||
SYSLINUX_MODULES_PATH="/usr/lib/syslinux/modules/bios"
|
||||
elif [ -d "/usr/share/syslinux/modules/bios" ]; then
|
||||
SYSLINUX_MODULES_PATH="/usr/share/syslinux/modules/bios"
|
||||
fi
|
||||
|
||||
if [ -z "$ISOLINUX_BIN_SRC" ]; then
|
||||
print_error "isolinux.bin not found within detected syslinux paths. Please check your syslinux installation."
|
||||
fi
|
||||
if [ -z "$LDLINUX_C32_SRC" ]; then
|
||||
print_error "ldlinux.c32 not found within detected syslinux paths. Ensure 'syslinux-common' is installed and up-to-date."
|
||||
fi
|
||||
|
||||
cp "$ISOLINUX_BIN_SRC" "$iso_dir/isolinux/" || print_error "Failed to copy isolinux.bin."
|
||||
cp "$LDLINUX_C32_SRC" "$iso_dir/isolinux/" || print_error "Failed to copy ldlinux.c32."
|
||||
|
||||
# Copy other essential .c32 modules that ldlinux.c32 might depend on
|
||||
if [ -n "$MEMDISK_C32_SRC" ]; then
|
||||
cp "$MEMDISK_C32_SRC" "$iso_dir/isolinux/" || print_warning "Failed to copy memdisk.c32, continuing anyway."
|
||||
fi
|
||||
if [ -n "$MBOOT_C32_SRC" ]; then
|
||||
cp "$MBOOT_C32_SRC" "$iso_dir/isolinux/" || print_warning "Failed to copy mboot.c32, continuing anyway."
|
||||
fi
|
||||
if [ -n "$LIBUTIL_C32_SRC" ]; then
|
||||
cp "$LIBUTIL_C32_SRC" "$iso_dir/isolinux/" || print_warning "Failed to copy libutil.c32, continuing anyway."
|
||||
fi
|
||||
if [ -f "$ISOLINUX_BASE_DIR/menu.c32" ]; then
|
||||
cp "$ISOLINUX_BASE_DIR/menu.c32" "$iso_dir/isolinux/" || print_warning "Failed to copy menu.c32, continuing anyway."
|
||||
elif [ -f "$SYSLINUX_MODULES_PATH/menu.c32" ]; then
|
||||
cp "$SYSLINUX_MODULES_PATH/menu.c32" "$iso_dir/isolinux/" || print_warning "Failed to copy menu.c32, continuing anyway."
|
||||
fi
|
||||
|
||||
# Create basic EFI structure (simplified for now)
|
||||
print_status "Creating basic EFI structure..."
|
||||
mkdir -p "$iso_dir/EFI/BOOT" || print_error "Failed to create EFI/BOOT directory."
|
||||
mkdir -p "$iso_dir/boot/grub" || print_error "Failed to create boot/grub directory."
|
||||
|
||||
# Create ISO using xorriso
|
||||
print_status "Creating bootable ISO using xorriso..."
|
||||
xorriso -as mkisofs \
|
||||
-o "$OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso" \
|
||||
-J -joliet-long \
|
||||
-r -V "ParticleOS-${VERSION}" \
|
||||
-b isolinux/isolinux.bin \
|
||||
-c isolinux/boot.cat \
|
||||
-boot-load-size 4 -boot-info-table \
|
||||
-no-emul-boot \
|
||||
-isohybrid-mbr "$ISOLINUX_BASE_DIR/isohdpfx.bin" \
|
||||
-partition_offset 16 \
|
||||
-part_like_isohybrid \
|
||||
-isohybrid-gpt-basdat \
|
||||
"$iso_dir" || print_error "Failed to create ISO with xorriso."
|
||||
|
||||
print_success "ISO created successfully: $OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso"
|
||||
}
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
print_status "Cleaning up build environment..."
|
||||
|
||||
# Remove any remaining container
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
podman container rm -f "$CONTAINER_NAME" 2>/dev/null || print_warning "Failed to remove container"
|
||||
fi
|
||||
|
||||
# Remove any remaining images
|
||||
if podman image exists "$SYSTEM_IMAGE" 2>/dev/null; then
|
||||
podman image rm -f "$SYSTEM_IMAGE" 2>/dev/null || print_warning "Failed to remove image"
|
||||
fi
|
||||
|
||||
print_success "Cleanup completed"
|
||||
}
|
||||
|
||||
# Signal trap for cleanup
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
echo "🚀 ParticleOS ISO Builder (Pure bootc)"
|
||||
echo "======================================"
|
||||
echo "Project: $PROJECT_NAME"
|
||||
echo "Version: $VERSION"
|
||||
echo "Build Directory: $BUILD_DIR"
|
||||
echo "Tool: Pure bootc + xorriso"
|
||||
echo ""
|
||||
echo "🔄 This build uses:"
|
||||
echo " • bootc for container-based system building"
|
||||
echo " • Dockerfile for system definition"
|
||||
echo " • Container extraction for ISO creation"
|
||||
echo " • xorriso for proven ISO creation"
|
||||
echo ""
|
||||
|
||||
check_prerequisites
|
||||
clean_build
|
||||
create_bootc_definition
|
||||
build_bootc_system
|
||||
extract_filesystem
|
||||
create_iso
|
||||
|
||||
print_header "Build Complete!"
|
||||
echo ""
|
||||
echo "🎉 ParticleOS ISO built successfully with pure bootc!"
|
||||
echo "📁 Location: $OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso"
|
||||
echo "🐳 Container Image: $SYSTEM_IMAGE"
|
||||
echo ""
|
||||
echo "Summary of Cacher Usage:"
|
||||
echo " Container Build: $CACHER_CONTAINER_BUILD_USED"
|
||||
echo ""
|
||||
echo "🧪 Test the ISO:"
|
||||
echo " qemu-system-x86_64 -m 4G -enable-kvm \\"
|
||||
echo " -cdrom $OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso \\"
|
||||
echo " -boot d"
|
||||
echo ""
|
||||
echo "🚀 Deploy with bootc:"
|
||||
echo " sudo bootc install to-disk /dev/sda --source-imgref oci:$SYSTEM_IMAGE"
|
||||
echo ""
|
||||
echo "✅ Pure bootc workflow: Container-first approach!"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
944
build-iso-bootc-native.sh
Normal file → Executable file
944
build-iso-bootc-native.sh
Normal file → Executable file
File diff suppressed because it is too large
Load diff
0
build-iso-bootc-xorriso.sh
Normal file → Executable file
0
build-iso-bootc-xorriso.sh
Normal file → Executable file
87
install-particleos
Normal file
87
install-particleos
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "=========================================="
|
||||
echo " ParticleOS bootc Installation"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "This will install ParticleOS using bootc to your system."
|
||||
echo "WARNING: This is a destructive operation that will erase the target device."
|
||||
echo ""
|
||||
|
||||
# Check if running from live environment
|
||||
if [ ! -f /etc/casper/hostname ]; then
|
||||
echo "Error: This script must be run from the ParticleOS live environment."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for target disk
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 <target-device>"
|
||||
echo "Example: $0 /dev/sda"
|
||||
echo ""
|
||||
echo "Available disks:"
|
||||
echo "=================="
|
||||
lsblk -d -o NAME,SIZE,MODEL,TYPE
|
||||
echo ""
|
||||
echo "Available partitions:"
|
||||
echo "====================="
|
||||
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
|
||||
echo ""
|
||||
echo "Please specify the target device (e.g., /dev/sda for entire disk)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_DEVICE="$1"
|
||||
|
||||
# Validate target device
|
||||
if [ ! -b "$TARGET_DEVICE" ]; then
|
||||
echo "Error: $TARGET_DEVICE is not a valid block device."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Show device information
|
||||
echo "Target device: $TARGET_DEVICE"
|
||||
echo "Device information:"
|
||||
lsblk "$TARGET_DEVICE" -o NAME,SIZE,TYPE,MOUNTPOINT
|
||||
echo ""
|
||||
|
||||
# Final confirmation
|
||||
echo "=========================================="
|
||||
echo "FINAL WARNING: This will completely erase $TARGET_DEVICE"
|
||||
echo "All data on this device will be lost permanently!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Type 'YES' (in uppercase) to confirm installation:"
|
||||
read -r confirmation
|
||||
|
||||
if [ "$confirmation" != "YES" ]; then
|
||||
echo "Installation cancelled."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Installing ParticleOS using bootc..."
|
||||
echo "This may take several minutes..."
|
||||
|
||||
# Install ParticleOS using bootc
|
||||
if bootc install --target "$TARGET_DEVICE" particleos-system:latest; then
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Installation completed successfully!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Reboot your system"
|
||||
echo "2. Boot from $TARGET_DEVICE"
|
||||
echo "3. Enjoy ParticleOS!"
|
||||
echo ""
|
||||
else
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Installation failed!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Please check the error messages above and try again."
|
||||
exit 1
|
||||
fi
|
||||
7
pkgs/add_repo.sh
Executable file
7
pkgs/add_repo.sh
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
# ForgeJo Debian Repository
|
||||
distribution=noble
|
||||
component=main
|
||||
sudo curl https://git.raines.xyz/api/packages/robojerk/debian/repository.key -o /etc/apt/keyrings/forgejo-robojerk.asc
|
||||
echo "deb [signed-by=/etc/apt/keyrings/forgejo-robojerk.asc] https://git.raines.xyz/api/packages/robojerk/debian $distribution $component" | sudo tee -a /etc/apt/sources.list.d/forgejo.list
|
||||
# Available packages
|
||||
# bootc=1.5.1-1~noble1 bootc-dev=1.5.1-1~noble1 libostree-doc=2025.2-1~noble1 ostree-boot=2025.2-1~noble1 ostree-tests=2025.2-1~noble1 ostree=2025.2-1~noble1 libostree-1-1=2025.2-1~noble1 libostree-dev=2025.2-1~noble1 gir1.2-ostree-1.0=2025.2-1~noble1 steam-launcher=1:1.0.0.83
|
||||
Loading…
Add table
Add a link
Reference in a new issue