Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/deploy_commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ on:

jobs:
check_and_format:
name: cargo check and clippy
runs-on: ubuntu-24.04
name: cargo check and clippy (${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
arch: [x86_64, aarch64]
runs-on: ${{ matrix.arch == 'aarch64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
steps:
- run: sudo apt-get update
- run: sudo apt-get install -y pkg-config libglib2.0-dev libgtk-4-dev libgtk-3-dev libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev libadwaita-1-dev
Expand Down
24 changes: 16 additions & 8 deletions .github/workflows/deploy_release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ on:
jobs:
check_and_format:
name: cargo check and clippy
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, aarch64]
runs-on: ${{ matrix.arch == 'aarch64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
steps:
- run: sudo apt-get update
- run: sudo apt-get install -y pkg-config libglib2.0-dev libgtk-4-dev libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev libadwaita-1-dev
- run: sudo apt-get install -y pkg-config libglib2.0-dev libgtk-4-dev libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev libadwaita-1-dev
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
Expand All @@ -20,15 +24,19 @@ jobs:
- run: cargo clippy

build_and_distropack:
name: build release + distropack upload
runs-on: ubuntu-24.04
name: build release + distropack upload (${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
arch: [x86_64, aarch64]
runs-on: ${{ matrix.arch == 'aarch64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
needs:
- check_and_format
steps:
- uses: actions/checkout@v4

- run: sudo apt-get update
- run: sudo apt-get install -y pkg-config libglib2.0-dev libgtk-4-dev libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev libadwaita-1-dev
- run: sudo apt-get install -y pkg-config libglib2.0-dev libgtk-4-dev libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev libadwaita-1-dev

- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
Expand Down Expand Up @@ -57,7 +65,7 @@ jobs:
uses: distropack/distropack-action@v1.0
with:
api-token: ${{ secrets.DISTROPACK_API_TOKEN }}
package-id: f6fee267-5e8e-4fe1-b4b1-f724736d598d
package-id: ${{ matrix.arch == 'aarch64' && secrets.DISTROPACK_DAEMON_AARCH64 || 'f6fee267-5e8e-4fe1-b4b1-f724736d598d' }}
version: ${{ steps.version.outputs.version }}
files: |
{
Expand All @@ -68,7 +76,7 @@ jobs:
uses: distropack/distropack-action@v1.0
with:
api-token: ${{ secrets.DISTROPACK_API_TOKEN }}
package-id: 9668ac33-5166-4952-a364-24d3dbc5abeb
package-id: ${{ matrix.arch == 'aarch64' && secrets.DISTROPACK_GTK_AARCH64 || '9668ac33-5166-4952-a364-24d3dbc5abeb' }}
version: ${{ steps.version.outputs.version }}
files: |
{
Expand All @@ -79,7 +87,7 @@ jobs:
uses: distropack/distropack-action@v1.0
with:
api-token: ${{ secrets.DISTROPACK_API_TOKEN }}
package-id: 019afefc-abbc-7ce1-8466-53d0f351c347
package-id: ${{ matrix.arch == 'aarch64' && secrets.DISTROPACK_TRAY_AARCH64 || '019afefc-abbc-7ce1-8466-53d0f351c347' }}
version: ${{ steps.version.outputs.version }}
files: |
{
Expand Down
2 changes: 1 addition & 1 deletion ci/gen_daemon_pkgbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="The core daemon for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url="{url}"
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_daemon_pkgbuild_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="The core daemon for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url="{url}"
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_gtk_pkgbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="A gtk frontend for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url={url}
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_gtk_pkgbuild_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="A gtk frontend for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url={url}
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_tray_pkgbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="A system tray item for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url={url}
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_tray_pkgbuild_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="A system tray item for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url={url}
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_webview_pkgbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="A Web Renderer frontend for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url={url}
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion ci/gen_webview_pkgbuild_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def create_pkgbuild(pkgname, pkgver, url):
pkgver={pkgver}
pkgrel=1
pkgdesc="A Web Renderer frontend for Power Options, a blazingly fast power management solution."
arch=('x86_64')
arch=('x86_64' 'aarch64')
url={url}
license=('MIT')

Expand Down
2 changes: 1 addition & 1 deletion crates/power-daemon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl Instance {

fs::remove_file(
self.profiles_path
.join(format!("{}.toml", &profile_to_remove_name)),
.join(format!("{}.toml", profile_to_remove_name)),
)
.expect("Could not remove profile file");

Expand Down
2 changes: 1 addition & 1 deletion crates/power-daemon/src/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ impl NetworkSettings {
if device_type.trim() == "1" {
run_command(&format!(
"ifconfig {} {}",
&name_str,
name_str,
if disable { "down" } else { "up" }
));
}
Expand Down
61 changes: 61 additions & 0 deletions docs/adr/001-arm-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
id: adrs-adr001
title: "ADR001: Multi-Architecture Support (x86_64 + aarch64)"
# prettier-ignore
description: Architecture Decision Record (ADR) for adding ARM (aarch64) support to Power Options distribution
---

## Context

Power Options is a pure Rust project with zero architecture-specific code — no `#[cfg(target_arch)]`, no arch-dependent dependencies, no inline assembly. The codebase compiles cleanly on any CPU architecture supported by Rust's tier 1 and tier 2 targets.

Despite this, the project's distribution infrastructure exclusively targets x86_64:

- **CI pipelines** (`deploy_release.yaml`, `deploy_commit.yaml`) run only on `ubuntu-24.04` (x86_64) runners.
- **AUR PKGBUILD generators** hardcode `arch=('x86_64')` in all 8 generators (daemon, gtk, webview, tray × stable + git variants).
- **DistroPack uploads** provide only x86_64 binaries.
- **OBS Debian control file** correctly uses `Architecture: any`, but CI never builds for non-x86 targets.

ARM-based devices (e.g., Raspberry Pi, Apple Silicon via Asahi Linux, Snapdragon X Elite laptops, server-grade Ampere Altra) are increasingly common Linux platforms. Users on these systems are forced to build from source manually, which works but defeats the purpose of the packaged distribution.

A user on an aarch64 system attempting `apt install power-options-gtk` receives:

```
power-options-gtk:amd64 : Depends: libadwaita-1-0:amd64 but it is not installable
```

This is because only an amd64 (x86_64) binary exists in the DistroPack repository — APT tries to satisfy it via multiarch on a system with no x86_64 userspace.

## Decision

We will add aarch64 as a supported architecture across all distribution channels:

1. **CI/CD**: Convert the release build job to a strategy matrix running on both `ubuntu-24.04` and `ubuntu-24.04-arm` GitHub-hosted runners. The commit check job will also run on both architectures.

2. **DistroPack**: Upload architecture-specific binaries from each matrix job. We will use distinct package IDs per architecture to keep package metadata clean.

3. **AUR PKGBUILDs**: Update all 8 PKGBUILD generators to set `arch=('x86_64' 'aarch64')`, allowing Arch Linux ARM (asahi-linux, Arch Linux ARM) users to install from the AUR.

4. **OBS / Debian packaging**: No changes needed — `Architecture: any` in `debian.control` and the absence of arch-specific requirements in the RPM `.spec` already permit multi-arch builds. The OBS build service will handle cross-architecture builds when configured.

5. **Install scripts**: No changes needed — they invoke `cargo build --release` natively on whatever architecture the user is on.

We intentionally do **not** add cross-compilation tooling (e.g., `cross`, `cargo-zigbuild`, QEMU binfmt) at this time. Using native ARM GitHub runners is simpler, faster, and avoids the complications of cross-compiling GTK4/libadwaita/WebKit system dependencies. If native ARM runners prove unavailable or too slow in the future, cross-compilation can be revisited.

## Consequences

### Positive
- ARM Linux users can install Power Options via apt, AUR, and OBS without building from source.
- The Rust codebase needs no changes — a testament to Rust's portability.
- GitHub's ARM runners are available at no additional cost for public repositories.
- The build matrix approach is easy to understand and extend (e.g., adding riscv64 in the future).

### Negative
- CI runtime approximately doubles (two parallel builds instead of one).
- DistroPack package management becomes slightly more complex with per-arch package IDs.
- AUR PKGBUILD `arch` arrays become slightly longer (all 8 files need `('x86_64' 'aarch64')`).

### Neutral
- The check_and_format job in commit CI will also run on ARM, catching any future architecture-specific regressions.
- The webview frontend (dioxus/webkit2gtk) builds on ARM where webkit2gtk is available — no additional work needed.
- Release tags now produce two sets of binaries. We must verify DistroPack processes both correctly before the first multi-arch release.
23 changes: 23 additions & 0 deletions docs/adr/_adr-XXXX-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
id: adrs-adr000
title: "ADR000: [TITLE]"
# prettier-ignore
description: Architecture Decision Record (ADR) for [TITLE] [DESCRIPTION]
---

<!-- These documents have names that are short noun phrases. For example, "ADR001: Deployment on Ruby on Rails 3.0.10" or "ADR009: LDAP for Multitenant Integration" -->

## Context

<!--
This section describes the forces at play, including technological, political, social, and project local. These forces are probably in tension, and should be called out as such. The language in this section is value-neutral. It is simply describing facts. -->

## Decision

<!-- This section describes our response to these forces. It is stated in full sentences, with active voice. "We will ..." -->

## Consequences

<!-- This section describes the resulting context, after applying the decision. All consequences should be listed here, not just the "positive" ones. A particular decision may have positive, negative, and neutral consequences, but all of them affect the team and project in the future. -->

<!-- This template is taken from a blog post by Michael Nygard http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions -->