From 8da036e5a05b895e9d34431d5acf716a309934fa Mon Sep 17 00:00:00 2001 From: Philip Peterson <1326208+philip-peterson@users.noreply.github.com> Date: Mon, 2 Nov 2026 04:29:11 -0900 Subject: [PATCH] Kickoff from our plasma-desktop fork, not a patch file The update bar is now a commit on quine-global-labs/plasma-desktop, branch quine-v (KDE's release plus our commits), and kickoff-builder builds from that branch. patches/kickoff/ goes; its standalone CMakeLists.txt moves to kickoff/. A missing branch for the image's Plasma version fails the build with a pointer to the fork's rebase workflow. Same plugin as before (built and compared on the runner). Co-Authored-By: Claude Opus 5.5 --- Containerfile | 26 ++-- {patches/kickoff => kickoff}/CMakeLists.txt | 0 overlay/usr/libexec/quine-linux/update-check | 2 +- patches/kickoff/0001-update-bar.patch | 132 ------------------- 4 files changed, 14 insertions(+), 146 deletions(-) rename {patches/kickoff => kickoff}/CMakeLists.txt (100%) delete mode 100644 patches/kickoff/0001-update-bar.patch diff --git a/Containerfile b/Containerfile index 7645b14..4673cab 100644 --- a/Containerfile +++ b/Containerfile @@ -37,19 +37,20 @@ RUN set -eux; \ # --- Builds Kickoff (the start menu) with our update bar. --- # Kickoff is QML packed into one plugin of plasma-desktop. This rebuilds -# just that plugin from the same plasma-desktop version the image ships -# (KDE's source, via the forge's mirror), with patches/kickoff/ on top, and -# the final stage puts it in place of the stock one. Like kmod-builder, it's -# built FROM BASE_IMAGE so it can't drift from the Plasma it runs on; the -# -devel packages are pinned to the installed versions (older ones come -# from Fedora's updates-archive). +# just that plugin from our fork, quine-global-labs/plasma-desktop, branch +# quine-v: KDE's release of the plasma-desktop version the image +# ships, plus our commits. The final stage puts it in place of the stock +# one. Like kmod-builder, it's built FROM BASE_IMAGE so it can't drift from +# the Plasma it runs on; the -devel packages are pinned to the installed +# versions (older ones come from Fedora's updates-archive). kickoff/ holds +# the CMakeLists.txt that builds the applet outside plasma-desktop's tree. FROM ${BASE_IMAGE} AS kickoff-builder -COPY patches/kickoff/ /tmp/kickoff/ +COPY kickoff/CMakeLists.txt /tmp/kickoff/ RUN set -eux; \ v() { rpm -q --qf '%{VERSION}-%{RELEASE}' "$1"; }; \ - devel=(cmake gcc-c++ extra-cmake-modules patch \ + devel=(cmake gcc-c++ extra-cmake-modules \ "libplasma-devel-$(v libplasma)" \ "qt6-qtbase-devel-$(v qt6-qtbase)" \ "qt6-qtdeclarative-devel-$(v qt6-qtdeclarative)"); \ @@ -58,15 +59,14 @@ RUN set -eux; \ done; \ dnf install -y --setopt=install_weak_deps=False "${devel[@]}"; \ V="$(rpm -q --qf '%{VERSION}' plasma-desktop)"; \ - echo "Building Kickoff from plasma-desktop ${V}"; \ + echo "Building Kickoff from quine-global-labs/plasma-desktop, branch quine-v${V}"; \ curl -fsSL --retry 3 -o /tmp/plasma-desktop.tar.gz \ - "https://forge.quinefoundation.com/quine-global-labs/mirror-kde-plasma-desktop/archive/v${V}.tar.gz"; \ + "https://forge.quinefoundation.com/quine-global-labs/plasma-desktop/archive/quine-v${V}.tar.gz" \ + || { echo "No branch quine-v${V} in quine-global-labs/plasma-desktop: the image moved to Plasma ${V}; its rebase workflow makes the branch, or failed to (check its Actions)" >&2; exit 1; }; \ mkdir -p /build-src; \ tar -xzf /tmp/plasma-desktop.tar.gz -C /build-src --strip-components=2 \ - mirror-kde-plasma-desktop/applets/kickoff; \ + plasma-desktop/applets/kickoff; \ cp /tmp/kickoff/CMakeLists.txt /build-src/; \ - cd /build-src; \ - for p in /tmp/kickoff/*.patch; do patch -p1 --fuzz=0 < "$p"; done; \ cmake -S /build-src -B /build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr; \ cmake --build /build -j"$(nproc)"; \ DESTDIR=/out cmake --install /build --strip; \ diff --git a/patches/kickoff/CMakeLists.txt b/kickoff/CMakeLists.txt similarity index 100% rename from patches/kickoff/CMakeLists.txt rename to kickoff/CMakeLists.txt diff --git a/overlay/usr/libexec/quine-linux/update-check b/overlay/usr/libexec/quine-linux/update-check index 24d612f..2541433 100755 --- a/overlay/usr/libexec/quine-linux/update-check +++ b/overlay/usr/libexec/quine-linux/update-check @@ -1,7 +1,7 @@ #!/usr/bin/bash # Is a newer Quine Linux available, or downloaded and waiting for a restart? # Writes the answer to /run/quine-linux/update-status.json, which Kickoff's -# update bar reads (patches/kickoff). Run as root by +# update bar reads (quine-global-labs/plasma-desktop). Run as root by # quine-update-check.service: bootc needs root. # # state: "staged" an update is downloaded; it applies at the next boot diff --git a/patches/kickoff/0001-update-bar.patch b/patches/kickoff/0001-update-bar.patch deleted file mode 100644 index a8f26f7..0000000 --- a/patches/kickoff/0001-update-bar.patch +++ /dev/null @@ -1,132 +0,0 @@ -diff --git a/kickoff/CMakeLists.txt b/kickoff/CMakeLists.txt -index 70e361c..d860cb4 100644 ---- a/kickoff/CMakeLists.txt -+++ b/kickoff/CMakeLists.txt -@@ -26,6 +26,7 @@ QML_SOURCES - ListOfGridsView.qml - ListOfGridsViewDelegate.qml - NormalPage.qml -+ UpdateBar.qml - PlacesPage.qml - SectionView.qml - VerticalStackView.qml -diff --git a/kickoff/FullRepresentation.qml b/kickoff/FullRepresentation.qml -index aa25d3c..7d9a6bb 100644 ---- a/kickoff/FullRepresentation.qml -+++ b/kickoff/FullRepresentation.qml -@@ -77,6 +77,9 @@ EmptyPage { - } - } - -+ // Quine Linux: system update status (UpdateBar.qml). -+ footer: UpdateBar {} -+ - contentItem: VerticalStackView { - id: contentItemStackView - focus: true -diff --git a/kickoff/UpdateBar.qml b/kickoff/UpdateBar.qml -new file mode 100644 -index 0000000..3ebe376 ---- /dev/null -+++ b/kickoff/UpdateBar.qml -@@ -0,0 +1,100 @@ -+/* -+ SPDX-FileCopyrightText: 2026 Quine Foundation -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+ -+// Quine Linux: a bar at the bottom of Kickoff when a newer system image is -+// available, or downloaded and waiting for a restart. It reads the status -+// that quine-update-check.service writes as root (quine-linux's overlay, -+// /usr/libexec/quine-linux/update-check), and is hidden otherwise. -+ -+pragma ComponentBehavior: Bound -+ -+import QtQuick -+import org.kde.kirigami as Kirigami -+import org.kde.plasma.plasma5support as P5Support -+import org.kde.plasma.private.sessions as Sessions -+ -+Kirigami.InlineMessage { -+ id: root -+ -+ readonly property string statusFile: "/run/quine-linux/update-status.json" -+ readonly property string readCommand: "cat " + statusFile -+ // "current", "available" or "staged"; anything else hides the bar. -+ property string updateState: "" -+ property string newBuild: "" -+ -+ position: Kirigami.InlineMessage.Position.Footer -+ // Hidden, InlineMessage's implicit height is 0, so the menu doesn't keep -+ // room for it (EmptyPage sizes by the footer's implicit height). -+ visible: updateState === "available" || updateState === "staged" -+ showCloseButton: false -+ type: updateState === "staged" ? Kirigami.MessageType.Positive : Kirigami.MessageType.Information -+ icon.name: updateState === "staged" ? "system-reboot-update" : "system-software-update" -+ text: updateState === "staged" -+ ? i18nc("@info", "An update is ready. Restart to finish updating.") -+ : i18nc("@info", "A system update is available%1.", -+ newBuild ? i18nc("@info build date", " (built %1)", newBuild) : "") -+ -+ actions: [ -+ Kirigami.Action { -+ visible: root.updateState === "available" -+ text: i18nc("@action:button", "Update Now") -+ icon.name: "system-software-update" -+ // Aurora's System Update: `ujust update` in a terminal. -+ onTriggered: { -+ executable.connectSource("kioclient exec /usr/share/applications/dev.getaurora.system-update.desktop") -+ kickoff.expanded = false -+ } -+ }, -+ Kirigami.Action { -+ visible: root.updateState === "staged" && sessions.canReboot -+ text: i18nc("@action:button", "Restart") -+ icon.name: "system-reboot" -+ onTriggered: { -+ kickoff.expanded = false -+ sessions.requestReboot() -+ } -+ } -+ ] -+ -+ Sessions.SessionManagement { -+ id: sessions -+ } -+ -+ P5Support.DataSource { -+ id: executable -+ engine: "executable" -+ connectedSources: [] -+ onNewData: (source, data) => { -+ disconnectSource(source) -+ if (source !== root.readCommand) { -+ return -+ } -+ let status = null -+ try { -+ status = JSON.parse(data["stdout"]) -+ } catch (e) { -+ // No file yet (the first check hasn't run, or a live session). -+ } -+ root.updateState = status?.state ?? "" -+ const built = status?.new?.timestamp -+ root.newBuild = built ? Qt.formatDate(new Date(built), Qt.locale(), Locale.ShortFormat) : "" -+ } -+ } -+ -+ function refresh() { -+ executable.connectSource(readCommand) -+ } -+ -+ Component.onCompleted: refresh() -+ -+ Connections { -+ target: kickoff -+ function onExpandedChanged() { -+ if (kickoff.expanded) { -+ root.refresh() -+ } -+ } -+ } -+}