diff --git a/Dockerfile.gui b/Dockerfile.gui deleted file mode 100644 index 66b266a6..00000000 --- a/Dockerfile.gui +++ /dev/null @@ -1,40 +0,0 @@ -# Use the same builder as the original Dockerfile -FROM archlinux:latest AS builder - -# Set up parallel downloads and other optimizations -COPY pacman.conf /etc/pacman.conf - -# Update system and install necessary packages -RUN pacman -Syu --noconfirm && \ - pacman -S --noconfirm --needed \ - git \ - archiso \ - grub \ - base-devel \ - python-flask \ - && pacman -Scc --noconfirm - -# Set the working directory -WORKDIR /build - -# Copy only necessary files for package installation -COPY packages.x86_64 bootstrap_packages.x86_64 profiledef.sh ./ - -# Create a new final image -FROM builder AS final - -# Set the working directory -WORKDIR /workdir - -# Copy the rest of the files -COPY . . - -# Use an entrypoint script for better flexibility -COPY ./scripts/entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh - -# Expose the port for the web GUI -EXPOSE 8080 - -# Set the entrypoint to run the Flask application -ENTRYPOINT ["python", "app.py"] diff --git a/README.md b/README.md index 30bb039a..5b28b583 100644 --- a/README.md +++ b/README.md @@ -84,55 +84,6 @@ To install Docker, follow the instructions for your operating system: Once the process completes, the ISO will be available in the `out/` directory within your local folder as `Arch.iso`. ---- - -## How to Build the ISO with a GUI - -For a more user-friendly experience, you can use a Docker container that provides a web-based graphical user interface (GUI) to build the ISO. - -### Prerequisites - -Ensure you have Docker installed and running on your system. - -### Steps to Build with the GUI - -1. **Clone the repository**: - - ```bash - git clone https://github.com/Githubguy132010/Arch-Linux-without-the-beeps.git - cd Arch-Linux-without-the-beeps - ``` - -2. **Build the GUI Docker Image**: - - Build the Docker image for the GUI application. - - ```bash - docker build -t arch-iso-gui -f Dockerfile.gui . - ``` - -3. **Run the GUI Container**: - - Run the container, mapping port 8080 to your host system. - - ```bash - docker run --rm --privileged -p 8080:8080 -v $(pwd):/workdir arch-iso-gui - ``` - -4. **Access the GUI**: - - Open your web browser and navigate to `http://localhost:8080`. - -5. **Build the ISO**: - - Click the "Build ISO" button to start the build process. The logs will be displayed in real-time on the page. - -6. **Download the ISO**: - - Once the build is complete, a download link for `Arch.iso` will appear. - ---- - ## How to Use GitHub Actions (Automated Workflow) This repository also includes a GitHub Actions workflow for building and releasing the ISO automatically on GitHub. diff --git a/app.py b/app.py deleted file mode 100644 index c0841d3c..00000000 --- a/app.py +++ /dev/null @@ -1,45 +0,0 @@ -import os -import subprocess -from flask import Flask, render_template, Response, send_from_directory - -app = Flask(__name__) -ISO_DIR = "/workdir/out" -ISO_NAME = "Arch.iso" -ISO_PATH = os.path.join(ISO_DIR, ISO_NAME) - -@app.route('/') -def index(): - return render_template('index.html') - -@app.route('/build') -def build(): - def generate(): - # Ensure the output directory exists - os.makedirs(ISO_DIR, exist_ok=True) - - # Command to execute the build script - command = ["/entrypoint.sh", "build", "out", "work"] - - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True) - - for line in process.stdout: - yield f"data: {line}\n\n" - - process.wait() - - if process.returncode == 0: - yield "data: BUILD_SUCCESS\n\n" - else: - yield "data: BUILD_FAILED\n\n" - - return Response(generate(), mimetype='text/event-stream') - -@app.route('/download') -def download(): - if os.path.exists(ISO_PATH): - return send_from_directory(directory=ISO_DIR, path=ISO_NAME, as_attachment=True) - else: - return "ISO not found.", 404 - -if __name__ == '__main__': - app.run(host='0.0.0.0', port=8080) diff --git a/dockerfile b/dockerfile index 73ff9377..f1334a12 100644 --- a/dockerfile +++ b/dockerfile @@ -1,33 +1,27 @@ +# syntax=docker/dockerfile:1.6 FROM archlinux:latest AS builder -# Set up parallel downloads and other optimizations COPY pacman.conf /etc/pacman.conf -# Update system and install necessary packages -RUN pacman -Syu --noconfirm && \ +RUN --mount=type=cache,target=/var/cache/pacman/pkg \ + pacman -Syu --noconfirm && \ pacman -S --noconfirm --needed \ - git \ - archiso \ - grub \ - base-devel \ - && pacman -Scc --noconfirm + archiso \ + base-devel \ + bsdtar \ + git \ + grub -# Set the working directory WORKDIR /build -# Copy only necessary files for package installation COPY packages.x86_64 bootstrap_packages.x86_64 profiledef.sh ./ -# Create a new final image FROM builder AS final -# Set the working directory WORKDIR /workdir -# Copy the rest of the files COPY . . -# Use an entrypoint script for better flexibility COPY ./scripts/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh diff --git a/pacman.conf b/pacman.conf index 5276768c..586848cb 100644 --- a/pacman.conf +++ b/pacman.conf @@ -2,23 +2,19 @@ # /etc/pacman.conf # # See the pacman.conf(5) manpage for option and repository directives - -# -# GENERAL OPTIONS # + [options] -# The following paths are commented out with their default values listed. -# If you wish to use different paths, uncomment and update the paths. #RootDir = / #DBPath = /var/lib/pacman/ -CacheDir = /var/cache/pacman/pkg/ +#CacheDir = /var/cache/pacman/pkg/ #LogFile = /var/log/pacman.log #GPGDir = /etc/pacman.d/gnupg/ #HookDir = /etc/pacman.d/hooks/ HoldPkg = pacman glibc -XferCommand = /usr/bin/curl -L -C - -f -o %o %u --retry 3 --retry-delay 3 --connect-timeout 10 +#XferCommand = /usr/bin/curl -L -C -f -o %o %u #XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u -CleanMethod = KeepInstalled +#CleanMethod = KeepInstalled Architecture = auto # Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup @@ -30,20 +26,12 @@ Architecture = auto # Misc options #UseSyslog -# Color output enabled Color -# Enable candy output for better visual feedback -ILoveCandy -# Increased parallel downloads for build speed -ParallelDownloads = 64 -# We cannot check disk space from within a chroot environment -#CheckSpace # enable disk space checks +#NoProgressBar +CheckSpace #VerbosePkgLists -DownloadUser = alpm -#DisableSandbox +ParallelDownloads = 16 -# 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 #RemoteFileSigLevel = Required @@ -69,11 +57,6 @@ LocalFileSigLevel = Optional # # The header [repo-name] is crucial - it must be present and # uncommented to enable the repo. -# - -# The testing repositories are disabled by default. To enable, uncomment the -# repo name header and Include lines. You can add preferred servers immediately -# after the header, and they will be used before the default mirrors. #[core-testing] #Include = /etc/pacman.d/mirrorlist @@ -87,9 +70,6 @@ Include = /etc/pacman.d/mirrorlist [extra] Include = /etc/pacman.d/mirrorlist -# If you want to run 32 bit applications on your x86_64 system, -# enable the multilib repositories as required here. - #[multilib-testing] #Include = /etc/pacman.d/mirrorlist diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 26f5058d..588acab6 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -1,12 +1,10 @@ #!/bin/bash -set -e +set -euo pipefail -# Colors for better output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color +NC='\033[0m' log() { echo -e "${GREEN}[INFO]${NC} $1" @@ -17,46 +15,64 @@ warn() { } error() { - echo -e "${RED}[ERROR]${NC} $1" + echo -e "${RED}[ERROR]${NC} $1" >&2 exit 1 } -# Function to build the ISO -build_iso() { - local output_dir="${1:-out}" - local work_dir="${2:-work}" - - log "Starting Arch Linux ISO build process..." - log "Work directory: $work_dir" - log "Output directory: $output_dir" - - # Create necessary directories - mkdir -p "$output_dir" - mkdir -p "$work_dir" - - # Run the mirror selection script - log "Selecting fastest mirrors..." - ./scripts/select-mirrors.sh || warn "Mirror selection failed, continuing with default mirrors" - - # Disable PC speaker module in airootfs if present - if [ -f "airootfs/etc/modprobe.d/nobeep.conf" ] \ - && grep -q "pcspkr" "airootfs/etc/modprobe.d/nobeep.conf" 2>/dev/null \ - && grep -q "snd_pcsp" "airootfs/etc/modprobe.d/nobeep.conf" 2>/dev/null; then - log "PC speaker already disabled in airootfs configuration." +ensure_root() { + if [[ ${EUID:-$(id -u)} -ne 0 ]]; then + error "This container entrypoint must run as root" + fi +} + +ensure_dependencies() { + local missing=() + for dep in mkarchiso bsdtar; do + if ! command -v "$dep" >/dev/null 2>&1; then + missing+=("$dep") + fi + done + + if (( ${#missing[@]} > 0 )); then + log "Installing missing build dependencies: ${missing[*]}" + pacman -Sy --noconfirm "${missing[@]}" + fi +} + +prepare_build_environment() { + export JOBS=${JOBS:-$(nproc)} + export MAKEFLAGS=${MAKEFLAGS:--j${JOBS}} + export BUILD_NCPUS=${BUILD_NCPUS:-${JOBS}} + + log "Using ${JOBS} parallel jobs for compression and builds" + + mkdir -p "${1}" "${2}" +} + +update_mirrors() { + if [[ ${SKIP_MIRROR_UPDATE:-0} == 1 ]]; then + warn "Skipping mirror refresh because SKIP_MIRROR_UPDATE is set" + return + fi + + if ./scripts/select-mirrors.sh; then + log "Mirrors updated successfully" else - log "Disabling PC speaker in airootfs configuration..." - mkdir -p "airootfs/etc/modprobe.d/" - echo "blacklist pcspkr" > "airootfs/etc/modprobe.d/nobeep.conf" - echo "blacklist snd_pcsp" >> "airootfs/etc/modprobe.d/nobeep.conf" + warn "Mirror selection script reported an issue; continuing with existing list" fi - - # Create a custom hook to disable beeps in various config files - if [ ! -f "airootfs/usr/share/libalpm/hooks/99-no-beep.hook" ]; then - log "Creating custom hook to disable beeps..." - if ! mkdir -p "airootfs/usr/share/libalpm/hooks/" 2>/dev/null; then - warn "Failed to create hooks directory, continuing..." - else - cat > "airootfs/usr/share/libalpm/hooks/99-no-beep.hook" << 'EOF' +} + +disable_pc_speaker() { + local modprobe_dir="airootfs/etc/modprobe.d" + mkdir -p "${modprobe_dir}" + cat >"${modprobe_dir}/nobeep.conf" <<'HOOK' +blacklist pcspkr +blacklist snd_pcsp +HOOK + + local hooks_dir="airootfs/usr/share/libalpm/hooks" + mkdir -p "${hooks_dir}" + cat >"${hooks_dir}/99-no-beep.hook" <<'HOOK' [Trigger] Type = Package Operation = Install @@ -67,92 +83,68 @@ Target = * Description = Disabling system beeps in various configuration files... When = PostTransaction Exec = /bin/bash -c "mkdir -p /etc/modprobe.d && echo 'blacklist pcspkr' > /etc/modprobe.d/nobeep.conf && echo 'blacklist snd_pcsp' >> /etc/modprobe.d/nobeep.conf && if [ -f /etc/inputrc ]; then grep -q 'set bell-style none' /etc/inputrc || echo 'set bell-style none' >> /etc/inputrc; fi" -EOF - fi - fi - - # Add settings to disable terminal bell in bash - if [ ! -f "airootfs/etc/skel/.bashrc" ]; then - log "Adding bash configuration to disable terminal bell..." - if ! mkdir -p "airootfs/etc/skel/" 2>/dev/null; then - warn "Failed to create skel directory, continuing..." - else - echo "# Disable terminal bell" > "airootfs/etc/skel/.bashrc" - echo "bind 'set bell-style none'" >> "airootfs/etc/skel/.bashrc" - fi +HOOK + + mkdir -p airootfs/etc + if [[ ! -f airootfs/etc/inputrc ]]; then + echo "set bell-style none" > airootfs/etc/inputrc fi - # Set bell-style none in global inputrc - if [ ! -f "airootfs/etc/inputrc" ]; then - log "Setting bell-style none in global inputrc..." - if ! mkdir -p "airootfs/etc" 2>/dev/null; then - warn "Failed to create etc directory, continuing..." - else - echo "set bell-style none" > "airootfs/etc/inputrc" - fi + mkdir -p airootfs/etc/skel + cat > airootfs/etc/skel/.bashrc <<'CONF' +# Disable terminal bell +bind 'set bell-style none' +CONF +} + +validate() { + log "Validating build prerequisites" + + [[ -f packages.x86_64 ]] || error "packages.x86_64 file not found" + [[ -x profiledef.sh ]] || error "profiledef.sh not found or not executable" + [[ -f pacman.conf ]] || error "pacman.conf not found" + + sort -u packages.x86_64 -o packages.x86_64 + if [[ -f bootstrap_packages.x86_64 ]]; then + sort -u bootstrap_packages.x86_64 -o bootstrap_packages.x86_64 fi - - # Optimize the build process with parallel compression - export JOBS=$(nproc) - log "Using $JOBS processors for parallel compression" - - # Note: We don't modify profiledef.sh anymore as -Xthreads is not supported by mksquashfs - # The profiledef.sh file already has proper XZ compression settings - - # Run mkarchiso with verbose option and handle errors - log "Building Arch ISO with mkarchiso..." - if mkarchiso -v -w "$work_dir" -o "$output_dir" .; then - log "ISO build completed successfully!" - log "ISO available at: $output_dir" + + log "Validation complete" +} + +build_iso() { + local output_dir="${1:-out}" + local work_dir="${2:-work}" + + log "Starting Arch Linux ISO build" + log "Work directory: ${work_dir}" + log "Output directory: ${output_dir}" + + ensure_root + ensure_dependencies + prepare_build_environment "${output_dir}" "${work_dir}" + update_mirrors + disable_pc_speaker + + log "Invoking mkarchiso" + if mkarchiso -v -w "${work_dir}" -o "${output_dir}" .; then + log "ISO build completed successfully" + log "ISO available at: ${output_dir}" else - error "ISO build failed!" + error "ISO build failed" fi } -# Function to clean up build artifacts clean() { - log "Cleaning up build artifacts..." + log "Cleaning up build artifacts" rm -rf work/* - log "Cleanup complete." -} - -# Function to validate the configuration -validate() { - log "Validating configuration..." - - # Check if packages.x86_64 exists - if [ ! -f "packages.x86_64" ]; then - error "packages.x86_64 file not found!" - fi - - # Check if profiledef.sh exists and is executable - if [ ! -x "profiledef.sh" ]; then - error "profiledef.sh not found or not executable!" - fi - - # Check if pacman.conf exists - if [ ! -f "pacman.conf" ]; then - error "pacman.conf not found!" - fi - - # Sort and deduplicate package lists - log "Sorting and deduplicating package lists..." - if [ -f "packages.x86_64" ]; then - sort -u packages.x86_64 -o packages.x86_64 - fi - - if [ -f "bootstrap_packages.x86_64" ]; then - sort -u bootstrap_packages.x86_64 -o bootstrap_packages.x86_64 - fi - - log "Configuration appears valid." + log "Cleanup complete" } -# Main switch -case "$1" in +case "${1:-build}" in build) validate - build_iso "$2" "$3" + build_iso "${2:-out}" "${3:-work}" ;; clean) clean @@ -161,19 +153,11 @@ case "$1" in validate ;; shell) - log "Starting interactive shell..." + log "Starting interactive shell" exec /bin/bash ;; *) log "Usage: $0 {build|clean|validate|shell} [output_dir] [work_dir]" - log "" - log "Commands:" - log " build - Build the Arch Linux ISO" - log " clean - Clean up build artifacts" - log " validate - Validate the configuration" - log " shell - Start an interactive shell" exit 1 ;; esac - -exit 0 \ No newline at end of file diff --git a/scripts/select-mirrors.sh b/scripts/select-mirrors.sh index 6aed2e76..b7c47680 100755 --- a/scripts/select-mirrors.sh +++ b/scripts/select-mirrors.sh @@ -1,10 +1,10 @@ #!/bin/bash -set -e +set -euo pipefail -# Colors for better output GREEN='\033[0;32m' YELLOW='\033[0;33m' -NC='\033[0m' # No Color +RED='\033[0;31m' +NC='\033[0m' log() { echo -e "${GREEN}[INFO]${NC} $1" @@ -14,31 +14,77 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $1" } -log "Selecting fastest mirrors..." - -# Create mirror directory if it doesn't exist -mkdir -p airootfs/etc/pacman.d/ - -# Backup existing mirrorlist if it exists -if [ -f /etc/pacman.d/mirrorlist ]; then - cp /etc/pacman.d/mirrorlist airootfs/etc/pacman.d/mirrorlist.backup 2>/dev/null || { - warn "Failed to backup mirrorlist, continuing without backup" - } -else - warn "No system mirrorlist found to backup" -fi - -# Install reflector if not already installed -if ! command -v reflector &> /dev/null; then - log "Installing reflector..." - pacman -Sy --noconfirm reflector -fi - -# Generate mirror list with reflector -log "Generating optimized mirror list..." -reflector --latest 20 \ - --sort rate \ - --protocol https \ - --save airootfs/etc/pacman.d/mirrorlist - -log "Mirror selection complete!" \ No newline at end of file +error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +require_command() { + if ! command -v "$1" >/dev/null 2>&1; then + log "Installing missing dependency: $1" + pacman -Sy --noconfirm "$1" + fi +} + +main() { + log "Selecting reliable Arch Linux mirrors..." + + local mirror_dir="airootfs/etc/pacman.d" + local mirror_target="${mirror_dir}/mirrorlist" + local system_mirror="/etc/pacman.d/mirrorlist" + local tmp_mirror + tmp_mirror="$(mktemp)" + trap 'rm -f "${tmp_mirror}"' EXIT + + mkdir -p "${mirror_dir}" + + if [[ -f "${system_mirror}" ]]; then + cp "${system_mirror}" "${mirror_dir}/mirrorlist.backup" + else + warn "No system mirrorlist found to back up" + fi + + require_command reflector + + local -a reflector_args + reflector_args=( + --protocol https + --latest 20 + --fastest 10 + --sort rate + --download-timeout 5 + --save "${tmp_mirror}" + ) + + if [[ -n "${REFLECTOR_COUNTRIES:-}" ]]; then + reflector_args+=(--country "${REFLECTOR_COUNTRIES}") + else + reflector_args+=(--completion-percent 100) + fi + + log "Running reflector with args: ${reflector_args[*]}" + + if reflector "${reflector_args[@]}"; then + mv "${tmp_mirror}" "${mirror_target}" + log "Mirror list saved to ${mirror_target}" + else + warn "Reflector failed to generate a mirror list" + if [[ -f "${mirror_target}" ]]; then + warn "Using existing mirror list at ${mirror_target}" + elif [[ -f "${system_mirror}" ]]; then + cp "${system_mirror}" "${mirror_target}" + warn "Fallback to system mirror list" + else + error "No mirror list available after reflector failure" + return 1 + fi + fi + + if [[ -f "${system_mirror}" ]]; then + cp "${mirror_target}" "${system_mirror}" + log "Updated system mirror list at ${system_mirror}" + fi + + log "Mirror selection complete" +} + +main "$@"