🏡 index : quine-global-labs/quine-linux.git

version: '3'

vars:
  IMAGE: quine-linux
  LIVE_IMAGE: quine-linux-live
  # What the Containerfile builds FROM: our Aurora fork
  # (quine-global-labs/aurora), built and published by that repo's workflow.
  # Override with a local build of the fork (BASE_IMAGE=localhost/aurora:stable,
  # see README) or stock upstream (BASE_IMAGE=ghcr.io/ublue-os/aurora:stable).
  BASE_IMAGE: forge.in.quineglobal.com/quine-global-labs/aurora:stable
  # What installed systems follow for updates: Aurora's uupd.timer stages
  # whatever is newest there daily, for the next boot. Our own name, so it
  # outlives where the images are stored: today a pull-only proxy to the
  # forge's registry (petersweb-infra nixos/edge.nix), where iso.yml pushes.
  UPDATE_IMAGE: registry.quineglobal.com/quine-linux:latest
  OUTPUT_DIR: '{{.ROOT_DIR}}/output'
  # Root is needed for the container builds and bootc; skip {{.SUDO}} when already
  # root (e.g. on a CI runner, which may not have {{.SUDO}} at all).
  SUDO:
    sh: '[ "$(id -u)" = 0 ] || echo sudo'
  # Any docker-CLI-compatible runtime works for plain builds. Prefers podman,
  # falls back to docker; override with CONTAINER_RUNTIME=... (env or task var).
  CONTAINER_RUNTIME:
    sh: echo "${CONTAINER_RUNTIME:-$(command -v podman >/dev/null 2>&1 && echo podman || echo docker)}"
  # bootc-image-builder now lives in github.com/osbuild/image-builder and is
  # published here; quay.io/centos-bootc/bootc-image-builder is frozen.
  BIB_IMAGE: ghcr.io/osbuild/bootc-image-builder:latest
  # What to build for: amd64 by default, so an arm64 host (e.g. Apple
  # Silicon) doesn't build for arm64 by accident. For arm64, pass
  # PLATFORM=linux/arm64 TARGET_ARCH=arm64 and the arm64 base
  # (BASE_IMAGE=forge.in.quineglobal.com/quine-global-labs/aurora:stable-arm64),
  # as iso.yml's arm64 job does. Disk images need a host of that architecture.
  PLATFORM: linux/amd64
  TARGET_ARCH: amd64
  SKOPEO_IMAGE: quay.io/skopeo/stable:latest
  # Titanoboa's ISO step runs in this (live/titanoboa-build-iso.sh).
  FEDORA_IMAGE: quay.io/fedora/fedora:latest
  # bootc-image-builder reads images from a containers-storage mounted at
  # /var/lib/containers/storage. Under podman that's root's real store; docker
  # has no such store, so images get copied (via skopeo) into this volume.
  DOCKER_STORAGE_VOLUME: quine-containers-storage
  STORAGE: '{{if eq .CONTAINER_RUNTIME "podman"}}/var/lib/containers/storage{{else}}{{.DOCKER_STORAGE_VOLUME}}{{end}}'
  PULL_FLAG: '{{if eq .CONTAINER_RUNTIME "podman"}}--pull=newer{{else}}--pull=always{{end}}'

tasks:
  default:
    desc: List available tasks
    cmds:
      - task --list
    silent: true

  build-image:
    desc: >-
      Build the quine-linux bootc container image on top of BASE_IMAGE
      (our Aurora build from the forge's registry by default), as root
      (under podman this lands in root's containers-storage, which bootc and
      bootc-image-builder read; under docker, the ISO tasks copy it over).
    cmds:
      - >-
        {{.SUDO}} {{.CONTAINER_RUNTIME}} build --platform {{.PLATFORM}}
        --build-arg BASE_IMAGE={{.BASE_IMAGE}}
        -t {{.IMAGE}} -f Containerfile .
    sources:
      - Containerfile
      - overlay/**/*
      - patches/**/*

  build-disk-image:
    desc: >-
      Build a ready-installed disk image (qcow2) of the local quine-linux
      image, via bootc-image-builder: boot it in a VM and plasma-setup asks
      for the first user. Output lands in {{.OUTPUT_DIR}}/qcow2/disk.qcow2.
    preconditions:
      - sh: |
          case "$(uname -m)" in x86_64|amd64) a=amd64 ;; aarch64|arm64) a=arm64 ;; *) a="$(uname -m)" ;; esac
          [ "$a" = "{{.TARGET_ARCH}}" ]
        msg: >-
          Disk image builds need a host of architecture {{.TARGET_ARCH}}. This
          one is {{ARCH}}, and bootc-image-builder's cross-arch mode fails
          partway (it runs the image for inspection, which needs emulation
          inside its own container).
    cmds:
      # Not a dep: deps run before preconditions, and this should fail fast.
      - task: build-image
      - task: export-to-storage
        vars: { IMAGES: "{{.IMAGE}}" }
      # An install follows the image name its disk was built from for
      # updates, so build it from UPDATE_IMAGE's name, not localhost/:
      # same image, under the name installs should pull from.
      # (bootc-image-builder's --target-imgref did this; image-builder
      # dropped it.)
      - >-
        {{if eq .CONTAINER_RUNTIME "podman"}}{{.SUDO}} podman tag localhost/{{.IMAGE}} {{.UPDATE_IMAGE}}{{else}}{{.SUDO}} {{.CONTAINER_RUNTIME}} run --rm --privileged
        -v {{.STORAGE}}:/var/lib/containers/storage {{.SKOPEO_IMAGE}}
        copy containers-storage:localhost/{{.IMAGE}}:latest containers-storage:{{.UPDATE_IMAGE}}{{end}}
      - mkdir -p {{.OUTPUT_DIR}}
      # Root on btrfs, as Aurora installs it: disk/config.toml.
      - >-
        {{.SUDO}} {{.CONTAINER_RUNTIME}} run --rm --privileged {{.PULL_FLAG}}
        --security-opt label=type:unconfined_t
        -v {{.OUTPUT_DIR}}:/output
        -v {{.ROOT_DIR}}/disk/config.toml:/config.toml:ro
        -v {{.STORAGE}}:/var/lib/containers/storage
        {{.BIB_IMAGE}}
        --type qcow2
        {{.UPDATE_IMAGE}}
    generates:
      - "{{.OUTPUT_DIR}}/qcow2/disk.qcow2"

  build-live-image:
    desc: >-
      Build the live ISO's root filesystem (live/Containerfile): quine-linux
      plus the live session and Anaconda WebUI, with PAYLOAD_IMAGE (what the
      installer installs) pulled into it. Podman only.
    vars:
      PAYLOAD_IMAGE: '{{.PAYLOAD_IMAGE | default .UPDATE_IMAGE}}'
    preconditions:
      - sh: '[ "{{.CONTAINER_RUNTIME}}" = podman ]'
        msg: The live ISO tasks need podman (they mount the image into Titanoboa's container).
    cmds:
      - >-
        {{.SUDO}} podman build --platform {{.PLATFORM}}
        --cap-add sys_admin --security-opt label=disable
        --build-arg BASE_IMAGE=localhost/{{.IMAGE}}
        --build-arg PAYLOAD_IMAGE={{.PAYLOAD_IMAGE}}
        -t {{.LIVE_IMAGE}} -f live/Containerfile live/

  build-live-iso:
    desc: >-
      Build the live ISO: boots into a Quine Linux session, with an installer.
      Titanoboa's script (live/titanoboa-build-iso.sh) packs the live image
      into it. Output lands in {{.OUTPUT_DIR}}/live/Quine-Linux-Live.iso.
      PAYLOAD_IMAGE: see build-live-image.
    preconditions:
      - sh: '[ "{{.CONTAINER_RUNTIME}}" = podman ]'
        msg: The live ISO tasks need podman (they mount the image into Titanoboa's container).
    cmds:
      - task: build-image
      - task: build-live-image
      - mkdir -p {{.OUTPUT_DIR}}/live
      - >-
        {{.SUDO}} podman run --rm {{.PULL_FLAG}}
        --cap-add sys_admin --security-opt label=disable
        -v {{.ROOT_DIR}}/live/titanoboa-build-iso.sh:/src/build_iso.sh:ro
        --mount type=image,source=localhost/{{.LIVE_IMAGE}},dst=/rootfs
        -v {{.OUTPUT_DIR}}/live:/output
        {{.FEDORA_IMAGE}} /src/build_iso.sh
    generates:
      - "{{.OUTPUT_DIR}}/live/Quine-Linux-Live.iso"

  export-to-storage:
    internal: true
    desc: >-
      Under docker, copy IMAGES (space-separated local tags) from the docker
      daemon into the containers-storage volume bootc-image-builder reads.
      No-op under podman, which builds straight into containers-storage.
    status:
      - '[ "{{.CONTAINER_RUNTIME}}" = podman ]'
    cmds:
      - for: { var: IMAGES }
        cmd: >-
          {{.SUDO}} {{.CONTAINER_RUNTIME}} run --rm --privileged
          -v /var/run/docker.sock:/var/run/docker.sock
          -v {{.STORAGE}}:/var/lib/containers/storage
          {{.SKOPEO_IMAGE}}
          copy docker-daemon:{{.ITEM}}:latest containers-storage:localhost/{{.ITEM}}:latest

  status:
    desc: Show current bootc deployment status (what's booted, what's staged/rollback).
    cmds:
      - bootc status

  test:stage:
    desc: >-
      Build the local image and stage it as the next-boot target on THIS
      machine (bootc switch, no reboot yet). This is the fast way to test a
      change -- especially the CS8409 mic-fix kernel module -- against the
      real running system without building an ISO or reinstalling anything.
      Reboot separately when ready: `task test:boot`, or `sudo systemctl reboot`.
    deps: [build-image]
    cmds:
      # bootc reads the host's own containers-storage, i.e. podman's (which
      # every bootc host ships), so a docker-built image is loaded into it.
      - cmd: '{{.SUDO}} docker save {{.IMAGE}} | {{.SUDO}} podman load'
        platforms: [linux]
        if: '[ "{{.CONTAINER_RUNTIME}}" != podman ]'
      - '{{.SUDO}} bootc switch --transport containers-storage localhost/{{.IMAGE}}'
      - bootc status --booted
      - echo "Staged localhost/{{.IMAGE}} for next boot. Run task test:boot when ready to reboot into it."

  test:boot:
    desc: Stage the local image (if not already) and reboot into it now.
    prompt: This will reboot this machine into the locally-built {{.IMAGE}} image. Continue?
    deps: [test:stage]
    cmds:
      - '{{.SUDO}} systemctl reboot'

  revert:
    desc: >-
      Roll back to the previously-booted deployment and reboot into it --
      undoes a `test:boot` switch (or any other deployment change) if
      something's wrong. Safe even if nothing was ever switched: bootc/
      rpm-ostree always keep the prior deployment around for exactly this.
    prompt: This will reboot this machine back into the previous deployment. Continue?
    cmds:
      - '{{.SUDO}} bootc rollback'
      - '{{.SUDO}} systemctl reboot'