Merge remote-tracking branch 'refs/remotes/portfolio/master' into codex/portfolio-263-20260907
This commit is contained in:
commit
a0f23f35e5
143 files changed
+5156
-1124
No files matched your search
@@ -39,7 +39,7 @@ jobs:
|
||||
archlinux:base-devel bash -lc '
|
||||
set -euo pipefail
|
||||
|
||||
pacman -Syu --noconfirm jq
|
||||
pacman -Syu --noconfirm git jq
|
||||
|
||||
groupadd -g "$HOST_GID" runner
|
||||
useradd -m -u "$HOST_UID" -g "$HOST_GID" runner
|
||||
|
||||
@@ -25,8 +25,9 @@ jobs:
|
||||
-w /workspace \
|
||||
archlinux:base-devel bash -lc '
|
||||
set -euo pipefail
|
||||
pacman -Syu --noconfirm jq
|
||||
pacman -Syu --noconfirm git jq
|
||||
./bin/sync-upstream self-test
|
||||
./bin/sync-rebuilds --self-test
|
||||
./bin/omarchy-pkgs self-test
|
||||
./bin/omarchy-release self-test
|
||||
'
|
||||
@@ -1,3 +1,4 @@
|
||||
.firecrawl/
|
||||
src/
|
||||
logs/
|
||||
build-output/
|
||||
|
||||
@@ -30,18 +30,57 @@ The filesystem no longer encodes release policy. Instead:
|
||||
## Prerequisites
|
||||
### aarch64 Builds (Optional)
|
||||
|
||||
To build ARM64 packages on x86_64, enable QEMU emulation:
|
||||
The repository host builds every architecture it publishes on the same
|
||||
machine. A foreign architecture runs under QEMU user emulation, which
|
||||
`bin/build` checks by actually running a container for the target platform.
|
||||
Rootful Docker registers QEMU on first use. Rootless Podman uses the host's
|
||||
registration and prints the one-time Arch setup commands when it is missing or
|
||||
lacks the credential flag required by `sudo` inside the builder:
|
||||
|
||||
```bash
|
||||
# Run after each reboot
|
||||
docker run --privileged --rm tonistiigi/binfmt --install arm64
|
||||
|
||||
# Verify
|
||||
docker run --rm --platform linux/arm64 alpine:latest uname -m
|
||||
podman run --rm --platform linux/arm64 docker.io/library/alpine:latest uname -m
|
||||
# Should output: aarch64
|
||||
```
|
||||
|
||||
**Note**: aarch64 builds use QEMU and slower than native x86_64 builds.
|
||||
**Note**: emulated builds are much slower than native ones.
|
||||
|
||||
### Published architectures
|
||||
|
||||
`helpers/paths.sh` names the architectures this repository publishes:
|
||||
|
||||
```bash
|
||||
PUBLISHED_ARCHES="${OMARCHY_ARCHES:-x86_64}"
|
||||
```
|
||||
|
||||
That list drives the whole scheduled pipeline. `check-versions` compares
|
||||
PKGBUILDs against each architecture's channel databases and writes one queue
|
||||
file per channel and architecture (`.sync-needed-<channel>-<arch>`);
|
||||
`auto-release <channel>` works through the queues one architecture at a
|
||||
time, each with its own backoff (`.build-failed-<channel>-<arch>`), so a
|
||||
failing build on one architecture never holds up the other; and the release
|
||||
train advances channels with `--arch all`: it takes one host-wide lock and
|
||||
verifies every architecture's source database before moving any of them. The
|
||||
first entry is the reference architecture the release train observes channels
|
||||
through. A remote sync failure can still leave a promotion temporarily partial;
|
||||
rerunning the same advance completes it safely.
|
||||
|
||||
Adding an architecture to the scheduled pipeline is therefore one checked-in
|
||||
change to that list: the next `check-versions` tick queues everything the new
|
||||
architecture lacks, and the next `auto-release` tick starts building it. A
|
||||
checked-in list also means the rebuild workflow and release host cannot drift
|
||||
onto different architecture sets. For a one-off run, override it directly:
|
||||
|
||||
```bash
|
||||
OMARCHY_ARCHES=x86_64 bin/check-versions
|
||||
OMARCHY_ARCHES=aarch64 bin/check-versions
|
||||
OMARCHY_ARCHES="x86_64 aarch64" bin/check-versions
|
||||
```
|
||||
|
||||
The builder image bootstraps
|
||||
`omarchy-keyring` from the x86_64 tree for every architecture, so the first
|
||||
build of a new architecture does not depend on a repository that only it can
|
||||
create.
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -300,10 +339,11 @@ bin/sync-upstream openai-codex-desktop # Update specific packages
|
||||
|
||||
Some vendors publish a release feed of their own that is faster and more precise
|
||||
than the AUR packaging of it. Those packages are `source: local` — Omarchy owns
|
||||
the PKGBUILD — and declare where releases come from in one of two ways.
|
||||
the PKGBUILD — and declare where releases come from either as data or, for an
|
||||
unusual feed, a small hook.
|
||||
|
||||
A vendor shipping tagged GitHub releases with a checksum manifest asset is pure
|
||||
data, declared as `upstream` in `.omarchy/package.json` with no code at all:
|
||||
A vendor shipping tagged GitHub releases is pure data, declared as `upstream`
|
||||
in `.omarchy/package.json` with no code at all:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
@@ -316,16 +356,107 @@ data, declared as `upstream` in `.omarchy/package.json` with no code at all:
|
||||
}
|
||||
```
|
||||
|
||||
`checksums` names the manifest asset the vendor publishes. A vendor publishing
|
||||
none sets `"digests": true` instead, and the checksums come from the SHA-256
|
||||
digest GitHub's release API reports for every asset — see
|
||||
`pkgbuilds/schist-bin/.omarchy/package.json`. Either way the artifacts
|
||||
themselves are never downloaded.
|
||||
|
||||
An architecture may map to an ordered array when its PKGBUILD downloads more
|
||||
than one release asset. Small versioned files outside the release assets can be
|
||||
listed under `sources` and are downloaded and hashed when a new version appears:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
"github": "owner/project",
|
||||
"digests": true,
|
||||
"assets": {
|
||||
"x86_64": ["tool-{pkgver}-x86_64", "tool-{pkgver}-x86_64.asc"],
|
||||
"aarch64": ["tool-{pkgver}-aarch64", "tool-{pkgver}-aarch64.asc"]
|
||||
},
|
||||
"sources": {
|
||||
"any": ["https://raw.githubusercontent.com/owner/project/{tag}/LICENSE"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Asset and source keys must be disjoint because each key maps to one PKGBUILD
|
||||
checksum array (`any` means the unsuffixed `sha256sums`).
|
||||
|
||||
Repositories whose historical releases use incompatible tag schemes may set
|
||||
`"latest_only": true`. The provider then considers only the newest stable
|
||||
GitHub release, while retaining all validation for that release. A quarantine
|
||||
will wait for that release to age instead of falling back to an older one.
|
||||
|
||||
`{tag}` and `{pkgver}` interpolate into asset names; a leading `v` on the tag is
|
||||
stripped for `pkgver`; drafts and prereleases are ignored. Only the 100 most
|
||||
recent releases are considered. The provider fails closed on anything it cannot
|
||||
read — an unusable tag, timestamp, or checksum stops the sync rather than being
|
||||
skipped.
|
||||
|
||||
A package may also declare `"min_release_age": "24h"` (`s`/`m`/`h`/`d` suffix or
|
||||
bare seconds) to quarantine fresh releases until maintainers have had time to
|
||||
pull a bad or compromised one. The newest release that has cleared the window
|
||||
ships, so a fast release cadence cannot starve updates. The window is enforced
|
||||
Projects that publish version tags but no checksum manifest can declare the
|
||||
tag repository, the exact tag shape, and every source that should be hashed:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/owner/project.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://github.com/owner/project/archive/refs/tags/{tag}.tar.gz"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The newest matching tag is selected with pacman's `vercmp`; unrelated tags are
|
||||
ignored. `tag_pattern` must contain exactly one `{pkgver}`. Source templates may
|
||||
use `{tag}` and `{pkgver}`. Each expanded URL must be HTTPS and is downloaded
|
||||
only when the discovered version is newer. A checked-in patch or other local
|
||||
source can be included as `file:patch-name.patch`; it is hashed from the package
|
||||
directory. Keys such as `any`, `x86_64`, and `aarch64` select the corresponding
|
||||
`sha256sums` array.
|
||||
|
||||
npm packages use the same source mapping, with `{npm_tarball}` available for
|
||||
the tarball named by the selected dist-tag:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
"npm": "@scope/package",
|
||||
"dist_tag": "latest",
|
||||
"sources": {
|
||||
"any": ["{npm_tarball}", "https://example.com/v{pkgver}/CHANGELOG.md"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`dist_tag` defaults to `latest`. The registry's publication timestamp is
|
||||
carried into the provider result, so `min_release_age` works for npm packages.
|
||||
|
||||
A vendor with a plain-text Debian `Packages` index can use it to discover the
|
||||
newest exact package version, then hash immutable source URLs:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
"debian": "https://example.com/debian/dists/stable/main/binary-amd64/Packages",
|
||||
"package": "example-app",
|
||||
"sources": {
|
||||
"x86_64": ["https://example.com/tool-{pkgver}-x64.tar.gz"],
|
||||
"aarch64": ["https://example.com/tool-{pkgver}-arm64.tar.gz"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This deliberately accepts only Debian versions that are already valid Arch
|
||||
`pkgver` values. Feeds needing epoch, revision, or filename translation retain
|
||||
a hook. Exactly one of `github`, `git_tags`, `npm`, or `debian` may appear in a
|
||||
declaration.
|
||||
|
||||
A timestamped provider may also declare `"min_release_age": "24h"`
|
||||
(`s`/`m`/`h`/`d` suffix or bare seconds) to quarantine fresh releases until
|
||||
maintainers have had time to pull a bad or compromised one. GitHub Releases and
|
||||
npm provide publication times; raw git tags and Debian Packages indexes do not,
|
||||
so combining either with this policy fails closed. The newest release that has
|
||||
cleared the window ships, so a fast release cadence cannot starve updates. The
|
||||
window is enforced
|
||||
centrally: whatever reports the release must prove its age via `published_at`,
|
||||
or the sync fails. A maintainer deliberately shipping inside the window runs
|
||||
`BYPASS_MIN_RELEASE_AGE=1 bin/sync-upstream <package>` locally and merges the
|
||||
@@ -378,7 +509,12 @@ A package names those dependencies in `.omarchy/package.json`:
|
||||
{ "source": "aur", "sync": false, "rebuild_on": ["qt6-base", "qt6-declarative", "qt6-wayland"] }
|
||||
```
|
||||
|
||||
`bin/sync-rebuilds` reads each named package's version from the official repositories and compares it to `rebuilt_against`, the record of what the checked-in pkgrel was last bumped for. pkgrel is bumped unless every name in `rebuild_on` is recorded and still matches, so a name the record does not carry reads as changed rather than going unexamined forever. Opting a package in therefore buys one rebuild: what its published build actually linked against is not knowable from here, and a record written without a rebuild would certify a build nobody checked.
|
||||
`bin/sync-rebuilds` reads each named package's version from the official
|
||||
repositories for every published architecture the package supports and compares
|
||||
it to `rebuilt_against`. Records are kept per architecture because Arch and
|
||||
Arch Linux ARM can carry different dependency versions. pkgrel is bumped once
|
||||
when any recorded version moves; that one source revision is then rebuilt by
|
||||
each architecture's normal queue.
|
||||
|
||||
The bump is the point of the command, and it has to land in git rather than in the builder. A rebuild that reuses the published version string produces a package pacman will never offer anyone, so merely unlocking the build gate would ship nothing. Bumping pkgrel needs no other change: `bin/check-versions` and the builder both already rebuild when pkgrel moves.
|
||||
|
||||
@@ -386,9 +522,12 @@ For an AUR-synced package the bump is expressed as the dotted Omarchy pkgrel suf
|
||||
|
||||
The bumped version is checked against the published one as well as the checked-in one, and refused when pacman would not order it higher. The checked-in version is not the floor; what a user already has is, and a checkout that has fallen behind the repository can otherwise be bumped to something that loses to the package it means to replace. That check is skipped with a warning when the published database cannot be read.
|
||||
|
||||
Versions are read from the local pacman database, so this runs on Arch or in an Arch container against a synced database. Only `core`, `extra` and `multilib` count: a Qt release sitting in testing or kde-unstable is not what the builder will link against, and rebuilding for it would ship a package built against the wrong ABI. The workflow points that database at `mirror.omarchy.org`, the mirror the x86_64 builder itself uses, because a mirror running ahead of the builder would record a version the build never linked against and nothing re-fires once the record matches.
|
||||
|
||||
aarch64 is not covered. Those builds resolve Qt from Arch Linux ARM, which can lag Arch, so one record cannot describe both architectures. Only x86_64 is published today, so nothing currently ships from the untracked side; if ARM publishing starts, `rebuilt_against` has to become per-architecture before this can be trusted there.
|
||||
x86_64 versions are read from the local pacman database, so the workflow runs
|
||||
in an Arch container pointed at `mirror.omarchy.org`, the same mirror as the
|
||||
x86_64 builder. aarch64 versions are read directly from the live Arch Linux ARM
|
||||
repository database, which is also what the ARM builder uses. Testing and
|
||||
staging repositories do not count. A legacy flat `rebuilt_against` record is
|
||||
read as x86_64 and is migrated naturally the next time a rebuild is needed.
|
||||
|
||||
### Other
|
||||
|
||||
@@ -586,7 +725,7 @@ Minimal examples:
|
||||
Fields:
|
||||
|
||||
- `source`: `aur` or `local`. A `local` package can still follow an upstream release, either declaratively via `upstream` or with an `.omarchy/upstream.sh` hook.
|
||||
- `upstream`: optional for `local` packages whose vendor ships tagged GitHub releases with a checksum manifest asset. `{ "github": "owner/repo", "checksums": "SHASUMS256.txt", "assets": { "<arch>": "name-{tag}.tar.xz" } }` — see [Sync Upstream Releases](#sync-upstream-releases). Mutually exclusive with `.omarchy/upstream.sh`.
|
||||
- `upstream`: optional for `local` packages following GitHub releases, git tags, npm dist-tags, or a Debian `Packages` index. GitHub architecture assets may be a string or an ordered array, and can be combined with disjoint versioned `sources` — see [Sync Upstream Releases](#sync-upstream-releases). Mutually exclusive with `.omarchy/upstream.sh`.
|
||||
- `min_release_age`: optional quarantine for upstream releases (`"24h"`, `"2d"`, or bare seconds). The newest release older than the window ships; anything younger waits, and a release whose age cannot be proven fails the sync. Bypass deliberately with `BYPASS_MIN_RELEASE_AGE=1 bin/sync-upstream <package>`.
|
||||
- `sync`: optional for AUR packages; defaults to `true`. Set `false` for AUR-origin packages that Omarchy maintains manually.
|
||||
- `aur`: optional AUR package name when it differs from the local package directory, usually for split packages.
|
||||
@@ -596,7 +735,7 @@ Fields:
|
||||
- `skip_build`: optional boolean; defaults to `false`. Set `true` to exclude a package from scheduled version checks and unscoped builds. The package can still be built explicitly with `bin/repo release --package <name>`.
|
||||
- `pkgrel`: optional Omarchy pkgrel suffix for a version-pinned rebuild bump. This emits `<aur pkgrel>.<suffix>` instead of replacing AUR's pkgrel. `offset` can be used only when preserving monotonic upgrades from old absolute pkgrel bumps. The metadata is removed automatically when AUR sync changes `pkgver`; the current package version is read from the checked-in PKGBUILD, so the version is not duplicated in JSON.
|
||||
- `rebuild_on`: optional array of package names this package links against closely enough that it must be rebuilt when they change, independent of its own source. Read by `bin/sync-rebuilds`.
|
||||
- `rebuilt_against`: written by `bin/sync-rebuilds`. Records the version of each `rebuild_on` package that the current pkgrel was bumped for.
|
||||
- `rebuilt_against`: written by `bin/sync-rebuilds`. Maps each published architecture to the versions of its `rebuild_on` packages that the current pkgrel was bumped for.
|
||||
- `upstream_commit`: set by `bin/sync-aur` for AUR packages. Used by `bin/package-worktree` to recreate the exact raw AUR package that Omarchy last synced.
|
||||
|
||||
### Build Matrix
|
||||
@@ -691,10 +830,15 @@ bin/repo release --package my-package
|
||||
- Mirrors: mirror.omarchy.org, rackspace, pkgbuild.com
|
||||
|
||||
### aarch64
|
||||
- QEMU emulation required on x86_64 hosts (slower)
|
||||
- Uses Arch Linux ARM repositories
|
||||
- Built on the repository host like x86_64; under QEMU when the host is x86_64
|
||||
- On an ARM host, package builds and the signing/database utility containers
|
||||
run natively; only an explicitly requested x86_64 package build is emulated
|
||||
- Uses Arch Linux ARM repositories through the same HTTPS mirror for every
|
||||
channel (Arch Linux ARM publishes no dated snapshots to pin a channel's base)
|
||||
- Additional repos: `[alarm]`, `[aur]`
|
||||
- Same workflow, just add `--arch aarch64`
|
||||
- Same workflow, just add `--arch aarch64`; the scheduled pipeline runs it
|
||||
automatically once `aarch64` is in `PUBLISHED_ARCHES`
|
||||
- Packages whose `arch=()` lacks `aarch64` are skipped, not failed
|
||||
|
||||
### Building for Both Architectures
|
||||
|
||||
@@ -745,8 +889,8 @@ The repository includes GitHub workflows and systemd services for automated rele
|
||||
All four units run **every 5 minutes**, staggered by a minute each, so a push
|
||||
reaches the mirror in minutes rather than hours:
|
||||
|
||||
1. **check-versions** (`*:0/5`): Pulls latest from git, compares PKGBUILD versions to published versions, creates state files if builds are needed
|
||||
2. **auto-release-edge** (`*:1/5`): If a state file exists, builds all edge packages that need updates
|
||||
1. **check-versions** (`*:0/5`): Pulls latest from git, compares PKGBUILD versions to published versions for every published architecture, creates one state file per channel and architecture if builds are needed
|
||||
2. **auto-release-edge** (`*:1/5`): For each published architecture with a state file, builds all edge packages that need updates
|
||||
3. **auto-release-rc** (`*:2/5`): Builds fast-ring packages for rc, from the main checkout like the other two — natively in the rc image, not copied from another channel. The pinned release pair is built separately by `omarchy-release rc` in the `rc` branch worktree
|
||||
4. **auto-release-stable** (`*:3/5`): If a state file exists, builds `release_ring=fast` packages for stable and replicates them to rc
|
||||
|
||||
@@ -760,10 +904,11 @@ That cadence is only safe because of three guards:
|
||||
an operator expects. `check-versions` takes it too — its `git pull` would
|
||||
otherwise swap PKGBUILDs out from under a running build.
|
||||
- **Backoff on failure.** A failed release records the attempt in
|
||||
`.build-failed-<channel>` and backs off exponentially — 10m, 20m, 40m, up to
|
||||
`.build-failed-<channel>-<arch>` and backs off exponentially — 10m, 20m, 40m, up to
|
||||
a 6h ceiling — instead of rebuilding the same broken tree every 5 minutes.
|
||||
**Any new commit clears the backoff immediately**, since a push is the most
|
||||
likely fix. Clear it by hand with `rm /root/.state/.build-failed-<channel>`.
|
||||
likely fix. Clear it by hand with
|
||||
`rm /root/.state/.build-failed-<channel>-<arch>`.
|
||||
- **Quiet when idle.** With nothing queued a tick exits without output, so the
|
||||
journal shows the runs that mattered rather than 288 no-ops a day.
|
||||
|
||||
@@ -816,10 +961,14 @@ bin/repo timers --local # inspect this machine instead
|
||||
```
|
||||
|
||||
State files are stored in `/root/.state/`:
|
||||
- `.sync-needed-<channel>` — the packages queued for that channel, one per
|
||||
line; the release run reads them to name what it is building
|
||||
- `.build-failed-<channel>` — consecutive failure count, timestamp, and the
|
||||
commit it failed on (drives the backoff; removing it forces a retry)
|
||||
- `.sync-needed-<channel>-<arch>` — the packages queued for that channel and
|
||||
architecture, one per line; the release run reads them to name what it is
|
||||
building
|
||||
- `.build-failed-<channel>-<arch>` — consecutive failure count, timestamp, and
|
||||
the commit it failed on (drives the backoff; removing it forces a retry)
|
||||
|
||||
Legacy files without the architecture suffix are consumed once as x86_64
|
||||
state, so upgrading the host does not lose an in-flight build.
|
||||
|
||||
### Schedule (America/New_York)
|
||||
|
||||
|
||||
+51
-3
@@ -25,6 +25,22 @@ SKIP_PROD_CHECK=false
|
||||
FAST_RING_ONLY=false
|
||||
BOOTSTRAP=false
|
||||
PACKAGES=""
|
||||
ALL_ARCHES=false
|
||||
|
||||
# Kept for --arch all, which re-invokes this script per architecture with the
|
||||
# other arguments unchanged (minus the --arch all pair itself).
|
||||
ORIGINAL_ARGS=()
|
||||
arch_option=false
|
||||
for arg in "$@"; do
|
||||
if [[ "$arch_option" == true ]]; then
|
||||
[[ "$arg" != "all" ]] && ORIGINAL_ARGS+=("--arch" "$arg")
|
||||
arch_option=false
|
||||
elif [[ "$arg" == "--arch" ]]; then
|
||||
arch_option=true
|
||||
else
|
||||
ORIGINAL_ARGS+=("$arg")
|
||||
fi
|
||||
done
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 --from <channel> --to <channel> [OPTIONS]"
|
||||
@@ -36,7 +52,8 @@ usage() {
|
||||
echo " or --bootstrap (one-time initial seed)"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --arch <arch> Target architecture (x86_64 or aarch64, default: x86_64)"
|
||||
echo " --arch <arch>|all Target architecture (x86_64 or aarch64, default: x86_64);"
|
||||
echo " all = every published architecture, one after another"
|
||||
echo " --package <names...> Advance only the named package(s)"
|
||||
echo " --fast-ring Restrict to fast-ring packages (stable -> rc parity copy)"
|
||||
echo " --bootstrap One-time stable -> rc seed before forward-only enforcement"
|
||||
@@ -65,8 +82,14 @@ while [[ $# -gt 0 ]]; do
|
||||
shift 2
|
||||
;;
|
||||
--arch)
|
||||
ARCH="$2"
|
||||
update_arch_paths
|
||||
if [[ "$2" == "all" ]]; then
|
||||
ALL_ARCHES=true
|
||||
ARCH=all
|
||||
else
|
||||
require_valid_arch "$2"
|
||||
ARCH="$2"
|
||||
update_arch_paths
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--package)
|
||||
@@ -134,6 +157,31 @@ case "$FROM->$TO" in
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$ALL_ARCHES" == true ]]; then
|
||||
# Hold one lock across the whole operation so a timer cannot mutate a
|
||||
# channel between architectures. Check every source database before moving
|
||||
# the first one; a failed sync can still require an idempotent retry, but a
|
||||
# missing architecture never creates a knowingly partial advance.
|
||||
if [[ "$DRY_RUN" != true ]]; then
|
||||
acquire_release_lock || exit 1
|
||||
fi
|
||||
|
||||
ARCHES=$(published_arches)
|
||||
for arch in $ARCHES; do
|
||||
source_db="$REPO_ROOT/$FROM/$arch/omarchy.db.tar.zst"
|
||||
if [[ ! -f "$source_db" ]]; then
|
||||
print_error "Source database not found: $source_db"
|
||||
echo "Nothing has been published to the $FROM channel for $arch."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for arch in $ARCHES; do
|
||||
"$0" --arch "$arch" "${ORIGINAL_ARGS[@]}" || exit $?
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SOURCE_DIR="$REPO_ROOT/$FROM/$ARCH"
|
||||
TARGET_DIR="$REPO_ROOT/$TO/$ARCH"
|
||||
SOURCE_DB="$SOURCE_DIR/omarchy.db.tar.zst"
|
||||
|
||||
+104
-57
@@ -1,6 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Run the release workflow for a channel when work is queued.
|
||||
# Usage: auto-release <edge|rc|stable>
|
||||
# Usage: auto-release <edge|rc|stable> [<arch>|all]
|
||||
#
|
||||
# With no architecture (what the timers pass), every published architecture
|
||||
# is processed in turn, each against its own queue and its own backoff, so a
|
||||
# failing aarch64 build never holds up x86_64 or the other way round.
|
||||
#
|
||||
# Safe to run on a tight schedule. Three guards make that true:
|
||||
#
|
||||
@@ -21,7 +25,7 @@ source "$BUILD_ROOT/helpers/paths.sh"
|
||||
source "$BUILD_ROOT/helpers/lock-helpers.sh"
|
||||
|
||||
MIRROR="${1:-}"
|
||||
STATE_DIR="${OMARCHY_STATE_DIR:-/root/.state}"
|
||||
ARCH_ARG="${2:-all}"
|
||||
|
||||
# Backoff schedule: 10m, 20m, 40m, 80m, 160m, 320m, then hourly-ish forever
|
||||
# (capped at 6h, the cadence this system ran at before frequent timers).
|
||||
@@ -29,8 +33,9 @@ BACKOFF_BASE_SECONDS="${OMARCHY_BACKOFF_BASE:-600}"
|
||||
BACKOFF_MAX_SECONDS="${OMARCHY_BACKOFF_MAX:-21600}"
|
||||
|
||||
if [[ -z "$MIRROR" ]]; then
|
||||
print_error "Usage: $0 <mirror>"
|
||||
print_error "Usage: $0 <mirror> [<arch>|all]"
|
||||
echo " mirror: edge, rc, or stable"
|
||||
echo " arch: one of $VALID_ARCHES, or all (default) for every published architecture"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -39,17 +44,13 @@ if [[ "$MIRROR" != "edge" && "$MIRROR" != "rc" && "$MIRROR" != "stable" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STATE_FILE="$STATE_DIR/.sync-needed-$MIRROR"
|
||||
FAIL_FILE="$STATE_DIR/.build-failed-$MIRROR"
|
||||
|
||||
# Nothing queued: stay quiet. At a 5-minute cadence this is most invocations,
|
||||
# and a header for each would bury the runs that matter in the journal.
|
||||
if [[ ! -f "$STATE_FILE" ]]; then
|
||||
exit 0
|
||||
if [[ "$ARCH_ARG" == "all" ]]; then
|
||||
ARCHES=$(published_arches)
|
||||
else
|
||||
require_valid_arch "$ARCH_ARG"
|
||||
ARCHES="$ARCH_ARG"
|
||||
fi
|
||||
|
||||
print_header "Processing Sync for $MIRROR"
|
||||
|
||||
# The build inputs are this checkout's contents; its HEAD identifies them.
|
||||
current_fingerprint() {
|
||||
git -C "$BUILD_ROOT" rev-parse HEAD 2>/dev/null || echo "unknown"
|
||||
@@ -65,57 +66,103 @@ backoff_seconds() {
|
||||
echo "$delay"
|
||||
}
|
||||
|
||||
FAIL_COUNT=0
|
||||
if [[ -f "$FAIL_FILE" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$FAIL_FILE" 2>/dev/null || true
|
||||
FAIL_COUNT="${FAILURE_COUNT:-0}"
|
||||
failed_at="${FAILURE_AT:-0}"
|
||||
failed_fingerprint="${FAILURE_FINGERPRINT:-}"
|
||||
# Returns 0 when this architecture's queue was processed (or was empty), 1 when
|
||||
# the release failed. Backoff and "someone else holds the lock" are not
|
||||
# failures: they are this tick deciding to do nothing.
|
||||
release_arch() {
|
||||
local arch="$1"
|
||||
local state_file fail_file
|
||||
state_file=$(sync_queue_file "$MIRROR" "$arch")
|
||||
fail_file=$(sync_fail_file "$MIRROR" "$arch")
|
||||
|
||||
if [[ "$failed_fingerprint" != "$(current_fingerprint)" ]]; then
|
||||
print_info "Repository changed since the last failure — clearing backoff and retrying"
|
||||
rm -f "$FAIL_FILE"
|
||||
FAIL_COUNT=0
|
||||
else
|
||||
delay=$(backoff_seconds "$FAIL_COUNT")
|
||||
now=$(date +%s)
|
||||
retry_at=$((failed_at + delay))
|
||||
if ((now < retry_at)); then
|
||||
print_warning "$MIRROR has failed $FAIL_COUNT time(s) on this tree — not retrying until $(date -d "@$retry_at" '+%H:%M:%S' 2>/dev/null || echo "+$((retry_at - now))s")"
|
||||
echo " Push a fix (any new commit clears this), or: rm $FAIL_FILE"
|
||||
exit 0
|
||||
fi
|
||||
print_info "Backoff elapsed — retrying $MIRROR (failure #$((FAIL_COUNT + 1)) if this fails)"
|
||||
# A queue written under the pre-architecture name belongs to x86_64.
|
||||
if [[ "$arch" == "x86_64" && ! -f "$state_file" && -f "$(legacy_sync_queue_file "$MIRROR")" ]]; then
|
||||
state_file=$(legacy_sync_queue_file "$MIRROR")
|
||||
fi
|
||||
if [[ "$arch" == "x86_64" && ! -f "$fail_file" && -f "$(legacy_sync_fail_file "$MIRROR")" ]]; then
|
||||
fail_file=$(legacy_sync_fail_file "$MIRROR")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Non-blocking: a build in progress means this tick has nothing to do.
|
||||
if ! try_release_lock; then
|
||||
holder=$(release_lock_holder)
|
||||
print_info "A release is already running (${holder:-holder unknown}) — skipping this tick"
|
||||
exit 0
|
||||
fi
|
||||
# Nothing queued: stay quiet. At a 5-minute cadence this is most
|
||||
# invocations, and a header for each would bury the runs that matter in
|
||||
# the journal.
|
||||
[[ -f "$state_file" ]] || return 0
|
||||
|
||||
print_info "State file found: $STATE_FILE"
|
||||
print_info "Starting release workflow for $MIRROR..."
|
||||
print_header "Processing Sync for $MIRROR ($arch)"
|
||||
|
||||
if "$BUILD_ROOT/bin/repo" release --mirror "$MIRROR" --skip-prod-check; then
|
||||
print_success "Release completed successfully for $MIRROR"
|
||||
rm -f "$STATE_FILE"
|
||||
rm -f "$FAIL_FILE"
|
||||
print_success "State file removed: $STATE_FILE"
|
||||
else
|
||||
status=$?
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
cat >"$FAIL_FILE" <<EOF
|
||||
FAILURE_COUNT=$FAIL_COUNT
|
||||
local fail_count=0 failed_at failed_fingerprint delay now retry_at
|
||||
if [[ -f "$fail_file" ]]; then
|
||||
FAILURE_COUNT=0 FAILURE_AT=0 FAILURE_FINGERPRINT=""
|
||||
# shellcheck disable=SC1090
|
||||
source "$fail_file" 2>/dev/null || true
|
||||
fail_count="${FAILURE_COUNT:-0}"
|
||||
failed_at="${FAILURE_AT:-0}"
|
||||
failed_fingerprint="${FAILURE_FINGERPRINT:-}"
|
||||
|
||||
if [[ "$failed_fingerprint" != "$(current_fingerprint)" ]]; then
|
||||
print_info "Repository changed since the last failure — clearing backoff and retrying"
|
||||
rm -f "$fail_file"
|
||||
fail_count=0
|
||||
else
|
||||
delay=$(backoff_seconds "$fail_count")
|
||||
now=$(date +%s)
|
||||
retry_at=$((failed_at + delay))
|
||||
if ((now < retry_at)); then
|
||||
print_warning "$MIRROR ($arch) has failed $fail_count time(s) on this tree — not retrying until $(date -d "@$retry_at" '+%H:%M:%S' 2>/dev/null || echo "+$((retry_at - now))s")"
|
||||
echo " Push a fix (any new commit clears this), or: rm $fail_file"
|
||||
return 0
|
||||
fi
|
||||
print_info "Backoff elapsed — retrying $MIRROR ($arch) (failure #$((fail_count + 1)) if this fails)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Non-blocking: a build in progress means this tick has nothing to do. The
|
||||
# lock is reentrant, so once this run holds it the remaining architectures
|
||||
# run under the same acquisition.
|
||||
if ! try_release_lock; then
|
||||
local holder
|
||||
holder=$(release_lock_holder)
|
||||
print_info "A release is already running (${holder:-holder unknown}) — skipping this tick"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_info "State file found: $state_file"
|
||||
print_info "Starting release workflow for $MIRROR ($arch)..."
|
||||
|
||||
if "$BUILD_ROOT/bin/repo" release --mirror "$MIRROR" --arch "$arch" --skip-prod-check; then
|
||||
print_success "Release completed successfully for $MIRROR ($arch)"
|
||||
local completed_state=("$state_file" "$fail_file")
|
||||
if [[ "$arch" == "x86_64" ]]; then
|
||||
completed_state+=("$(legacy_sync_queue_file "$MIRROR")" "$(legacy_sync_fail_file "$MIRROR")")
|
||||
fi
|
||||
if ! rm -f "${completed_state[@]}"; then
|
||||
print_error "Release succeeded, but its queue state could not be cleared"
|
||||
return 1
|
||||
fi
|
||||
print_success "State file removed: $state_file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
fail_count=$((fail_count + 1))
|
||||
if ! cat >"$fail_file" <<EOF
|
||||
FAILURE_COUNT=$fail_count
|
||||
FAILURE_AT=$(date +%s)
|
||||
FAILURE_FINGERPRINT=$(current_fingerprint)
|
||||
EOF
|
||||
next=$(backoff_seconds "$FAIL_COUNT")
|
||||
print_error "Release failed for $MIRROR (attempt $FAIL_COUNT)"
|
||||
print_warning "State file retained for retry: $STATE_FILE"
|
||||
then
|
||||
print_error "Could not record failure state: $fail_file"
|
||||
return 1
|
||||
fi
|
||||
local next
|
||||
next=$(backoff_seconds "$fail_count")
|
||||
print_error "Release failed for $MIRROR ($arch) (attempt $fail_count)"
|
||||
print_warning "State file retained for retry: $state_file"
|
||||
print_warning "Backing off $((next / 60))m before the next attempt; a new commit retries sooner"
|
||||
exit "$status"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
status=0
|
||||
for arch in $ARCHES; do
|
||||
release_arch "$arch" || status=1
|
||||
done
|
||||
exit "$status"
|
||||
@@ -13,6 +13,27 @@ print_header "Omarchy Package Builder"
|
||||
|
||||
DRY_RUN=false
|
||||
|
||||
# Knobs for builds driven from CI or resumed by hand. Each defaults to the
|
||||
# historical behaviour, so an unadorned `bin/build` is unchanged.
|
||||
#
|
||||
# OMARCHY_KEEP_BUILD_WORKSPACE=1 keep build-output/$MIRROR/$ARCH instead of
|
||||
# wiping it, so packages built by an earlier
|
||||
# job (or a previous, interrupted run) seed
|
||||
# the build database and resolve as
|
||||
# dependencies of what builds now.
|
||||
# OMARCHY_SKIP_BUILDER_IMAGE=1 use the omarchy-pkg-builder image already
|
||||
# present instead of building it; a workflow
|
||||
# that builds the image once with an external
|
||||
# BuildKit cache can then fan out over many
|
||||
# package jobs without each one rebuilding it.
|
||||
# OMARCHY_DEFER_RUNTIME_DEPS=true build the omarchy/omarchy-settings pair
|
||||
# with --nodeps (see build/build.sh); only
|
||||
# for a pipeline that verifies the install
|
||||
# transaction afterwards.
|
||||
KEEP_BUILD_WORKSPACE=${OMARCHY_KEEP_BUILD_WORKSPACE:-0}
|
||||
SKIP_BUILDER_IMAGE=${OMARCHY_SKIP_BUILDER_IMAGE:-0}
|
||||
DEFER_RUNTIME_DEPS=${OMARCHY_DEFER_RUNTIME_DEPS:-false}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
@@ -67,6 +88,11 @@ while [[ $# -gt 0 ]]; do
|
||||
echo " $0 --package yay"
|
||||
echo " $0 --package yay elephant cursor-bin"
|
||||
echo ""
|
||||
echo "Environment (for CI and resumed builds; defaults keep today's behaviour):"
|
||||
echo " OMARCHY_KEEP_BUILD_WORKSPACE=1 keep build-output and reuse packages already there"
|
||||
echo " OMARCHY_SKIP_BUILDER_IMAGE=1 use the existing builder image instead of building it"
|
||||
echo " OMARCHY_DEFER_RUNTIME_DEPS=true build the omarchy pair with --nodeps (transaction verified later)"
|
||||
echo ""
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
@@ -76,18 +102,55 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
require_valid_arch "$ARCH"
|
||||
|
||||
if [[ $DEFER_RUNTIME_DEPS != "false" && $DEFER_RUNTIME_DEPS != "true" ]]; then
|
||||
print_error "OMARCHY_DEFER_RUNTIME_DEPS must be true or false"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Deferring runtime dependencies is only sound for the omarchy pair, and only
|
||||
# when both halves are built together: the pair depends on each other and on
|
||||
# packages that a sharded pipeline builds in other jobs, and the consumer of
|
||||
# this mode installs the assembled set in one verified transaction. Check the
|
||||
# request here so a misuse fails before Docker starts.
|
||||
if [[ $DEFER_RUNTIME_DEPS == "true" ]]; then
|
||||
deferred_runtime=0
|
||||
deferred_settings=0
|
||||
deferred_count=0
|
||||
for package in $PACKAGES; do
|
||||
((deferred_count += 1))
|
||||
case $package in
|
||||
omarchy|omarchy-dev) deferred_runtime=1 ;;
|
||||
omarchy-settings|omarchy-settings-dev) deferred_settings=1 ;;
|
||||
*)
|
||||
print_error "OMARCHY_DEFER_RUNTIME_DEPS only applies to the omarchy/omarchy-settings pair, not $package"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if (( deferred_runtime != 1 || deferred_settings != 1 || deferred_count != 2 )); then
|
||||
print_error "OMARCHY_DEFER_RUNTIME_DEPS requires --package with exactly the omarchy pair"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Show target architecture and mirror after parsing args
|
||||
print_info "Target architecture: $ARCH"
|
||||
print_info "Mirror: $MIRROR"
|
||||
print_info "Build workspace: $BUILD_OUTPUT_DIR"
|
||||
print_info "Final output: $REPO_DIR"
|
||||
if [[ $DEFER_RUNTIME_DEPS == "true" ]]; then
|
||||
print_info "Runtime dependency checks: deferred to the install transaction"
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
print_warning "DRY RUN MODE - build plan only; no Docker or makepkg will run"
|
||||
print_warning "DRY RUN MODE - build plan only; no container or makepkg will run"
|
||||
ARCH="$ARCH" \
|
||||
MIRROR="$MIRROR" \
|
||||
PACKAGES="$PACKAGES" \
|
||||
DRY_RUN=true \
|
||||
DEFER_RUNTIME_DEPS="$DEFER_RUNTIME_DEPS" \
|
||||
PKGBUILDS_DIR="$PKGBUILDS_DIR" \
|
||||
BUILD_OUTPUT_DIR="$BUILD_OUTPUT_DIR" \
|
||||
FINAL_OUTPUT_DIR="$REPO_DIR" \
|
||||
@@ -100,21 +163,45 @@ fi
|
||||
# Create directories if they don't exist
|
||||
mkdir -p "$BUILD_OUTPUT_DIR" "$REPO_DIR" "$SRC_DIR"
|
||||
|
||||
# Check Docker is available
|
||||
check_docker
|
||||
# Check the selected container engine is available
|
||||
check_engine
|
||||
|
||||
# Setup QEMU for aarch64 builds on x86_64 hosts
|
||||
if [[ "$(uname -m)" == "x86_64" && "$ARCH" == "aarch64" ]]; then
|
||||
# Check if QEMU is already working
|
||||
if ! docker run --rm --platform linux/arm64 alpine:3.21 /bin/true >/dev/null 2>&1; then
|
||||
print_info "Setting up QEMU for ARM64 emulation..."
|
||||
setup_qemu
|
||||
# A foreign target architecture runs under QEMU user emulation. Probe by
|
||||
# actually running a container for the target platform: that is the only
|
||||
# test that covers both "binfmt not registered" and "registered but broken".
|
||||
HOST_ARCH=$(uname -m)
|
||||
[[ "$HOST_ARCH" == "arm64" ]] && HOST_ARCH=aarch64
|
||||
if [[ "$HOST_ARCH" != "$ARCH" ]]; then
|
||||
PROBE_IMAGE="alpine:3.21"
|
||||
[[ "$CONTAINER_ENGINE" == "podman" ]] && PROBE_IMAGE="docker.io/library/alpine:3.21"
|
||||
|
||||
# Rootless Podman cannot repair host binfmt state itself. Validate the flags
|
||||
# before the basic probe, because an F-only registration can start an ARM
|
||||
# container but silently breaks sudo inside it.
|
||||
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
||||
setup_qemu "$ARCH"
|
||||
fi
|
||||
|
||||
if ! "$CONTAINER_ENGINE" run "${CONTAINER_RUN_ARGS[@]}" --rm "$(get_platform_arg "$ARCH")" "$PROBE_IMAGE" /bin/true >/dev/null 2>&1; then
|
||||
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
||||
print_error "QEMU $ARCH is registered, but the container probe failed"
|
||||
print_info "Refresh the registration with: sudo systemctl restart systemd-binfmt"
|
||||
exit 1
|
||||
else
|
||||
print_info "Setting up QEMU for $ARCH emulation on this $HOST_ARCH host..."
|
||||
setup_qemu "$ARCH"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean build-output directory to start fresh
|
||||
print_info "Cleaning build workspace..."
|
||||
rm -rf "$BUILD_OUTPUT_DIR"/*
|
||||
# Clean build-output directory to start fresh, unless the caller seeded it
|
||||
# with packages from an earlier job or is resuming an interrupted run.
|
||||
if [[ $KEEP_BUILD_WORKSPACE == "1" ]]; then
|
||||
print_info "Keeping existing build workspace..."
|
||||
else
|
||||
print_info "Cleaning build workspace..."
|
||||
rm -rf "${BUILD_OUTPUT_DIR:?}"/*
|
||||
fi
|
||||
mkdir -p "$BUILD_OUTPUT_DIR"
|
||||
|
||||
# Show package info
|
||||
@@ -124,8 +211,20 @@ else
|
||||
print_info "Building unscoped packages for $MIRROR mirror"
|
||||
fi
|
||||
|
||||
# Build/update the Docker image
|
||||
build_docker_image "$BUILD_DIR" "$ARCH" "$MIRROR"
|
||||
# Build/update the Docker image, unless the caller prepared the exact image
|
||||
# already (a workflow building it once with an external BuildKit cache). A
|
||||
# missing image is an error rather than a silent rebuild: the point of the
|
||||
# flag is that every job runs the same bytes.
|
||||
IMAGE_TAG="omarchy-pkg-builder:latest-$ARCH-$MIRROR"
|
||||
if [[ $SKIP_BUILDER_IMAGE == "1" ]]; then
|
||||
if ! "$CONTAINER_ENGINE" image inspect "$IMAGE_TAG" >/dev/null 2>&1; then
|
||||
print_error "Prepared builder image is unavailable: $IMAGE_TAG"
|
||||
exit 1
|
||||
fi
|
||||
print_info "Using prepared builder image: $IMAGE_TAG"
|
||||
else
|
||||
build_docker_image "$BUILD_DIR" "$ARCH" "$MIRROR"
|
||||
fi
|
||||
|
||||
print_info "Running package build..."
|
||||
|
||||
@@ -133,9 +232,12 @@ print_info "Running package build..."
|
||||
mkdir -p "$BUILD_OUTPUT_DIR"
|
||||
mkdir -p "$REPO_DIR"
|
||||
|
||||
# Ensure output directories are writable by container user
|
||||
make_dir_writable "$BUILD_OUTPUT_DIR"
|
||||
make_dir_writable "$REPO_DIR"
|
||||
# Rootful Docker writes as the image uid, so retain its existing permission
|
||||
# workaround. Rootless Podman uses keep-id and must leave ownership/modes alone.
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
make_dir_writable "$BUILD_OUTPUT_DIR"
|
||||
make_dir_writable "$REPO_DIR"
|
||||
fi
|
||||
|
||||
# Build Docker arguments
|
||||
DOCKER_ARGS=(
|
||||
@@ -144,6 +246,7 @@ DOCKER_ARGS=(
|
||||
-e MIRROR="$MIRROR"
|
||||
-e PACKAGES="$PACKAGES"
|
||||
-e OMARCHY_RC_PINS="${OMARCHY_RC_PINS:-}"
|
||||
-e DEFER_RUNTIME_DEPS="$DEFER_RUNTIME_DEPS"
|
||||
-v "$BUILD_ROOT/build-output:/build-output"
|
||||
-v "$REPO_ROOT:/pkgs.omarchy.org"
|
||||
-v "$BUILD_DIR:/build:ro"
|
||||
@@ -151,11 +254,16 @@ DOCKER_ARGS=(
|
||||
-v "$BUILD_ROOT/pkgbuilds:/pkgbuilds:ro"
|
||||
)
|
||||
|
||||
# Podman-created images can leave WORKDIR owned by a remapped uid. Mount the
|
||||
# existing host-user-owned workspace so the builder can write there.
|
||||
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
||||
DOCKER_ARGS+=(-v "$SRC_DIR:/src")
|
||||
fi
|
||||
|
||||
# Run the builder with assembled args
|
||||
IMAGE_TAG="omarchy-pkg-builder:latest-$ARCH-$MIRROR"
|
||||
PLATFORM_ARG=$(get_platform_arg "$ARCH")
|
||||
|
||||
docker run $PLATFORM_ARG "${DOCKER_ARGS[@]}" "$IMAGE_TAG" /build/build.sh
|
||||
"$CONTAINER_ENGINE" run "${CONTAINER_RUN_ARGS[@]}" "$PLATFORM_ARG" "${DOCKER_ARGS[@]}" "$IMAGE_TAG" /build/build.sh
|
||||
|
||||
BUILD_RESULT=$?
|
||||
|
||||
|
||||
+61
-20
@@ -1,6 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Check PKGBUILD versions against published repo versions
|
||||
# Creates state files for edge and/or stable if any packages need building
|
||||
# Creates a state file per channel and architecture when packages need building
|
||||
#
|
||||
# Usage: check-versions [--pull] [--arch <arch>]
|
||||
# --pull pull the repository first (the scheduled run does this)
|
||||
# --arch <arch> check one architecture; default: every published one
|
||||
|
||||
set -e
|
||||
|
||||
@@ -10,11 +14,27 @@ source "$BUILD_ROOT/helpers/paths.sh"
|
||||
source "$BUILD_ROOT/helpers/package-metadata.sh"
|
||||
source "$BUILD_ROOT/helpers/lock-helpers.sh"
|
||||
|
||||
STATE_DIR="${OMARCHY_STATE_DIR:-/root/.state}"
|
||||
ARCH="${ARCH:-x86_64}"
|
||||
PULL=false
|
||||
ARCHES=""
|
||||
|
||||
[[ "${1:-}" == "--pull" ]] && PULL=true
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--pull)
|
||||
PULL=true
|
||||
shift
|
||||
;;
|
||||
--arch)
|
||||
require_valid_arch "$2"
|
||||
ARCHES="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
print_error "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[[ -n "$ARCHES" ]] || ARCHES=$(published_arches)
|
||||
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
@@ -59,10 +79,26 @@ get_repo_version() {
|
||||
'
|
||||
}
|
||||
|
||||
# The PKGBUILD's full version (epoch:pkgver-pkgrel) for the architecture being
|
||||
# checked. Prints nothing when pkgver or pkgrel cannot be read: a partial
|
||||
# version like "-" would compare unequal to everything published and queue a
|
||||
# rebuild on every tick, so an unreadable PKGBUILD must not queue at all.
|
||||
get_pkgbuild_version() {
|
||||
local pkgdir="$1"
|
||||
if [[ -f "$pkgdir/PKGBUILD" ]]; then
|
||||
(cd "$pkgdir" && bash -c 'source PKGBUILD 2>/dev/null; if [[ -n "$epoch" ]]; then echo "${epoch}:${pkgver}-${pkgrel}"; else echo "${pkgver}-${pkgrel}"; fi')
|
||||
local epoch pkgver pkgrel
|
||||
|
||||
[[ -f "$pkgdir/PKGBUILD" ]] || return 1
|
||||
|
||||
epoch=$(package_pkgbuild_var "$pkgdir" epoch "$ARCH")
|
||||
pkgver=$(package_pkgbuild_var "$pkgdir" pkgver "$ARCH")
|
||||
pkgrel=$(package_pkgbuild_var "$pkgdir" pkgrel "$ARCH")
|
||||
|
||||
[[ -n "$pkgver" && -n "$pkgrel" ]] || return 1
|
||||
|
||||
if [[ -n "$epoch" ]]; then
|
||||
echo "${epoch}:${pkgver}-${pkgrel}"
|
||||
else
|
||||
echo "${pkgver}-${pkgrel}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -77,8 +113,8 @@ check_vcs_unchanged() {
|
||||
|
||||
# If epoch or pkgrel changed in PKGBUILD, release even if upstream is unchanged.
|
||||
local pkgbuild_epoch pkgbuild_pkgrel
|
||||
pkgbuild_epoch=$(cd "$pkgdir" && bash -c 'source PKGBUILD 2>/dev/null; echo "${epoch:-}"')
|
||||
pkgbuild_pkgrel=$(cd "$pkgdir" && bash -c 'source PKGBUILD 2>/dev/null; echo "${pkgrel}"')
|
||||
pkgbuild_epoch=$(package_pkgbuild_var "$pkgdir" epoch "$ARCH")
|
||||
pkgbuild_pkgrel=$(package_pkgbuild_var "$pkgdir" pkgrel "$ARCH")
|
||||
|
||||
local repo_pkgrel="${repo_version##*-}"
|
||||
local repo_no_pkgrel="${repo_version%-*}"
|
||||
@@ -106,12 +142,11 @@ check_package() {
|
||||
local mirror="$3"
|
||||
|
||||
local pkgbuild_version repo_version
|
||||
pkgbuild_version=$(get_pkgbuild_version "$pkgdir")
|
||||
repo_version=$(get_repo_version "$pkg" "$mirror")
|
||||
|
||||
if [[ -z "$pkgbuild_version" ]]; then
|
||||
if ! pkgbuild_version=$(get_pkgbuild_version "$pkgdir") || [[ -z "$pkgbuild_version" ]]; then
|
||||
print_warning "$pkg: could not read pkgver/pkgrel from its PKGBUILD for $ARCH — not queueing"
|
||||
return 1
|
||||
fi
|
||||
repo_version=$(get_repo_version "$pkg" "$mirror")
|
||||
|
||||
if grep -qE '^pkgver[[:space:]]*\(\)' "$pkgdir/PKGBUILD"; then
|
||||
if [[ -n "$repo_version" && -n "$(package_extract_vcs_hash_from_version "$repo_version")" ]]; then
|
||||
@@ -147,11 +182,12 @@ check_package() {
|
||||
|
||||
check_mirror() {
|
||||
local mirror="$1"
|
||||
local state_file="$STATE_DIR/.sync-needed-$mirror"
|
||||
local state_file
|
||||
state_file=$(sync_queue_file "$mirror" "$ARCH")
|
||||
local needs_build=false
|
||||
local packages=()
|
||||
|
||||
print_info "Checking $mirror packages..."
|
||||
print_info "Checking $mirror packages for $ARCH..."
|
||||
|
||||
while IFS= read -r pkg; do
|
||||
local pkgdir="$PKGBUILDS_DIR/$pkg"
|
||||
@@ -159,7 +195,7 @@ check_mirror() {
|
||||
needs_build=true
|
||||
packages+=("$pkg")
|
||||
fi
|
||||
done < <(packages_for_unscoped_build "$mirror")
|
||||
done < <(packages_for_unscoped_build "$mirror" "$ARCH")
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -168,18 +204,23 @@ check_mirror() {
|
||||
# this to name the packages in its start report, which is the difference
|
||||
# between "a build is running" and "your package is in this build".
|
||||
printf '%s\n' "${packages[@]}" >"$state_file"
|
||||
print_success "${mirror^} needs building (${#packages[@]} packages)"
|
||||
print_success "${mirror^} ($ARCH) needs building (${#packages[@]} packages)"
|
||||
print_info "Packages: ${packages[*]}"
|
||||
print_info "State file created: $state_file"
|
||||
else
|
||||
print_info "${mirror^} is up to date"
|
||||
print_info "${mirror^} ($ARCH) is up to date"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
check_mirror edge
|
||||
check_mirror rc
|
||||
check_mirror stable
|
||||
# One pass per published architecture: the version comparison reads that
|
||||
# architecture's channel databases, and each queue is its own file.
|
||||
for ARCH in $ARCHES; do
|
||||
update_arch_paths
|
||||
check_mirror edge
|
||||
check_mirror rc
|
||||
check_mirror stable
|
||||
done
|
||||
|
||||
print_success "Version check complete!"
|
||||
+13
-7
@@ -1,21 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Clean Docker builder images and cache
|
||||
# Clean builder images and cache for the selected container engine
|
||||
# Forces a fresh image build on next run
|
||||
|
||||
set -e
|
||||
|
||||
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
||||
source "$BUILD_ROOT/helpers/message-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/docker-helpers.sh"
|
||||
|
||||
print_header "Cleaning Docker Builder Images"
|
||||
check_engine
|
||||
print_header "Cleaning Container Builder Images"
|
||||
|
||||
# Remove all omarchy-pkg-builder images
|
||||
print_info "Removing omarchy-pkg-builder images..."
|
||||
docker images omarchy-pkg-builder -q | xargs -r docker rmi -f 2>/dev/null || true
|
||||
"$CONTAINER_ENGINE" images omarchy-pkg-builder -q | xargs -r "$CONTAINER_ENGINE" rmi -f 2>/dev/null || true
|
||||
|
||||
# Clear buildx cache for these builds
|
||||
print_info "Clearing buildx cache..."
|
||||
docker buildx prune -a -f
|
||||
# Clear this engine's build cache.
|
||||
print_info "Clearing build cache..."
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
"$CONTAINER_ENGINE" buildx prune -a -f
|
||||
else
|
||||
"$CONTAINER_ENGINE" image prune --build-cache -f
|
||||
fi
|
||||
|
||||
print_success "Docker builder cache cleared"
|
||||
print_success "Container builder cache cleared"
|
||||
print_info "Next build will create fresh images"
|
||||
+7
-3
@@ -31,9 +31,13 @@ clean_packages() {
|
||||
# Skip signature files
|
||||
[[ "$pkg" == *.sig ]] && continue
|
||||
|
||||
# Extract package name (remove version and architecture)
|
||||
# Format: name-version-release-arch.pkg.tar.*
|
||||
local pkgname=$(echo "$pkg" | sed -E 's/-[0-9]+.*-(any|x86_64|i686)\.pkg\.tar\..*//')
|
||||
# Format: name-version-release-arch.pkg.tar.*. Work from the right because
|
||||
# package names can themselves contain version-like pieces (qt6-5compat,
|
||||
# nvidia-580xx-utils), while pkgver and pkgrel cannot contain hyphens.
|
||||
local stem="${pkg%%.pkg.tar.*}"
|
||||
stem="${stem%-*}" # architecture
|
||||
stem="${stem%-*}" # pkgrel
|
||||
local pkgname="${stem%-*}" # pkgver
|
||||
|
||||
# Add to array
|
||||
if [[ -n "${packages[$pkgname]}" ]]; then
|
||||
|
||||
+14
-7
@@ -21,9 +21,10 @@ BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
||||
source "$BUILD_ROOT/helpers/message-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/paths.sh"
|
||||
source "$BUILD_ROOT/helpers/host-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/package-metadata.sh"
|
||||
|
||||
UPSTREAM_URL="${OMARCHY_UPSTREAM_URL:-https://github.com/basecamp/omarchy.git}"
|
||||
EDGE_DB_URL="${OMARCHY_EDGE_DB_URL:-https://pkgs.omarchy.org/edge/x86_64/omarchy.db.tar.zst}"
|
||||
EDGE_DB_URL="${OMARCHY_EDGE_DB_URL:-https://pkgs.omarchy.org/edge/$(reference_arch)/omarchy.db.tar.zst}"
|
||||
RELEASE_PACKAGES=(omarchy omarchy-settings)
|
||||
DEFAULT_RC_REF="quattro"
|
||||
SRCDEST_DIR="$BUILD_ROOT/.srcdest"
|
||||
@@ -92,7 +93,7 @@ version_is_rc() { version_is_prerelease "$1"; }
|
||||
|
||||
pkgbuild_var() {
|
||||
local pkg="$1" var="$2"
|
||||
(cd "$BUILD_ROOT/pkgbuilds/$pkg" && bash -c "source PKGBUILD 2>/dev/null; echo \"\${$var}\"")
|
||||
package_pkgbuild_var "$BUILD_ROOT/pkgbuilds/$pkg" "$var"
|
||||
}
|
||||
|
||||
# Prints the published version of $pkg from the edge DB. Distinguishes
|
||||
@@ -327,13 +328,19 @@ regenerate_checksums() {
|
||||
|
||||
trigger_build_host() {
|
||||
local host
|
||||
queue_edge_builds() {
|
||||
mkdir -p "$STATE_DIR" || return 1
|
||||
local arch
|
||||
for arch in $(published_arches); do
|
||||
touch "$(sync_queue_file edge "$arch")" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
# Explicit host configuration outranks the local-host inference (a
|
||||
# workstation that ran a full local release carries the db marker too).
|
||||
if ! resolve_repo_host "${REPO_HOST_OVERRIDE:-}" >/dev/null && on_repo_host; then
|
||||
print_info "Triggering edge build locally (this is the build host)..."
|
||||
if mkdir -p "${OMARCHY_STATE_DIR:-/root/.state}" &&
|
||||
touch "${OMARCHY_STATE_DIR:-/root/.state}/.sync-needed-edge" &&
|
||||
systemctl start --no-block omarchy-auto-release-edge.service; then
|
||||
if queue_edge_builds && systemctl start --no-block omarchy-auto-release-edge.service; then
|
||||
print_success "Edge build triggered"
|
||||
else
|
||||
print_warning "Could not start the edge release service — the 6-hourly timer will pick it up"
|
||||
@@ -343,11 +350,11 @@ trigger_build_host() {
|
||||
if ! host=$(resolve_repo_host "${REPO_HOST_OVERRIDE:-}"); then
|
||||
print_info "No repository host configured (set OMARCHY_REPO_HOST or $BUILD_ROOT/.repo-host — any ssh destination, e.g. root@<host> or an ssh-config alias)."
|
||||
print_info "The 6-hourly auto-release timer will pick this up, or trigger manually:"
|
||||
echo " ssh <build-host> 'git -C /root/omarchy-pkgs pull --ff-only && touch /root/.state/.sync-needed-edge && systemctl start omarchy-auto-release-edge.service'"
|
||||
echo " ssh <build-host> 'git -C /root/omarchy-pkgs pull --ff-only && systemctl start omarchy-check-versions.service omarchy-auto-release-edge.service'"
|
||||
return 0
|
||||
fi
|
||||
print_info "Triggering edge build on $host..."
|
||||
if ssh "$host" 'git -C /root/omarchy-pkgs pull --ff-only && mkdir -p /root/.state && touch /root/.state/.sync-needed-edge && systemctl start --no-block omarchy-auto-release-edge.service'; then
|
||||
if ssh "$host" 'git -C /root/omarchy-pkgs pull --ff-only && cd /root/omarchy-pkgs && export BUILD_ROOT=/root/omarchy-pkgs && source helpers/paths.sh && mkdir -p "$STATE_DIR" && for arch in $(published_arches); do touch "$(sync_queue_file edge "$arch")"; done && systemctl start --no-block omarchy-auto-release-edge.service'; then
|
||||
print_success "Edge build triggered on $host"
|
||||
else
|
||||
print_warning "Could not trigger $host — the 6-hourly timer will pick it up"
|
||||
|
||||
+93
-55
@@ -18,6 +18,7 @@ set -e
|
||||
|
||||
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
||||
source "$BUILD_ROOT/helpers/message-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/docker-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/paths.sh"
|
||||
source "$BUILD_ROOT/helpers/host-helpers.sh"
|
||||
|
||||
@@ -28,7 +29,11 @@ ISO_REPO="${OMARCHY_ISO_REPO:-omacom-io/omarchy-iso}"
|
||||
DEV_BRANCH="${OMARCHY_DEV_BRANCH:-quattro}"
|
||||
|
||||
PKGS_DB_BASE="${OMARCHY_PKGS_DB_BASE:-https://pkgs.omarchy.org}"
|
||||
RC_DB_URL="$PKGS_DB_BASE/rc/x86_64/omarchy.db.tar.zst"
|
||||
# The first published architecture supplies the version-ordering floor when
|
||||
# cutting pins. Readiness checks below still verify every published
|
||||
# architecture before an RC or final release can move forward.
|
||||
OBSERVED_ARCH=$(reference_arch)
|
||||
RC_DB_URL="$PKGS_DB_BASE/rc/$OBSERVED_ARCH/omarchy.db.tar.zst"
|
||||
|
||||
SRCDEST_DIR="$BUILD_ROOT/.srcdest"
|
||||
MIRROR_CLONE="$SRCDEST_DIR/omarchy" # bare mirror (shared with bin/omarchy-pkgs)
|
||||
@@ -181,12 +186,12 @@ ensure_work_clone() {
|
||||
# Prints omarchy's published version in a channel; empty when absent, rc 2 when
|
||||
# the database cannot be read (callers must not mistake an outage for absence).
|
||||
published_version() {
|
||||
local channel="$1" tmp descs
|
||||
local channel="$1" arch="${2:-$OBSERVED_ARCH}" tmp descs
|
||||
tmp=$(mktemp) || return 2
|
||||
# A unique query string busts the CDN cache: right after a sync the plain
|
||||
# URL can keep serving the previous db for a while, which reads as "not
|
||||
# published yet" to status, the wait loop, and ship's pre-checks.
|
||||
if ! curl -sf "$PKGS_DB_BASE/$channel/x86_64/omarchy.db.tar.zst?$(date +%s%N)" -o "$tmp"; then
|
||||
if ! curl -sf "$PKGS_DB_BASE/$channel/$arch/omarchy.db.tar.zst?$(date +%s%N)" -o "$tmp"; then
|
||||
rm -f "$tmp"
|
||||
return 2
|
||||
fi
|
||||
@@ -207,6 +212,14 @@ published_version() {
|
||||
' <<<"$descs"
|
||||
}
|
||||
|
||||
all_arches_at_version() { # all_arches_at_version <channel> <pkgver>
|
||||
local channel="$1" want="$2" arch got
|
||||
for arch in $(published_arches); do
|
||||
got=$(published_version "$channel" "$arch" 2>/dev/null) || return 1
|
||||
[[ "${got%-*}" == "$want" ]] || return 1
|
||||
done
|
||||
}
|
||||
|
||||
# The rc branch of THIS repo carries the current pins. Read them without
|
||||
# touching the working tree.
|
||||
rc_branch_pin() { # prints "pkgver commit", empty when no rc branch
|
||||
@@ -251,8 +264,12 @@ fi
|
||||
git -C /root/omarchy-pkgs-rc fetch origin rc
|
||||
git -C /root/omarchy-pkgs-rc reset --hard origin/rc
|
||||
cd /root/omarchy-pkgs-rc
|
||||
OMARCHY_RC_PINS=1 OMARCHY_REPO_ROOT=/root/omarchy-pkgs/pkgs.omarchy.org \
|
||||
bin/repo release --mirror rc --package omarchy omarchy-settings --skip-prod-check
|
||||
# The pair is built once per published architecture (helpers/paths.sh on the
|
||||
# host decides which), so every architecture'"'"'s rc channel carries the pins.
|
||||
for arch in $(BUILD_ROOT=/root/omarchy-pkgs-rc bash -c "source helpers/paths.sh; published_arches"); do
|
||||
OMARCHY_RC_PINS=1 OMARCHY_REPO_ROOT=/root/omarchy-pkgs/pkgs.omarchy.org \
|
||||
bin/repo release --mirror rc --arch "$arch" --package omarchy omarchy-settings --skip-prod-check
|
||||
done
|
||||
'
|
||||
|
||||
trigger_rc_build() {
|
||||
@@ -278,19 +295,25 @@ host_advance() { # host_advance <from> <to> [extra args...]
|
||||
# against this machine's (likely stale) local tree would be wrong.
|
||||
if ! resolve_repo_host "$REPO_HOST_OVERRIDE" >/dev/null && ! on_repo_host; then
|
||||
print_no_host_help "advance $from -> $to" \
|
||||
" cd /root/omarchy-pkgs && bin/repo advance --from $from --to $to --skip-prod-check $*"
|
||||
" cd /root/omarchy-pkgs && bin/repo advance --from $from --to $to --arch all --skip-prod-check $*"
|
||||
return 1
|
||||
fi
|
||||
"$BUILD_ROOT/bin/repo" advance --from "$from" --to "$to" --skip-prod-check "$@"
|
||||
# --arch all: the host advances every architecture it publishes, so a train
|
||||
# never moves a channel for one architecture and not another.
|
||||
"$BUILD_ROOT/bin/repo" advance --from "$from" --to "$to" --arch all --skip-prod-check "$@"
|
||||
}
|
||||
|
||||
wait_for_published() { # wait_for_published <channel> <version> [timeout-seconds]
|
||||
local channel="$1" want="$2" timeout="${3:-3600}" waited=0 got
|
||||
print_info "Waiting for $want to appear in the $channel channel (up to $((timeout / 60))m)..."
|
||||
local channel="$1" want="$2" timeout="${3:-3600}" waited=0 arch got pending
|
||||
print_info "Waiting for $want in $channel for: $(published_arches | tr '\n' ' ')"
|
||||
while ((waited < timeout)); do
|
||||
got=$(published_version "$channel" 2>/dev/null) || got=""
|
||||
if [[ "${got%-*}" == "$want" ]]; then
|
||||
print_success "$channel now serves omarchy $got"
|
||||
pending=""
|
||||
for arch in $(published_arches); do
|
||||
got=$(published_version "$channel" "$arch" 2>/dev/null) || got=""
|
||||
[[ "${got%-*}" == "$want" ]] || pending+=" $arch=${got:-unreachable}"
|
||||
done
|
||||
if [[ -z "$pending" ]]; then
|
||||
print_success "$channel now serves omarchy $want on every published architecture"
|
||||
return 0
|
||||
fi
|
||||
sleep 60
|
||||
@@ -298,7 +321,7 @@ wait_for_published() { # wait_for_published <channel> <version> [timeout-seconds
|
||||
printf '.' >&2
|
||||
done
|
||||
echo "" >&2
|
||||
print_warning "Timed out waiting for $want in $channel (currently: ${got:-unknown})"
|
||||
print_warning "Timed out waiting for $want in $channel (pending:$pending)"
|
||||
print_info "The build may still be running — re-run this command to resume."
|
||||
return 1
|
||||
}
|
||||
@@ -352,8 +375,8 @@ iso_checkout() { # prints a usable omarchy-iso checkout, cloning to tmp if neede
|
||||
build_iso() { # build_iso <version> [--rc]
|
||||
local version="$1" rc_flag="${2:-}" dir
|
||||
dir=$(iso_checkout) || return 1
|
||||
if ! command -v docker >/dev/null || ! docker info >/dev/null 2>&1; then
|
||||
print_warning "Docker unavailable — cannot build the ISO here. Run on a Docker machine:"
|
||||
if [[ -z "$CONTAINER_ENGINE" ]] || ! "$CONTAINER_ENGINE" info >/dev/null 2>&1; then
|
||||
print_warning "No container engine is available — cannot build the ISO here. Run on a Docker or Podman machine:"
|
||||
echo " cd $dir && bin/omarchy-iso-release ${rc_flag:+$rc_flag }$version"
|
||||
return 1
|
||||
fi
|
||||
@@ -662,15 +685,13 @@ cmd_rc() {
|
||||
if [[ -n "$pin" ]]; then
|
||||
local pin_ver="${pin%% *}" pin_commit="${pin##* }"
|
||||
if [[ "$pin_commit" == "$head" && "$pin_ver" =~ ^${version//./\\.}rc[0-9]+$ ]]; then
|
||||
local pub
|
||||
pub=$(published_version rc 2>/dev/null) || pub=""
|
||||
if [[ "${pub%-*}" == "$pin_ver" ]]; then
|
||||
print_success "$pin_ver is already cut from this head and published to rc"
|
||||
if all_arches_at_version rc "$pin_ver"; then
|
||||
print_success "$pin_ver is already cut from this head and published to rc on every architecture"
|
||||
maybe_iso "$pin_ver" rc "$iso_mode"
|
||||
return 0
|
||||
fi
|
||||
print_info "$pin_ver is pinned from this head but not published yet — re-triggering the build"
|
||||
trigger_rc_build || true
|
||||
trigger_rc_build || return 1
|
||||
[[ "$wait" == true ]] && wait_for_published rc "$pin_ver"
|
||||
maybe_iso "$pin_ver" rc "$iso_mode"
|
||||
return 0
|
||||
@@ -686,7 +707,7 @@ cmd_rc() {
|
||||
new_ver="${new_pin%% *}"
|
||||
print_success "Pinned $new_ver (rc branch pushed)"
|
||||
|
||||
trigger_rc_build || true
|
||||
trigger_rc_build || return 1
|
||||
if [[ "$wait" == true ]]; then
|
||||
wait_for_published rc "$new_ver" || return 1
|
||||
fi
|
||||
@@ -708,9 +729,7 @@ cmd_ship() {
|
||||
exit 1
|
||||
fi
|
||||
version=$(branch_to_version "$branch")
|
||||
local stable_now
|
||||
stable_now=$(published_version stable 2>/dev/null) || stable_now=""
|
||||
if [[ "${stable_now%-*}" == "$version" ]] &&
|
||||
if all_arches_at_version stable "$version" &&
|
||||
gh release view "v$version" --repo "$UPSTREAM_REPO" >/dev/null 2>&1; then
|
||||
print_success "Nothing to ship — $version is tagged, released, and live on stable"
|
||||
exit 0
|
||||
@@ -752,10 +771,8 @@ cmd_ship() {
|
||||
echo " omarchy-release rc"
|
||||
exit 1
|
||||
fi
|
||||
local pub
|
||||
pub=$(published_version rc 2>/dev/null) || pub=""
|
||||
if [[ "${pub%-*}" != "$pin_ver" ]]; then
|
||||
print_error "$pin_ver is pinned but rc serves '${pub:-nothing}' — the candidate build hasn't published"
|
||||
if ! all_arches_at_version rc "$pin_ver"; then
|
||||
print_error "$pin_ver is pinned but is not published for every architecture"
|
||||
echo "Wait for it (or re-run: omarchy-release rc), then ship."
|
||||
exit 1
|
||||
fi
|
||||
@@ -799,10 +816,9 @@ cmd_ship() {
|
||||
|
||||
# 2. Final pins into rc. Resolve the tag we just established so the final
|
||||
# PKGBUILDs record both its provenance and its exact commit.
|
||||
local rc_pub stable_pub
|
||||
rc_pub=$(published_version rc 2>/dev/null) || rc_pub=""
|
||||
if [[ "${rc_pub%-*}" == "$version" ]]; then
|
||||
print_success "2/7 Final $version already published to rc"
|
||||
local stable_pub
|
||||
if all_arches_at_version rc "$version"; then
|
||||
print_success "2/7 Final $version already published to rc on every architecture"
|
||||
else
|
||||
if [[ "$pin_ver" != "$version" ]]; then
|
||||
print_info "2/7 Pinning final $version from tag v$version..."
|
||||
@@ -810,22 +826,21 @@ cmd_ship() {
|
||||
else
|
||||
print_info "2/7 Final $version pinned — re-triggering build"
|
||||
fi
|
||||
trigger_rc_build || true
|
||||
trigger_rc_build || exit 1
|
||||
wait_for_published rc "$version" || exit 1
|
||||
fi
|
||||
|
||||
# 3. Promote rc -> stable
|
||||
stable_pub=$(published_version stable 2>/dev/null) || stable_pub=""
|
||||
if [[ "${stable_pub%-*}" == "$version" ]]; then
|
||||
print_success "3/7 Stable already serves $version"
|
||||
if all_arches_at_version stable "$version"; then
|
||||
print_success "3/7 Stable already serves $version on every architecture"
|
||||
else
|
||||
host_advance rc stable || exit 1
|
||||
stable_pub=$(published_version stable 2>/dev/null) || stable_pub=""
|
||||
if [[ "${stable_pub%-*}" != "$version" ]]; then
|
||||
print_error "Promotion ran but stable serves '${stable_pub:-nothing}' — investigate before continuing"
|
||||
if ! all_arches_at_version stable "$version"; then
|
||||
print_error "Promotion ran but stable does not serve $version on every architecture"
|
||||
exit 1
|
||||
fi
|
||||
print_success "3/7 Promoted to stable: omarchy $stable_pub"
|
||||
stable_pub=$(published_version stable 2>/dev/null) || stable_pub="$version"
|
||||
print_success "3/7 Promoted to stable: omarchy $stable_pub on every architecture"
|
||||
fi
|
||||
|
||||
# 4. Final pins onto master (keeps edge overlap publishing and the repo record)
|
||||
@@ -908,7 +923,7 @@ next_step() { # prints "<command>|<description>"
|
||||
last=$(newest_release_branch 2>/dev/null) || last=""
|
||||
if [[ -n "$last" && "$STABLE_VER" != "<unreachable>" ]]; then
|
||||
last_ver=$(branch_to_version "$last")
|
||||
if [[ "${STABLE_VER%-*}" != "$last_ver" ]] ||
|
||||
if ! all_arches_at_version stable "$last_ver" ||
|
||||
{ command -v gh >/dev/null && ! gh release view "v$last_ver" --repo "$UPSTREAM_REPO" >/dev/null 2>&1; }; then
|
||||
echo "ship|$last_ver is tagged but not fully shipped — resume ship"
|
||||
return
|
||||
@@ -924,7 +939,7 @@ next_step() { # prints "<command>|<description>"
|
||||
echo "ship|Final $TRAIN_VER is pinned — finish shipping (re-runs are safe)"
|
||||
elif [[ "$pin_commit" != "$TRAIN_HEAD" ]]; then
|
||||
echo "rc|$TRAIN has commits newer than $pin_ver — cut the next candidate"
|
||||
elif [[ "${RC_VER%-*}" != "$pin_ver" ]]; then
|
||||
elif ! all_arches_at_version rc "$pin_ver"; then
|
||||
echo "rc|$pin_ver is pinned but not published — re-run rc to re-trigger/wait"
|
||||
else
|
||||
echo "ship|$pin_ver is published to rc — test it, then ship"
|
||||
@@ -994,20 +1009,24 @@ cmd_doctor() {
|
||||
check "makepkg available (checksums)" command -v makepkg
|
||||
check "curl available" command -v curl
|
||||
check "upstream reachable ($UPSTREAM_URL)" git ls-remote "$UPSTREAM_URL" HEAD
|
||||
local ch
|
||||
local ch arch
|
||||
for ch in edge stable; do
|
||||
if published_version "$ch" >/dev/null 2>&1; then
|
||||
print_success "$ch channel db readable"
|
||||
for arch in $(published_arches); do
|
||||
if published_version "$ch" "$arch" >/dev/null 2>&1; then
|
||||
print_success "$ch/$arch channel db readable"
|
||||
else
|
||||
print_error "$ch/$arch channel db readable"
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
done
|
||||
done
|
||||
for arch in $(published_arches); do
|
||||
if published_version rc "$arch" >/dev/null 2>&1; then
|
||||
print_success "rc/$arch channel db readable"
|
||||
else
|
||||
print_error "$ch channel db readable"
|
||||
failures=$((failures + 1))
|
||||
print_warning "rc/$arch channel db not readable — bootstrap it first: bin/repo bootstrap-rc (on the build host)"
|
||||
fi
|
||||
done
|
||||
if published_version rc >/dev/null 2>&1; then
|
||||
print_success "rc channel db readable"
|
||||
else
|
||||
print_warning "rc channel db not readable — bootstrap it first: bin/repo bootstrap-rc (on the build host)"
|
||||
fi
|
||||
local host
|
||||
if host=$(repo_host); then
|
||||
check "build host ssh ($host)" ssh -o ConnectTimeout=10 "$host" true
|
||||
@@ -1016,10 +1035,10 @@ cmd_doctor() {
|
||||
else
|
||||
print_warning "no build host configured — set OMARCHY_REPO_HOST, --host, or write an ssh destination (root@<host> or an ssh-config alias) to $BUILD_ROOT/.repo-host; until then builds trigger on the 6h timer only"
|
||||
fi
|
||||
if command -v docker >/dev/null && docker info >/dev/null 2>&1; then
|
||||
print_success "docker available (ISO builds possible here)"
|
||||
if [[ -n "$CONTAINER_ENGINE" ]] && "$CONTAINER_ENGINE" info >/dev/null 2>&1; then
|
||||
print_success "$CONTAINER_ENGINE available (ISO builds possible here)"
|
||||
else
|
||||
print_warning "docker unavailable — ISO builds will print instructions instead"
|
||||
print_warning "container engine unavailable — ISO builds will print instructions instead"
|
||||
fi
|
||||
echo ""
|
||||
if ((failures == 0)); then
|
||||
@@ -1054,6 +1073,25 @@ cmd_self_test() {
|
||||
expect "version_is_patch 5.0.0" "$(version_is_patch 5.0.0 && echo yes || echo no)" "no"
|
||||
expect "previous_patch_tag 4.0.2" "$(previous_patch_tag 4.0.2)" "v4.0.1"
|
||||
expect "previous_patch_tag 4.0.10" "$(previous_patch_tag 4.0.10)" "v4.0.9"
|
||||
|
||||
# Keep release readiness fail-closed when only one architecture has reached
|
||||
# the requested version. This replaces the network reader for this process;
|
||||
# self-test exits immediately afterwards.
|
||||
published_version() {
|
||||
case "$2" in
|
||||
x86_64) echo "${TEST_X86_VERSION:-4.0.2-1}" ;;
|
||||
aarch64) echo "${TEST_ARM_VERSION:-4.0.2-1}" ;;
|
||||
esac
|
||||
}
|
||||
PUBLISHED_ARCHES=x86_64
|
||||
expect "x86-only readiness" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "ready"
|
||||
PUBLISHED_ARCHES=aarch64
|
||||
expect "ARM-only readiness" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "ready"
|
||||
PUBLISHED_ARCHES="x86_64 aarch64"
|
||||
TEST_ARM_VERSION=4.0.1-1
|
||||
expect "mixed versions block release" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "blocked"
|
||||
TEST_ARM_VERSION=4.0.2-1
|
||||
expect "both architectures ready" "$(all_arches_at_version rc 4.0.2 && echo ready || echo blocked)" "ready"
|
||||
echo ""
|
||||
if ((failures == 0)); then
|
||||
print_success "Self-test passed"
|
||||
|
||||
+19
-8
@@ -149,11 +149,16 @@ fi
|
||||
# leave nvidia-580xx-dkms and opencl-nvidia-580xx behind. An output's own name
|
||||
# still matches, for pushing just one of them on purpose.
|
||||
#
|
||||
# pkgbase comes from .PKGINFO rather than the PKGBUILD: it is what makepkg
|
||||
# actually recorded, and it needs no guessing about which directory built what.
|
||||
pkgbase_of() {
|
||||
# Package identity comes from .PKGINFO rather than the filename or PKGBUILD: it
|
||||
# is what makepkg actually recorded, and it handles epochs and split packages.
|
||||
package_identity_of() {
|
||||
bsdtar -xOf "$1" .PKGINFO 2>/dev/null |
|
||||
awk -F ' = ' '$1 == "pkgbase" { print $2; exit }'
|
||||
awk -F ' = ' '
|
||||
$1 == "pkgname" { name = $2 }
|
||||
$1 == "pkgbase" { base = $2 }
|
||||
$1 == "pkgver" { version = $2 }
|
||||
END { print name "\t" base "\t" version }
|
||||
'
|
||||
}
|
||||
|
||||
FILES=()
|
||||
@@ -161,14 +166,18 @@ if [[ -z "$PACKAGES" ]]; then
|
||||
FILES=("${ALL_FILES[@]}")
|
||||
else
|
||||
declare -A MATCHED=()
|
||||
declare -A LATEST_FILE=()
|
||||
declare -A LATEST_VERSION=()
|
||||
for file in "${ALL_FILES[@]}"; do
|
||||
# name-version-release-arch.pkg.tar.zst -> name
|
||||
pkgname="${file%-*-*-*.pkg.tar.*}"
|
||||
pkgbase=$(pkgbase_of "$BUILD_OUTPUT_DIR/$file")
|
||||
IFS=$'\t' read -r pkgname pkgbase pkgver < <(package_identity_of "$BUILD_OUTPUT_DIR/$file")
|
||||
for wanted in $PACKAGES; do
|
||||
if [[ "$pkgname" == "$wanted" || "$pkgbase" == "$wanted" ]]; then
|
||||
FILES+=("$file")
|
||||
MATCHED["$wanted"]=1
|
||||
if [[ -z "${LATEST_FILE[$pkgname]:-}" ]] ||
|
||||
[[ $(vercmp "$pkgver" "${LATEST_VERSION[$pkgname]}") -gt 0 ]]; then
|
||||
LATEST_FILE["$pkgname"]="$file"
|
||||
LATEST_VERSION["$pkgname"]="$pkgver"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
done
|
||||
@@ -181,6 +190,8 @@ else
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
mapfile -t FILES < <(printf '%s\n' "${LATEST_FILE[@]}" | sort)
|
||||
fi
|
||||
|
||||
if [[ ${#FILES[@]} -eq 0 ]]; then
|
||||
|
||||
+5
-1
@@ -114,7 +114,11 @@ BUILT_FILES=""
|
||||
# What the scheduled version check queued, when it was the one that asked for
|
||||
# this run. Absent for a manual run, which is fine — the report just omits it.
|
||||
QUEUED_PACKAGES=""
|
||||
QUEUE_FILE="${OMARCHY_STATE_DIR:-/root/.state}/.sync-needed-$MIRROR"
|
||||
QUEUE_FILE=$(sync_queue_file "$MIRROR" "$ARCH")
|
||||
# A queue written under the pre-architecture name belongs to x86_64.
|
||||
if [[ "$ARCH" == "x86_64" && ! -s "$QUEUE_FILE" && -s "$(legacy_sync_queue_file "$MIRROR")" ]]; then
|
||||
QUEUE_FILE=$(legacy_sync_queue_file "$MIRROR")
|
||||
fi
|
||||
[[ -s "$QUEUE_FILE" ]] && QUEUED_PACKAGES=$(grep -c '' "$QUEUE_FILE")
|
||||
|
||||
if [[ "$DRY_RUN" != true ]]; then
|
||||
|
||||
+15
-10
@@ -62,8 +62,8 @@ if [[ ! -d "$REPO_DIR" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Docker is available
|
||||
check_docker
|
||||
# Check the selected container engine is available
|
||||
check_engine
|
||||
|
||||
# Find package files to confirm before running Docker
|
||||
cd "$REPO_DIR"
|
||||
@@ -88,24 +88,29 @@ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Build/update the Docker image (always use x86_64 for removal - it's architecture independent)
|
||||
# repo-remove is mirror-independent — always use the edge x86_64 image
|
||||
build_docker_image "$BUILD_DIR" "x86_64" "edge"
|
||||
# repo-remove is architecture-independent, so use a host-native edge image.
|
||||
TOOL_ARCH=$(docker_native_arch) || {
|
||||
print_error "Unsupported host architecture: $(uname -m)"
|
||||
exit 1
|
||||
}
|
||||
build_docker_image "$BUILD_DIR" "$TOOL_ARCH" "edge"
|
||||
|
||||
acquire_release_lock || exit 1
|
||||
|
||||
print_info "Removing package..."
|
||||
|
||||
# Ensure directory is writable by container user
|
||||
make_dir_writable "$REPO_DIR"
|
||||
# Rootless Podman uses keep-id and leaves host ownership/modes intact.
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
make_dir_writable "$REPO_DIR"
|
||||
fi
|
||||
|
||||
# Run the removal script in Docker (always use x86_64 image)
|
||||
docker run --rm --platform linux/amd64 \
|
||||
# Run the removal script in the host-native image.
|
||||
"$CONTAINER_ENGINE" run "${CONTAINER_RUN_ARGS[@]}" --rm "$(get_platform_arg "$TOOL_ARCH")" \
|
||||
-e ARCH="$ARCH" \
|
||||
-e MIRROR="$MIRROR" \
|
||||
-v "$REPO_ROOT:/pkgs.omarchy.org" \
|
||||
-v "$BUILD_DIR:/build:ro" \
|
||||
omarchy-pkg-builder:latest-x86_64-edge /build/remove-package.sh "$PACKAGE_NAME"
|
||||
"omarchy-pkg-builder:latest-$TOOL_ARCH-edge" /build/remove-package.sh "$PACKAGE_NAME"
|
||||
|
||||
RESULT=$?
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ set -e
|
||||
|
||||
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
||||
source "$BUILD_ROOT/helpers/message-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/docker-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/paths.sh"
|
||||
|
||||
CHECK_ONLY=false
|
||||
SKIP_TIMERS=false
|
||||
@@ -61,10 +63,12 @@ if command -v apt-get >/dev/null 2>&1; then
|
||||
DISTRO="debian"
|
||||
PKG_BSDTAR="libarchive-tools"
|
||||
PKG_DOCKER="docker.io"
|
||||
PKG_PODMAN="podman"
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
DISTRO="arch"
|
||||
PKG_BSDTAR="libarchive"
|
||||
PKG_DOCKER="docker"
|
||||
PKG_PODMAN="podman"
|
||||
else
|
||||
print_error "Unsupported distribution — need apt-get or pacman"
|
||||
exit 1
|
||||
@@ -72,18 +76,36 @@ fi
|
||||
|
||||
print_info "Distribution: $DISTRO"
|
||||
|
||||
# A fresh repository host still defaults to Docker. An explicit Podman choice,
|
||||
# or a working Podman selected by the shared helper, is left alone.
|
||||
if [[ -z "$CONTAINER_ENGINE" ]]; then
|
||||
CONTAINER_ENGINE=docker
|
||||
export CONTAINER_ENGINE
|
||||
fi
|
||||
if ! container_engine_supported; then
|
||||
print_error "Unsupported CONTAINER_ENGINE: $CONTAINER_ENGINE (use docker or podman)"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
PKG_ENGINE="$PKG_DOCKER"
|
||||
ENGINE_NAME="Docker"
|
||||
else
|
||||
PKG_ENGINE="$PKG_PODMAN"
|
||||
ENGINE_NAME="Podman"
|
||||
fi
|
||||
|
||||
if [[ "$CHECK_ONLY" != true && $EUID -ne 0 ]]; then
|
||||
print_error "Run as root (installing packages and systemd units)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Docker and the release timers are both systemd units. Say so plainly rather
|
||||
# than failing later on a missing command — a container is the usual way to end
|
||||
# up here, and it cannot be a repository host.
|
||||
# The release timers are systemd units. Say so plainly rather than failing
|
||||
# later on a missing command — a container is the usual way to end up here,
|
||||
# and it cannot be a repository host.
|
||||
if [[ "$CHECK_ONLY" != true ]] && ! command -v systemctl >/dev/null 2>&1; then
|
||||
print_error "systemctl not found — the repository host must run systemd"
|
||||
echo ""
|
||||
echo "Docker and the release timers are systemd units. This looks like a"
|
||||
echo "The release timers are systemd units. This looks like a"
|
||||
echo "container; run setup on the host itself."
|
||||
exit 1
|
||||
fi
|
||||
@@ -139,24 +161,27 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- docker ------------------------------------------------------------------
|
||||
# --- container engine --------------------------------------------------------
|
||||
|
||||
# Docker is left alone when it already works. A host may well be running a
|
||||
# The selected engine is left alone when it already works. A host may be running a
|
||||
# version from Docker's own repository rather than the distribution's, and
|
||||
# replacing that underneath a working builder would be a poor trade for
|
||||
# tidiness.
|
||||
print_info "Checking Docker..."
|
||||
print_info "Checking $ENGINE_NAME..."
|
||||
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
print_step "docker present: $(docker --version 2>/dev/null | head -1)"
|
||||
if docker info >/dev/null 2>&1; then
|
||||
print_success "Docker is installed and running — leaving it alone"
|
||||
if command -v "$CONTAINER_ENGINE" >/dev/null 2>&1; then
|
||||
print_step "$CONTAINER_ENGINE present: $("$CONTAINER_ENGINE" --version 2>/dev/null | head -1)"
|
||||
if "$CONTAINER_ENGINE" info >/dev/null 2>&1; then
|
||||
print_success "$ENGINE_NAME is installed and available — leaving it alone"
|
||||
elif [[ "$CHECK_ONLY" == true ]]; then
|
||||
print_warning "Docker is installed but not running; would start it"
|
||||
print_warning "$ENGINE_NAME is installed but unavailable"
|
||||
elif [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
||||
print_error "Podman is installed but unavailable to the current user"
|
||||
exit 1
|
||||
else
|
||||
print_info "Docker is installed but not running — starting it"
|
||||
systemctl enable --now docker.service
|
||||
if docker info >/dev/null 2>&1; then
|
||||
if "$CONTAINER_ENGINE" info >/dev/null 2>&1; then
|
||||
print_success "Docker started"
|
||||
else
|
||||
print_error "Docker is installed but still not responding"
|
||||
@@ -165,16 +190,24 @@ if command -v docker >/dev/null 2>&1; then
|
||||
fi
|
||||
fi
|
||||
elif [[ "$CHECK_ONLY" == true ]]; then
|
||||
print_warning "Would install $PKG_DOCKER and enable it"
|
||||
else
|
||||
print_info "Installing $PKG_DOCKER..."
|
||||
install_packages "$PKG_DOCKER"
|
||||
systemctl enable --now docker.service
|
||||
if docker info >/dev/null 2>&1; then
|
||||
print_success "Docker installed and running"
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
print_warning "Would install $PKG_ENGINE and enable it"
|
||||
else
|
||||
print_error "Docker installed but not responding"
|
||||
echo " Check 'systemctl status docker' — builds cannot run without it."
|
||||
print_warning "Would install $PKG_ENGINE"
|
||||
fi
|
||||
else
|
||||
print_info "Installing $PKG_ENGINE..."
|
||||
install_packages "$PKG_ENGINE"
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
systemctl enable --now docker.service
|
||||
fi
|
||||
if "$CONTAINER_ENGINE" info >/dev/null 2>&1; then
|
||||
print_success "$ENGINE_NAME installed and available"
|
||||
else
|
||||
print_error "$ENGINE_NAME installed but not responding"
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
echo " Check 'systemctl status docker' — builds cannot run without it."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -237,6 +270,10 @@ echo ""
|
||||
|
||||
# --- release timers ----------------------------------------------------------
|
||||
|
||||
print_info "Published architectures: $(published_arches | tr '\n' ' ')"
|
||||
echo " (PUBLISHED_ARCHES in helpers/paths.sh; OMARCHY_ARCHES overrides a one-off command)"
|
||||
echo ""
|
||||
|
||||
TIMERS=(omarchy-check-versions omarchy-auto-release-edge omarchy-auto-release-rc omarchy-auto-release-stable)
|
||||
|
||||
if [[ "$SKIP_TIMERS" == true ]]; then
|
||||
|
||||
@@ -52,8 +52,8 @@ if [[ ! -d "$BUILD_OUTPUT_DIR" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Docker is available
|
||||
check_docker
|
||||
# Check the selected container engine is available
|
||||
check_engine
|
||||
|
||||
# Check GPG credentials are in environment
|
||||
if [[ -z "$GPG_PRIVATE_KEY" ]]; then
|
||||
@@ -66,23 +66,30 @@ if [[ -z "$GPG_PASSPHRASE" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build/update the Docker image (always use x86_64 for signing - it's architecture independent)
|
||||
build_docker_image "$BUILD_DIR" "x86_64" "$MIRROR"
|
||||
# Signing is architecture-independent, so run its utility container natively
|
||||
# on either an x86_64 or ARM host.
|
||||
TOOL_ARCH=$(docker_native_arch) || {
|
||||
print_error "Unsupported host architecture: $(uname -m)"
|
||||
exit 1
|
||||
}
|
||||
build_docker_image "$BUILD_DIR" "$TOOL_ARCH" "$MIRROR"
|
||||
|
||||
print_info "Running package signing..."
|
||||
|
||||
# Ensure output directory is writable by container user
|
||||
make_dir_writable "$BUILD_OUTPUT_DIR"
|
||||
# Rootless Podman uses keep-id and leaves host ownership/modes intact.
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
make_dir_writable "$BUILD_OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
# Run the signing script in Docker (always use x86_64 image)
|
||||
docker run --rm --platform linux/amd64 \
|
||||
# Run the signing script in the host-native image.
|
||||
"$CONTAINER_ENGINE" run "${CONTAINER_RUN_ARGS[@]}" --rm "$(get_platform_arg "$TOOL_ARCH")" \
|
||||
-e ARCH="$ARCH" \
|
||||
-e MIRROR="$MIRROR" \
|
||||
-e GPG_PRIVATE_KEY="$GPG_PRIVATE_KEY" \
|
||||
-e GPG_PASSPHRASE="$GPG_PASSPHRASE" \
|
||||
-v "$BUILD_ROOT/build-output:/build-output" \
|
||||
-v "$BUILD_DIR:/build:ro" \
|
||||
omarchy-pkg-builder:latest-x86_64-$MIRROR /build/sign.sh
|
||||
"omarchy-pkg-builder:latest-$TOOL_ARCH-$MIRROR" /build/sign.sh
|
||||
|
||||
SIGN_RESULT=$?
|
||||
|
||||
|
||||
+249
-60
@@ -17,11 +17,14 @@ SELF_TEST=false
|
||||
# rebuilding for it would ship a package built against the wrong ABI.
|
||||
OFFICIAL_REPOS=" core extra multilib core-debug extra-debug "
|
||||
|
||||
# The published repository, used as the floor a bumped pkgrel has to clear.
|
||||
# Only x86_64 is published today; aarch64 has no repository to compare against.
|
||||
# The published repositories are the floor a bumped pkgrel has to clear.
|
||||
PUBLISHED_BASE_URL="${OMARCHY_PUBLISHED_BASE_URL:-https://pkgs.omarchy.org}"
|
||||
PUBLISHED_MIRRORS=(edge stable)
|
||||
PUBLISHED_ARCH=x86_64
|
||||
|
||||
# Arch Linux ARM has no dated snapshots. This is the same live repository the
|
||||
# aarch64 builder resolves; override it only when the builder mirror changes.
|
||||
ALARM_BASE_URL="${OMARCHY_ALARM_BASE_URL:-https://fl.us.mirror.archlinuxarm.org/aarch64}"
|
||||
ALARM_REPOS=(core extra alarm aur)
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
@@ -34,10 +37,13 @@ A package opts in by naming those dependencies in .omarchy/package.json:
|
||||
|
||||
{ "source": "aur", "sync": false, "rebuild_on": ["qt6-base"] }
|
||||
|
||||
The versions the current pkgrel was bumped for are recorded alongside, in
|
||||
rebuilt_against, and written by this command:
|
||||
The versions the current pkgrel was bumped for are recorded per published
|
||||
architecture in rebuilt_against, and written by this command:
|
||||
|
||||
{ "rebuild_on": ["qt6-base"], "rebuilt_against": { "qt6-base": "6.11.2-2" } }
|
||||
{ "rebuild_on": ["qt6-base"], "rebuilt_against": {
|
||||
"x86_64": { "qt6-base": "6.11.2-3" },
|
||||
"aarch64": { "qt6-base": "6.11.2-2" }
|
||||
} }
|
||||
|
||||
pkgrel is bumped unless every package named in rebuild_on is recorded and still
|
||||
matches. A name that is missing from the record counts as changed, so opting a
|
||||
@@ -60,8 +66,9 @@ Examples:
|
||||
$0 # Update every package that declares rebuild_on
|
||||
$0 quickshell-git # Update specific packages
|
||||
|
||||
Trigger versions are read from the local pacman database, so sync it first
|
||||
(pacman -Sy) or this reports whatever that database last saw.
|
||||
x86_64 trigger versions come from the local pacman database; aarch64 versions
|
||||
come from the live Arch Linux ARM repository database. Only architectures in
|
||||
PUBLISHED_ARCHES that the package supports are considered.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -94,7 +101,7 @@ SPECIFIC_MODE=false
|
||||
# The version of a trigger package as the build container would resolve it.
|
||||
# A name pacman does not know reports nothing rather than failing, so the caller
|
||||
# gets to say which package was left alone instead of the run dying here.
|
||||
repo_version() {
|
||||
native_repo_version() {
|
||||
local package="$1"
|
||||
local info
|
||||
|
||||
@@ -108,9 +115,59 @@ repo_version() {
|
||||
' <<<"$info"
|
||||
}
|
||||
|
||||
load_alarm_repo() {
|
||||
local repo="$1" db index
|
||||
index="$TEMP_DIR/alarm-$repo.index"
|
||||
[[ -f "$index" ]] && return 0
|
||||
|
||||
db="$TEMP_DIR/alarm-$repo.db"
|
||||
if ! curl -fsSL --max-time 120 -o "$db" "$ALARM_BASE_URL/$repo/$repo.db" 2>/dev/null; then
|
||||
print_error "Could not read the aarch64 $repo repository database"
|
||||
return 1
|
||||
fi
|
||||
if ! tar -tf "$db" >/dev/null 2>&1; then
|
||||
print_error "Unreadable aarch64 $repo repository database"
|
||||
return 1
|
||||
fi
|
||||
|
||||
tar -xOf "$db" --wildcards '*/desc' 2>/dev/null | awk '
|
||||
function emit() {
|
||||
if (name != "" && version != "") {
|
||||
print name "\t" version
|
||||
if (base != "" && base != name) print base "\t" version
|
||||
}
|
||||
name=""; base=""; version=""
|
||||
}
|
||||
$0 == "%FILENAME%" { emit(); next }
|
||||
$0 == "%NAME%" { if (name != "" && version != "") emit(); getline; name=$0; next }
|
||||
$0 == "%BASE%" { getline; base=$0; next }
|
||||
$0 == "%VERSION%" { getline; version=$0; next }
|
||||
END { emit() }
|
||||
' >"$index"
|
||||
}
|
||||
|
||||
alarm_repo_version() {
|
||||
local package="$1" repo version
|
||||
for repo in "${ALARM_REPOS[@]}"; do
|
||||
load_alarm_repo "$repo" || return 1
|
||||
version=$(awk -F '\t' -v package="$package" '$1 == package { print $2; exit }' "$TEMP_DIR/alarm-$repo.index")
|
||||
if [[ -n "$version" ]]; then
|
||||
echo "$version"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
repo_version() { # repo_version <arch> <package>
|
||||
case "$1" in
|
||||
x86_64) native_repo_version "$2" ;;
|
||||
aarch64) alarm_repo_version "$2" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
declare -A PUBLISHED_VERSION=()
|
||||
PUBLISHED_LOADED=false
|
||||
PUBLISHED_AVAILABLE=true
|
||||
|
||||
remember_published() {
|
||||
local name="$1"
|
||||
@@ -131,34 +188,35 @@ load_published_versions() {
|
||||
[[ "$PUBLISHED_LOADED" == true ]] && return 0
|
||||
PUBLISHED_LOADED=true
|
||||
|
||||
local mirror db name base version
|
||||
local arch mirror db name base version
|
||||
|
||||
for mirror in "${PUBLISHED_MIRRORS[@]}"; do
|
||||
db="$TEMP_DIR/published-$mirror.db.tar.zst"
|
||||
for arch in $(published_arches); do
|
||||
for mirror in "${PUBLISHED_MIRRORS[@]}"; do
|
||||
db="$TEMP_DIR/published-$mirror-$arch.db.tar.zst"
|
||||
|
||||
if ! curl -fsSL --max-time 120 -o "$db" \
|
||||
"$PUBLISHED_BASE_URL/$mirror/$PUBLISHED_ARCH/omarchy.db.tar.zst" 2>/dev/null; then
|
||||
print_warning "Could not read the published $mirror database; bumps are not checked against it this run"
|
||||
PUBLISHED_AVAILABLE=false
|
||||
continue
|
||||
fi
|
||||
if ! curl -fsSL --max-time 120 -o "$db" \
|
||||
"$PUBLISHED_BASE_URL/$mirror/$arch/omarchy.db.tar.zst" 2>/dev/null; then
|
||||
print_warning "Could not read the published $mirror/$arch database; bumps are not checked against it this run"
|
||||
continue
|
||||
fi
|
||||
|
||||
while IFS=$'\t' read -r name base version; do
|
||||
[[ -n "$name" && -n "$version" ]] && remember_published "$name" "$version"
|
||||
[[ -n "$base" && -n "$version" ]] && remember_published "$base" "$version"
|
||||
done < <(
|
||||
tar -xOf "$db" --wildcards '*/desc' 2>/dev/null | awk '
|
||||
function emit() {
|
||||
if (name != "" && version != "") print name "\t" base "\t" version
|
||||
name=""; base=""; version=""
|
||||
}
|
||||
$0 == "%FILENAME%" { emit(); next }
|
||||
$0 == "%NAME%" { if (name != "" && version != "") emit(); getline; name=$0; next }
|
||||
$0 == "%BASE%" { getline; base=$0; next }
|
||||
$0 == "%VERSION%" { getline; version=$0; next }
|
||||
END { emit() }
|
||||
'
|
||||
)
|
||||
while IFS=$'\t' read -r name base version; do
|
||||
[[ -n "$name" && -n "$version" ]] && remember_published "$name" "$version"
|
||||
[[ -n "$base" && -n "$version" ]] && remember_published "$base" "$version"
|
||||
done < <(
|
||||
tar -xOf "$db" --wildcards '*/desc' 2>/dev/null | awk '
|
||||
function emit() {
|
||||
if (name != "" && version != "") print name "\t" base "\t" version
|
||||
name=""; base=""; version=""
|
||||
}
|
||||
$0 == "%FILENAME%" { emit(); next }
|
||||
$0 == "%NAME%" { if (name != "" && version != "") emit(); getline; name=$0; next }
|
||||
$0 == "%BASE%" { getline; base=$0; next }
|
||||
$0 == "%VERSION%" { getline; version=$0; next }
|
||||
END { emit() }
|
||||
'
|
||||
)
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
@@ -179,7 +237,7 @@ pkgbuild_field() {
|
||||
local package_dir="$1"
|
||||
local field="$2"
|
||||
|
||||
(cd "$package_dir" && env -u OMARCHY_SRC bash -c "source PKGBUILD 2>/dev/null; echo \"\${$field:-}\"")
|
||||
package_pkgbuild_var "$package_dir" "$field"
|
||||
}
|
||||
|
||||
# 2 -> 3, and 1.1 -> 1.2. Anything else is a pkgrel this command has no business
|
||||
@@ -252,7 +310,17 @@ record_triggers() {
|
||||
local package_dir="$1"
|
||||
local current="$2"
|
||||
|
||||
write_metadata "$package_dir" '.rebuilt_against = $current' --argjson current "$current"
|
||||
# A flat record is the legacy x86_64 shape. Preserve records for
|
||||
# architectures outside this run, then replace the ones just rebuilt.
|
||||
write_metadata "$package_dir" '
|
||||
(.rebuilt_against // {}) as $old |
|
||||
(if ($old | length) == 0 then {}
|
||||
elif ($old | to_entries | all(.value | type == "string"))
|
||||
then {x86_64: $old}
|
||||
else $old
|
||||
end) as $by_arch |
|
||||
.rebuilt_against = ($by_arch * $current)
|
||||
' --argjson current "$current"
|
||||
}
|
||||
|
||||
# Metadata that does not parse would otherwise drop its package out of the run
|
||||
@@ -300,21 +368,41 @@ sync_package() {
|
||||
|
||||
print_info "Checking $package against ${triggers[*]}..."
|
||||
|
||||
local current="{}" trigger version
|
||||
for trigger in "${triggers[@]}"; do
|
||||
version=$(repo_version "$trigger")
|
||||
if [[ -z "$version" ]]; then
|
||||
print_error " $trigger is in no official repository; leaving $package alone"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
if ! current=$(jq -c --arg name "$trigger" --arg version "$version" '.[$name] = $version' <<<"$current"); then
|
||||
print_error " Could not record $trigger $version for $package"
|
||||
local current="{}" arch arch_current trigger version considered=0
|
||||
for arch in $(published_arches); do
|
||||
package_supports_arch "$package_dir" "$arch" || continue
|
||||
considered=$((considered + 1))
|
||||
arch_current="{}"
|
||||
for trigger in "${triggers[@]}"; do
|
||||
if ! version=$(repo_version "$arch" "$trigger"); then
|
||||
print_error " Could not read $arch repository versions; leaving $package alone"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$version" ]]; then
|
||||
print_error " $trigger is in no $arch repository; leaving $package alone"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
if ! arch_current=$(jq -c --arg name "$trigger" --arg version "$version" '.[$name] = $version' <<<"$arch_current"); then
|
||||
print_error " Could not record $arch/$trigger $version for $package"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
if ! current=$(jq -c --arg arch "$arch" --argjson versions "$arch_current" '.[$arch] = $versions' <<<"$current"); then
|
||||
print_error " Could not record $arch trigger versions for $package"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
if ((considered == 0)); then
|
||||
print_info " Skipping: not built for any published architecture"
|
||||
((++SKIPPED))
|
||||
return 0
|
||||
fi
|
||||
|
||||
local recorded
|
||||
if ! recorded=$(package_metadata_value "$package_dir" '.rebuilt_against' ""); then
|
||||
print_error " Could not read .omarchy/package.json for $package"
|
||||
@@ -323,13 +411,20 @@ sync_package() {
|
||||
fi
|
||||
[[ -n "$recorded" && "$recorded" != "null" ]] || recorded="{}"
|
||||
|
||||
# Before architecture-specific records existed, rebuilt_against described
|
||||
# x86_64. Read it that way without forcing a metadata-only migration.
|
||||
if jq -e 'to_entries | all(.value | type == "string")' >/dev/null <<<"$recorded"; then
|
||||
recorded=$(jq -c '{x86_64: .}' <<<"$recorded")
|
||||
fi
|
||||
|
||||
# Walk the declared triggers rather than the record, so a name the record does
|
||||
# not carry reads as changed instead of going unexamined forever.
|
||||
local moved
|
||||
if ! moved=$(jq -r --argjson recorded "$recorded" '
|
||||
to_entries
|
||||
| map(select($recorded[.key] != .value)
|
||||
| "\(.key) \($recorded[.key] // "unrecorded") -> \(.value)")
|
||||
[to_entries[] as $arch
|
||||
| $arch.value | to_entries[] as $trigger
|
||||
| select($recorded[$arch.key][$trigger.key] != $trigger.value)
|
||||
| "\($arch.key)/\($trigger.key) \($recorded[$arch.key][$trigger.key] // "unrecorded") -> \($trigger.value)"]
|
||||
| join(", ")
|
||||
' <<<"$current"); then
|
||||
print_error " Could not compare recorded trigger versions for $package"
|
||||
@@ -338,7 +433,7 @@ sync_package() {
|
||||
fi
|
||||
|
||||
if [[ -z "$moved" ]]; then
|
||||
print_info " Already rebuilt against $(jq -r 'to_entries | map("\(.key) \(.value)") | join(", ")' <<<"$current")"
|
||||
print_info " Already rebuilt against every published architecture"
|
||||
((++SKIPPED))
|
||||
return 0
|
||||
fi
|
||||
@@ -466,11 +561,11 @@ selftest_root() {
|
||||
}
|
||||
|
||||
selftest_package() {
|
||||
local root="$1" name="$2" pkgrel="$3" metadata="$4" pkgver="${5:-1.0}"
|
||||
local root="$1" name="$2" pkgrel="$3" metadata="$4" pkgver="${5:-1.0}" arches="${6:-x86_64}"
|
||||
local dir="$root/pkgbuilds/$name"
|
||||
|
||||
mkdir -p "$dir/.omarchy"
|
||||
printf 'pkgname=%s\npkgver=%s\npkgrel=%s\narch=(x86_64)\n' "$name" "$pkgver" "$pkgrel" > "$dir/PKGBUILD"
|
||||
printf 'pkgname=%s\npkgver=%s\npkgrel=%s\narch=(%s)\n' "$name" "$pkgver" "$pkgrel" "$arches" > "$dir/PKGBUILD"
|
||||
printf '%s\n' "$metadata" > "$dir/.omarchy/package.json"
|
||||
}
|
||||
|
||||
@@ -514,19 +609,51 @@ selftest_published() {
|
||||
cat > "$root/stub/curl" <<'STUB'
|
||||
#!/bin/bash
|
||||
out=""
|
||||
url=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-o) out="$2"; shift 2 ;;
|
||||
*) shift ;;
|
||||
*) url="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
db="$(dirname "$0")/omarchy.db.tar.zst"
|
||||
if [[ "$url" == */aarch64/* ]]; then
|
||||
repo="${url%/*}"
|
||||
repo="${repo##*/}"
|
||||
db="$(dirname "$0")/alarm-$repo.db"
|
||||
else
|
||||
db="$(dirname "$0")/omarchy.db.tar.zst"
|
||||
fi
|
||||
[[ -f "$db" && -n "$out" ]] || exit 22
|
||||
cp "$db" "$out"
|
||||
STUB
|
||||
chmod +x "$root/stub/curl"
|
||||
}
|
||||
|
||||
selftest_alarm() {
|
||||
local root="$1"
|
||||
shift
|
||||
local repo staging="$root/stub/alarm-db" entry name version
|
||||
|
||||
for repo in core extra; do
|
||||
rm -rf "$staging"
|
||||
mkdir -p "$staging"
|
||||
if [[ "$repo" == "core" ]]; then
|
||||
mkdir -p "$staging/unrelated-1-1"
|
||||
printf '%%FILENAME%%\nunrelated-1-1-aarch64.pkg.tar.zst\n\n%%NAME%%\nunrelated\n\n%%BASE%%\nunrelated\n\n%%VERSION%%\n1-1\n' \
|
||||
> "$staging/unrelated-1-1/desc"
|
||||
else
|
||||
for entry in "$@"; do
|
||||
name="${entry%=*}"
|
||||
version="${entry#*=}"
|
||||
mkdir -p "$staging/$name-$version"
|
||||
printf '%%FILENAME%%\n%s-%s-aarch64.pkg.tar.zst\n\n%%NAME%%\n%s\n\n%%BASE%%\n%s\n\n%%VERSION%%\n%s\n' \
|
||||
"$name" "$version" "$name" "$name" "$version" > "$staging/$name-$version/desc"
|
||||
done
|
||||
fi
|
||||
tar -czf "$root/stub/alarm-$repo.db" -C "$staging" .
|
||||
done
|
||||
}
|
||||
|
||||
cmd_self_test() {
|
||||
local failures=0
|
||||
local root
|
||||
@@ -545,7 +672,8 @@ cmd_self_test() {
|
||||
local root="$1"
|
||||
shift
|
||||
local status=0
|
||||
PATH="$root/stub:$PATH" "$root/bin/sync-rebuilds" "$@" > "$root/output" 2>&1 || status=$?
|
||||
OMARCHY_ARCHES="${SELFTEST_ARCHES:-x86_64}" \
|
||||
PATH="$root/stub:$PATH" "$root/bin/sync-rebuilds" "$@" > "$root/output" 2>&1 || status=$?
|
||||
echo "$status"
|
||||
}
|
||||
|
||||
@@ -563,7 +691,7 @@ cmd_self_test() {
|
||||
check "run succeeds" 0 "$(run_case "$root")"
|
||||
check "pkgrel bumped" 2 "$(pkgrel_of "$root/pkgbuilds/t-partial")"
|
||||
check "unrecorded trigger now recorded" "2-2" \
|
||||
"$(jq -r '.rebuilt_against["dep-b"]' "$root/pkgbuilds/t-partial/.omarchy/package.json")"
|
||||
"$(jq -r '.rebuilt_against.x86_64["dep-b"]' "$root/pkgbuilds/t-partial/.omarchy/package.json")"
|
||||
|
||||
echo "Opting a package in buys a rebuild rather than a bare record:"
|
||||
root=$(selftest_root fresh)
|
||||
@@ -573,7 +701,7 @@ cmd_self_test() {
|
||||
check "run succeeds" 0 "$(run_case "$root")"
|
||||
check "pkgrel bumped" 2 "$(pkgrel_of "$root/pkgbuilds/t-fresh")"
|
||||
check "trigger recorded" "1-1" \
|
||||
"$(jq -r '.rebuilt_against["dep-a"]' "$root/pkgbuilds/t-fresh/.omarchy/package.json")"
|
||||
"$(jq -r '.rebuilt_against.x86_64["dep-a"]' "$root/pkgbuilds/t-fresh/.omarchy/package.json")"
|
||||
|
||||
echo "An unchanged package is left alone:"
|
||||
root=$(selftest_root current)
|
||||
@@ -612,6 +740,67 @@ cmd_self_test() {
|
||||
check "suffix recorded for the next AUR sync" 1 \
|
||||
"$(jq -r '.pkgrel.suffix' "$root/pkgbuilds/t-aur/.omarchy/package.json")"
|
||||
|
||||
echo "A dependency is tracked independently for both published architectures:"
|
||||
root=$(selftest_root multiarch)
|
||||
selftest_package "$root" t-multi 1 '{"source":"local","rebuild_on":["dep-a"],"rebuilt_against":{"dep-a":"1-1"}}' 1.0 'x86_64 aarch64'
|
||||
selftest_pacman "$root" dep-a=1-1
|
||||
selftest_published "$root"
|
||||
selftest_alarm "$root" dep-a=2-1
|
||||
SELFTEST_ARCHES="x86_64 aarch64"
|
||||
check "run succeeds" 0 "$(run_case "$root")"
|
||||
unset SELFTEST_ARCHES
|
||||
check "pkgrel bumped once" 2 "$(pkgrel_of "$root/pkgbuilds/t-multi")"
|
||||
check "x86_64 trigger recorded" "1-1" \
|
||||
"$(jq -r '.rebuilt_against.x86_64["dep-a"]' "$root/pkgbuilds/t-multi/.omarchy/package.json")"
|
||||
check "aarch64 trigger recorded" "2-1" \
|
||||
"$(jq -r '.rebuilt_against.aarch64["dep-a"]' "$root/pkgbuilds/t-multi/.omarchy/package.json")"
|
||||
|
||||
echo "An ARM-only run records only the ARM dependency state:"
|
||||
root=$(selftest_root arm-only)
|
||||
selftest_package "$root" t-arm 1 '{"source":"local","rebuild_on":["dep-a"]}' 1.0 'x86_64 aarch64'
|
||||
selftest_pacman "$root"
|
||||
selftest_published "$root"
|
||||
selftest_alarm "$root" dep-a=2-1
|
||||
SELFTEST_ARCHES=aarch64
|
||||
check "run succeeds" 0 "$(run_case "$root")"
|
||||
unset SELFTEST_ARCHES
|
||||
check "pkgrel bumped" 2 "$(pkgrel_of "$root/pkgbuilds/t-arm")"
|
||||
check "ARM trigger recorded" "2-1" \
|
||||
"$(jq -r '.rebuilt_against.aarch64["dep-a"]' "$root/pkgbuilds/t-arm/.omarchy/package.json")"
|
||||
check "x86_64 was not consulted" "false" \
|
||||
"$(jq -r '.rebuilt_against | has("x86_64")' "$root/pkgbuilds/t-arm/.omarchy/package.json")"
|
||||
|
||||
echo "An x86-only package ignores ARM during a dual-architecture run:"
|
||||
root=$(selftest_root x86-package)
|
||||
selftest_package "$root" t-x86 1 '{"source":"local","rebuild_on":["dep-a"],"rebuilt_against":{"dep-a":"1-1"}}'
|
||||
selftest_pacman "$root" dep-a=1-1
|
||||
selftest_published "$root"
|
||||
selftest_alarm "$root" dep-a=2-1
|
||||
SELFTEST_ARCHES="x86_64 aarch64"
|
||||
check "run succeeds" 0 "$(run_case "$root")"
|
||||
unset SELFTEST_ARCHES
|
||||
check "pkgrel untouched" 1 "$(pkgrel_of "$root/pkgbuilds/t-x86")"
|
||||
|
||||
echo "A PKGBUILD that branches on CARCH at file scope still reads its version:"
|
||||
root=$(selftest_root carch-branch)
|
||||
mkdir -p "$root/pkgbuilds/t-carch/.omarchy"
|
||||
cat > "$root/pkgbuilds/t-carch/PKGBUILD" <<'PKG'
|
||||
pkgname=t-carch
|
||||
case "$CARCH" in
|
||||
x86_64) _suffix=x64 ;;
|
||||
aarch64) _suffix=arm64 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
pkgver=1.0
|
||||
pkgrel=3
|
||||
arch=(x86_64 aarch64)
|
||||
PKG
|
||||
echo '{"source":"local"}' > "$root/pkgbuilds/t-carch/.omarchy/package.json"
|
||||
check "pkgver read for x86_64" "1.0" "$(package_pkgbuild_var "$root/pkgbuilds/t-carch" pkgver x86_64)"
|
||||
check "pkgrel read for x86_64" "3" "$(package_pkgbuild_var "$root/pkgbuilds/t-carch" pkgrel x86_64)"
|
||||
check "arch-specific value follows CARCH" "arm64" "$(package_pkgbuild_var "$root/pkgbuilds/t-carch" _suffix aarch64)"
|
||||
check "unsupported arch reports failure" 1 "$(package_pkgbuild_var "$root/pkgbuilds/t-carch" pkgver armv7h >/dev/null; echo $?)"
|
||||
|
||||
echo ""
|
||||
if [[ "$failures" -eq 0 ]]; then
|
||||
print_success "Self-test passed"
|
||||
@@ -626,9 +815,9 @@ if [[ "$SELF_TEST" == true ]]; then
|
||||
exit $?
|
||||
fi
|
||||
|
||||
for tool in pacman vercmp jq curl; do
|
||||
for tool in pacman vercmp jq curl tar; do
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
print_error "$tool not found: reading trigger versions and ordering pkgrels both need pacman"
|
||||
print_error "$tool not found: rebuild trigger sync cannot run"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
+320
-18
@@ -18,11 +18,11 @@ Usage: $0 [PACKAGE...]
|
||||
|
||||
Update packages that track an upstream vendor release feed instead of the AUR.
|
||||
|
||||
A package whose upstream ships tagged GitHub releases with a checksum manifest
|
||||
opts in declaratively, via "upstream" in .omarchy/package.json (see
|
||||
helpers/upstream-github.sh for the schema); no code needed. Anything with a
|
||||
bespoke feed provides pkgbuilds/<package>/.omarchy/upstream.sh instead, a hook
|
||||
that reports the newest upstream release as JSON on stdout:
|
||||
Packages opt in declaratively through "upstream" in .omarchy/package.json.
|
||||
Providers cover GitHub Releases with checksum manifests or API asset digests,
|
||||
semver-shaped git tags, npm dist-tags, and plain Debian Packages indexes. See
|
||||
README.md for the schemas. Anything outside those conventions may provide
|
||||
pkgbuilds/<package>/.omarchy/upstream.sh, a hook that reports JSON on stdout:
|
||||
|
||||
{
|
||||
"pkgver": "1.2.3",
|
||||
@@ -332,27 +332,27 @@ sync_package() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
local github_repo has_upstream=false
|
||||
github_repo=$(package_upstream_github_repo "$package_dir")
|
||||
local provider has_upstream=false
|
||||
provider=$(package_upstream_provider "$package_dir")
|
||||
if package_has_upstream_provider "$package_dir"; then
|
||||
has_upstream=true
|
||||
fi
|
||||
|
||||
# A present-but-unusable declaration fails loudly; treating it like "no
|
||||
# upstream source" would silently drop the package from scheduled runs.
|
||||
if [[ "$has_upstream" == true && -z "$github_repo" ]]; then
|
||||
print_error "Package $package has an unusable upstream declaration (needs a github owner/repo)"
|
||||
if [[ "$has_upstream" == true && -z "$provider" ]]; then
|
||||
print_error "Package $package has an unusable or ambiguous upstream declaration"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "$github_repo" && -f "$hook" ]]; then
|
||||
print_error "Package $package declares both upstream.github and an upstream.sh hook; keep exactly one"
|
||||
if [[ -n "$provider" && -f "$hook" ]]; then
|
||||
print_error "Package $package declares both an upstream provider and an upstream.sh hook; keep exactly one"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -z "$github_repo" && ! -f "$hook" ]]; then
|
||||
if [[ -z "$provider" && ! -f "$hook" ]]; then
|
||||
if [[ "$SPECIFIC_MODE" == true ]]; then
|
||||
print_error "Package $package has neither an upstream declaration nor .omarchy/upstream.sh"
|
||||
((++FAILED))
|
||||
@@ -372,10 +372,16 @@ sync_package() {
|
||||
|
||||
print_info "Checking $package for upstream releases..."
|
||||
|
||||
local release
|
||||
if [[ -n "$github_repo" ]]; then
|
||||
if ! release=$(github_upstream_release "$package_dir" "$min_age"); then
|
||||
print_error "GitHub release provider failed for $package"
|
||||
local release release_status=0
|
||||
if [[ -n "$provider" ]]; then
|
||||
case "$provider" in
|
||||
github) release=$(github_upstream_release "$package_dir" "$min_age") || release_status=$? ;;
|
||||
git_tags) release=$(git_tags_upstream_release "$package_dir") || release_status=$? ;;
|
||||
npm) release=$(npm_upstream_release "$package_dir") || release_status=$? ;;
|
||||
debian) release=$(debian_upstream_release "$package_dir") || release_status=$? ;;
|
||||
esac
|
||||
if [[ ${release_status:-0} -ne 0 ]]; then
|
||||
print_error "$provider upstream provider failed for $package"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
@@ -461,8 +467,8 @@ sync_package() {
|
||||
# paths. Covers release selection (fallback past quarantined releases,
|
||||
# draft/prerelease filtering, bypass, unchanged version), failure paths
|
||||
# (unusable tags/timestamps, missing checksums), checksum template mapping
|
||||
# for both architectures, the min_release_age backstop, the duration parser,
|
||||
# and manifest validation.
|
||||
# for both architectures, release API digests, the min_release_age backstop,
|
||||
# the duration parser, and manifest validation.
|
||||
cmd_self_test() {
|
||||
local failures=0
|
||||
|
||||
@@ -539,6 +545,31 @@ EOF
|
||||
check "bypass lifts the quarantine" "2.0.0" "$(jq -r '.pkgver // "<none>"' <<<"$out")"
|
||||
check "x86_64 checksum via * binary-mode prefix" "$sum_x20" "$(jq -r '.sha256sums.x86_64[0] // "<none>"' <<<"$out")"
|
||||
|
||||
cp "$pkg/.omarchy/package.json" "$pkg/normal.json"
|
||||
jq '.upstream.latest_only = true' "$pkg/normal.json" > "$pkg/.omarchy/package.json"
|
||||
FIXTURE_RELEASES=$(jq -n --arg old "$old2d" '[
|
||||
{tag_name: "v1.9.0", published_at: $old, draft: false, prerelease: false},
|
||||
{tag_name: "v0.4.1-8", published_at: $old, draft: false, prerelease: false}
|
||||
]')
|
||||
FIXTURE_CHECKSUMS=$(printf '%s\n' \
|
||||
"$sum_x19 ./tool-v1.9.0-x64.tar.xz" \
|
||||
"$sum_a19 ./tool-v1.9.0-arm64.tar.xz")
|
||||
out=$(github_upstream_release "$pkg" 0 2>/dev/null) || out="<error>"
|
||||
check "latest_only ignores incompatible historical tags" "1.9.0" "$(jq -r '.pkgver // "<none>"' <<<"$out")"
|
||||
cp "$pkg/normal.json" "$pkg/.omarchy/package.json"
|
||||
FIXTURE_RELEASES=$(jq -n --arg young "$young" --arg old2 "$old2d" --arg old3 "$old3d" '[
|
||||
{tag_name: "v2.0.0", published_at: $young, draft: false, prerelease: false},
|
||||
{tag_name: "v1.9.9", published_at: $old2, draft: false, prerelease: true},
|
||||
{tag_name: "v1.9.8", published_at: $old2, draft: true, prerelease: false},
|
||||
{tag_name: "v1.9.0", published_at: $old2, draft: false, prerelease: false},
|
||||
{tag_name: "v1.8.0", published_at: $old3, draft: false, prerelease: false}
|
||||
]')
|
||||
FIXTURE_CHECKSUMS=$(printf '%s\n' \
|
||||
"$sum_x19 ./tool-v1.9.0-x64.tar.xz" \
|
||||
"$sum_a19 tool-v1.9.0-arm64.tar.xz" \
|
||||
"$sum_x20 *tool-v2.0.0-x64.tar.xz" \
|
||||
"$sum_a20 tool-v2.0.0-arm64.tar.xz")
|
||||
|
||||
out=$(github_upstream_release "$pkg" 8640000 2>/dev/null) || out="<error>"
|
||||
check "everything quarantined reports no update" "{}" "$(jq -c . <<<"$out")"
|
||||
|
||||
@@ -562,6 +593,187 @@ EOF
|
||||
rc=0; github_upstream_release "$pkg" 86400 >/dev/null 2>&1 || rc=$?
|
||||
check "missing aarch64 checksum fails the sync" "1" "$rc"
|
||||
|
||||
# A vendor publishing no manifest: checksums come from the digests the
|
||||
# release API reports per asset, with nothing fetched beyond the feed.
|
||||
echo "Release API digests:"
|
||||
local digpkg="$TEMP_DIR/selftest-digests"
|
||||
mkdir -p "$digpkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=1\n' > "$digpkg/PKGBUILD"
|
||||
cat > "$digpkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"github": "example/tool",
|
||||
"digests": true,
|
||||
"assets": {
|
||||
"x86_64": "tool-{pkgver}-1-x86_64.pkg.tar.zst",
|
||||
"aarch64": "tool-{pkgver}-1-aarch64.pkg.tar.zst"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
FIXTURE_RELEASES=$(jq -n --arg old "$old2d" --arg x "$sum_x19" --arg a "$sum_a19" '[
|
||||
{tag_name: "v1.9.0", published_at: $old, draft: false, prerelease: false, assets: [
|
||||
{name: "tool-1.9.0-1-x86_64.pkg.tar.zst", digest: ("sha256:" + $x)},
|
||||
{name: "tool-1.9.0-1-aarch64.pkg.tar.zst", digest: ("sha256:" + $a)},
|
||||
{name: "tool-1.9.0-1-x86_64.rpm", digest: "sha256:0000000000000000000000000000000000000000000000000000000000000000"}
|
||||
]}
|
||||
]')
|
||||
FIXTURE_CHECKSUMS="manifest must not be consulted"
|
||||
out=$(github_upstream_release "$digpkg" 0 2>/dev/null) || out="<error>"
|
||||
check "x86_64 checksum via the asset digest" "$sum_x19" "$(jq -r '.sha256sums.x86_64[0] // "<none>"' <<<"$out")"
|
||||
check "aarch64 checksum via the asset digest" "$sum_a19" "$(jq -r '.sha256sums.aarch64[0] // "<none>"' <<<"$out")"
|
||||
|
||||
FIXTURE_RELEASES=$(jq -n --arg old "$old2d" --arg x "$sum_x19" '[
|
||||
{tag_name: "v1.9.0", published_at: $old, draft: false, prerelease: false, assets: [
|
||||
{name: "tool-1.9.0-1-x86_64.pkg.tar.zst", digest: ("sha256:" + $x)},
|
||||
{name: "tool-1.9.0-1-aarch64.pkg.tar.zst"}
|
||||
]}
|
||||
]')
|
||||
rc=0; github_upstream_release "$digpkg" 0 >/dev/null 2>&1 || rc=$?
|
||||
check "asset without a digest fails the sync" "1" "$rc"
|
||||
|
||||
FIXTURE_RELEASES=$(jq -n --arg old "$old2d" --arg x "$sum_x19" '[
|
||||
{tag_name: "v1.9.0", published_at: $old, draft: false, prerelease: false, assets: [
|
||||
{name: "tool-1.9.0-1-x86_64.pkg.tar.zst", digest: ("sha256:" + $x)},
|
||||
{name: "tool-1.9.0-2-aarch64.pkg.tar.zst", digest: ("sha256:" + $x)}
|
||||
]}
|
||||
]')
|
||||
rc=0; github_upstream_release "$digpkg" 0 >/dev/null 2>&1 || rc=$?
|
||||
check "asset re-cut under another release number fails the sync" "1" "$rc"
|
||||
|
||||
FIXTURE_RELEASES=$(jq -n --arg old "$old2d" --arg x "$sum_x19" --arg a "$sum_a19" '[
|
||||
{tag_name: "v1.9.0", published_at: $old, draft: false, prerelease: false, assets: [
|
||||
{name: "tool-1.9.0-1-x86_64.pkg.tar.zst", digest: $x},
|
||||
{name: "tool-1.9.0-1-aarch64.pkg.tar.zst", digest: ("sha256:" + $a)}
|
||||
]}
|
||||
]')
|
||||
rc=0; github_upstream_release "$digpkg" 0 >/dev/null 2>&1 || rc=$?
|
||||
check "digest without the sha256: prefix fails the sync" "1" "$rc"
|
||||
|
||||
# The provider enforces the declaration shape itself: scheduled runs reach
|
||||
# it without validate_package_metadata.
|
||||
jq '.upstream.checksums = "SHASUMS256.txt"' "$digpkg/.omarchy/package.json" > "$digpkg/both.json"
|
||||
cp "$digpkg/.omarchy/package.json" "$digpkg/good.json"
|
||||
cp "$digpkg/both.json" "$digpkg/.omarchy/package.json"
|
||||
rc=0; github_upstream_release "$digpkg" 0 >/dev/null 2>&1 || rc=$?
|
||||
check "provider rejects checksums and digests together" "1" "$rc"
|
||||
jq '.upstream.digests = "true"' "$digpkg/good.json" > "$digpkg/.omarchy/package.json"
|
||||
rc=0; github_upstream_release "$digpkg" 0 >/dev/null 2>&1 || rc=$?
|
||||
check "provider rejects a non-boolean digests" "1" "$rc"
|
||||
cp "$digpkg/good.json" "$digpkg/.omarchy/package.json"
|
||||
|
||||
echo "Ordered GitHub assets with supplemental sources:"
|
||||
local multipkg="$TEMP_DIR/selftest-multi-assets" multi_sum support_sum multi_vst
|
||||
mkdir -p "$multipkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=1\n' > "$multipkg/PKGBUILD"
|
||||
cat > "$multipkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"github": "example/tool",
|
||||
"digests": true,
|
||||
"assets": {
|
||||
"x86_64": ["tool-{pkgver}-x86_64", "tool-{pkgver}-x86_64.asc"],
|
||||
"aarch64": ["tool-{pkgver}-aarch64", "tool-{pkgver}-aarch64.asc"]
|
||||
},
|
||||
"sources": {
|
||||
"any": ["https://example.test/tool/{tag}/support.txt"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
local sum_x19_sig sum_a19_sig
|
||||
sum_x19_sig=$(printf '1%.0s' {1..64})
|
||||
sum_a19_sig=$(printf '2%.0s' {1..64})
|
||||
FIXTURE_RELEASES=$(jq -n --arg old "$old2d" --arg x "$sum_x19" --arg xs "$sum_x19_sig" \
|
||||
--arg a "$sum_a19" --arg as "$sum_a19_sig" '[
|
||||
{tag_name: "v1.9.0", published_at: $old, draft: false, prerelease: false, assets: [
|
||||
{name: "tool-1.9.0-x86_64", digest: ("sha256:" + $x)},
|
||||
{name: "tool-1.9.0-x86_64.asc", digest: ("sha256:" + $xs)},
|
||||
{name: "tool-1.9.0-aarch64", digest: ("sha256:" + $a)},
|
||||
{name: "tool-1.9.0-aarch64.asc", digest: ("sha256:" + $as)}
|
||||
]}
|
||||
]')
|
||||
upstream_fetch_source() { printf 'remote fixture for %s\n' "$1" > "$2"; }
|
||||
multi_sum=$(github_upstream_release "$multipkg" 0 2>/dev/null) || multi_sum="<error>"
|
||||
support_sum=$(printf 'remote fixture for %s\n' 'https://example.test/tool/v1.9.0/support.txt' | sha256sum | cut -d' ' -f1)
|
||||
check "ordered GitHub assets produce an ordered checksum array" "$sum_x19 $sum_x19_sig" \
|
||||
"$(jq -r '.sha256sums.x86_64 | join(" ")' <<<"$multi_sum")"
|
||||
check "GitHub supplemental source is downloaded and hashed" "$support_sum" \
|
||||
"$(jq -r '.sha256sums.any[0]' <<<"$multi_sum")"
|
||||
multi_vst=0; validate_package_metadata "$multipkg" >/dev/null || multi_vst=$?
|
||||
check "GitHub asset lists and disjoint sources validate" "0" "$multi_vst"
|
||||
jq '.upstream.sources.x86_64 = ["https://example.test/duplicate"]' \
|
||||
"$multipkg/.omarchy/package.json" > "$multipkg/overlap.json"
|
||||
cp "$multipkg/.omarchy/package.json" "$multipkg/good.json"
|
||||
cp "$multipkg/overlap.json" "$multipkg/.omarchy/package.json"
|
||||
multi_vst=0; validate_package_metadata "$multipkg" >/dev/null || multi_vst=$?
|
||||
check "GitHub assets and sources cannot target the same checksum array" "1" "$multi_vst"
|
||||
cp "$multipkg/good.json" "$multipkg/.omarchy/package.json"
|
||||
|
||||
echo "Debian Packages provider:"
|
||||
local debpkg="$TEMP_DIR/selftest-debian" deb_sum deb_x_sum deb_a_sum deb_vst
|
||||
mkdir -p "$debpkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=1\nsha256sums_x86_64=("old")\nsha256sums_aarch64=("old")\n' > "$debpkg/PKGBUILD"
|
||||
cat > "$debpkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"debian": "https://packages.example.test/dists/stable/main/binary-amd64/Packages",
|
||||
"package": "example-app",
|
||||
"sources": {
|
||||
"x86_64": ["https://downloads.example.test/app-{pkgver}-x64.tar.gz"],
|
||||
"aarch64": ["https://downloads.example.test/app-{pkgver}-arm64.tar.gz"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
debian_fetch_packages() {
|
||||
cat <<'EOF'
|
||||
Package: unrelated
|
||||
Version: 99.0.0
|
||||
|
||||
Package: example-app
|
||||
Version: 1.9.0
|
||||
|
||||
Package: example-app
|
||||
Version: 1.10.0
|
||||
EOF
|
||||
}
|
||||
deb_sum=$(debian_upstream_release "$debpkg")
|
||||
deb_x_sum=$(printf 'remote fixture for %s\n' 'https://downloads.example.test/app-1.10.0-x64.tar.gz' | sha256sum | cut -d' ' -f1)
|
||||
deb_a_sum=$(printf 'remote fixture for %s\n' 'https://downloads.example.test/app-1.10.0-arm64.tar.gz' | sha256sum | cut -d' ' -f1)
|
||||
check "Debian provider selects the newest exact package stanza" "1.10.0" "$(jq -r '.pkgver' <<<"$deb_sum")"
|
||||
check "Debian x86_64 source is hashed" "$deb_x_sum" "$(jq -r '.sha256sums.x86_64[0]' <<<"$deb_sum")"
|
||||
check "Debian aarch64 source is hashed" "$deb_a_sum" "$(jq -r '.sha256sums.aarch64[0]' <<<"$deb_sum")"
|
||||
deb_vst=0; validate_package_metadata "$debpkg" >/dev/null || deb_vst=$?
|
||||
check "Debian declaration validates" "0" "$deb_vst"
|
||||
printf 'pkgver=1.10.0\npkgrel=1\nsha256sums_x86_64=("old")\nsha256sums_aarch64=("old")\n' > "$debpkg/PKGBUILD"
|
||||
check "checked-in Debian version avoids source downloads" "{}" "$(debian_upstream_release "$debpkg" | jq -c .)"
|
||||
|
||||
echo "End-to-end Debian sync with the checked-in 1password recipe:"
|
||||
local one_root="$TEMP_DIR/e2e-1password" one_dir one_version=8.12.35
|
||||
mkdir -p "$one_root"
|
||||
cp -a "$BUILD_ROOT/pkgbuilds/1password" "$one_root/1password"
|
||||
one_dir="$one_root/1password"
|
||||
debian_fetch_packages() {
|
||||
printf 'Package: 1password\nVersion: %s\n' "$one_version"
|
||||
}
|
||||
upstream_fetch_source() { printf 'remote fixture for %s\n' "$1" > "$2"; }
|
||||
local one_prev_updated=$UPDATED one_prev_failed=$FAILED
|
||||
PKGBUILDS_DIR="$one_root" sync_package 1password >/dev/null 2>&1 || true
|
||||
check "1password sync updates without failures" "updated=1 failed=0" \
|
||||
"updated=$((UPDATED - one_prev_updated)) failed=$((FAILED - one_prev_failed))"
|
||||
check "1password pkgver is the single download version source" "$one_version" \
|
||||
"$(grep -m1 '^pkgver=' "$one_dir/PKGBUILD" | cut -d= -f2-)"
|
||||
check "1password pkgrel resets to 1" "1" \
|
||||
"$(grep -m1 '^pkgrel=' "$one_dir/PKGBUILD" | cut -d= -f2-)"
|
||||
check "1password x86 URL follows the rewritten pkgver" "1password-${one_version}.x64.tar.gz" \
|
||||
"$(CARCH=x86_64 bash -c 'source "$1"; basename "${source_x86_64[0]}"' _ "$one_dir/PKGBUILD")"
|
||||
check "1password ARM URL follows the rewritten pkgver" "1password-${one_version}.arm64.tar.gz" \
|
||||
"$(CARCH=aarch64 bash -c 'source "$1"; basename "${source_aarch64[0]}"' _ "$one_dir/PKGBUILD")"
|
||||
|
||||
echo "Quarantine backstop:"
|
||||
local rel st
|
||||
rel=$(jq -n --arg p "$old2d" '{pkgver: "1.9.0", published_at: $p, sha256sums: {}}')
|
||||
@@ -614,10 +826,100 @@ EOF
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool"}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "upstream without checksums/assets is rejected" "1" "$vst"
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool", "checksums": "SHASUMS256.txt", "digests": true, "assets": {"x86_64": "a"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "upstream with both checksums and digests is rejected" "1" "$vst"
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool", "digests": "yes", "assets": {"x86_64": "a"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "non-boolean digests is rejected" "1" "$vst"
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool", "checksums": false, "digests": true, "assets": {"x86_64": "a"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "checksums: false alongside digests is rejected" "1" "$vst"
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool", "checksums": "SUMS", "digests": null, "assets": {"x86_64": "a"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "digests: null is rejected" "1" "$vst"
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool", "checksums": "SUMS", "digests": false, "assets": {"x86_64": "a"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "digests: false beside a checksums manifest is accepted" "0" "$vst"
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool", "digests": false, "assets": {"x86_64": "a"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "digests: false alone is rejected" "1" "$vst"
|
||||
cp "$digpkg/.omarchy/package.json" "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "the digests declaration shape is accepted" "0" "$vst"
|
||||
echo '{"source":"local","upstream":{"github":"example/tool","git_tags":"https://example/tool.git","checksums":"sums","assets":{"any":"tool"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "multiple provider types are rejected" "1" "$vst"
|
||||
cp "$pkg/.omarchy/package.json" "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "the real declaration shape is accepted" "0" "$vst"
|
||||
|
||||
echo "Git-tag provider:"
|
||||
local tagpkg="$TEMP_DIR/selftest-tags" tag_sum remote_sum local_sum
|
||||
mkdir -p "$tagpkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=4\nsha256sums=("old" "old")\n' > "$tagpkg/PKGBUILD"
|
||||
printf 'local fixture\n' > "$tagpkg/local.patch"
|
||||
cat > "$tagpkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://example.test/tool.git",
|
||||
"tag_pattern": "release/{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://downloads.example.test/tool-{pkgver}.tar.gz", "file:local.patch"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
git_tags_fetch_refs() {
|
||||
printf '%s\n' \
|
||||
'aaaa refs/tags/release/1.9.0' \
|
||||
'bbbb refs/tags/release/1.10.0' \
|
||||
'cccc refs/tags/not-a-release'
|
||||
}
|
||||
upstream_fetch_source() { printf 'remote fixture for %s\n' "$1" > "$2"; }
|
||||
tag_sum=$(git_tags_upstream_release "$tagpkg")
|
||||
remote_sum=$(printf 'remote fixture for %s\n' 'https://downloads.example.test/tool-1.10.0.tar.gz' | sha256sum | cut -d' ' -f1)
|
||||
local_sum=$(sha256sum "$tagpkg/local.patch" | cut -d' ' -f1)
|
||||
check "pacman ordering selects 1.10.0 over 1.9.0" "1.10.0" "$(jq -r '.pkgver' <<<"$tag_sum")"
|
||||
check "remote source template is downloaded and hashed" "$remote_sum" "$(jq -r '.sha256sums.any[0]' <<<"$tag_sum")"
|
||||
check "local source entry is hashed" "$local_sum" "$(jq -r '.sha256sums.any[1]' <<<"$tag_sum")"
|
||||
vst=0; validate_package_metadata "$tagpkg" >/dev/null || vst=$?
|
||||
check "git-tags declaration validates" "0" "$vst"
|
||||
|
||||
echo "npm provider:"
|
||||
local npmpkg="$TEMP_DIR/selftest-npm" npm_sum npm_tar_sum npm_notes_sum
|
||||
mkdir -p "$npmpkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=1\nsha256sums=("old" "old")\n' > "$npmpkg/PKGBUILD"
|
||||
cat > "$npmpkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"npm": "@example/tool",
|
||||
"dist_tag": "latest",
|
||||
"sources": {
|
||||
"any": ["{npm_tarball}", "https://example.test/tool/{pkgver}/notes"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
npm_fetch_metadata() {
|
||||
jq -n '{
|
||||
"dist-tags": {latest: "2.0.0"},
|
||||
versions: {"2.0.0": {dist: {tarball: "https://registry.npmjs.org/@example/tool/-/tool-2.0.0.tgz"}}},
|
||||
time: {"2.0.0": "2024-01-02T03:04:05.000Z"}
|
||||
}'
|
||||
}
|
||||
npm_sum=$(npm_upstream_release "$npmpkg")
|
||||
npm_tar_sum=$(printf 'remote fixture for %s\n' 'https://registry.npmjs.org/@example/tool/-/tool-2.0.0.tgz' | sha256sum | cut -d' ' -f1)
|
||||
npm_notes_sum=$(printf 'remote fixture for %s\n' 'https://example.test/tool/2.0.0/notes' | sha256sum | cut -d' ' -f1)
|
||||
check "npm dist-tag selects its version" "2.0.0" "$(jq -r '.pkgver' <<<"$npm_sum")"
|
||||
check "npm tarball placeholder is hashed" "$npm_tar_sum" "$(jq -r '.sha256sums.any[0]' <<<"$npm_sum")"
|
||||
check "npm pkgver template is hashed" "$npm_notes_sum" "$(jq -r '.sha256sums.any[1]' <<<"$npm_sum")"
|
||||
check "npm publication time is preserved" "2024-01-02T03:04:05.000Z" "$(jq -r '.published_at' <<<"$npm_sum")"
|
||||
vst=0; validate_package_metadata "$npmpkg" >/dev/null || vst=$?
|
||||
check "npm declaration validates" "0" "$vst"
|
||||
|
||||
# End to end over the real mise-bin package: its checked-in metadata and
|
||||
# PKGBUILD, the full sync_package path (selection, validation, backstop,
|
||||
# rewrite, read-back verification), with only the two network fetches
|
||||
|
||||
+38
-32
@@ -84,15 +84,18 @@ echo ""
|
||||
|
||||
# --- queued work -------------------------------------------------------------
|
||||
|
||||
print_info "Queued builds (state files in $STATE_DIR)"
|
||||
print_info "Queued builds (state files in $STATE_DIR; architectures: $(published_arches | tr '\n' ' '))"
|
||||
queued=false
|
||||
for channel in edge rc stable; do
|
||||
state_file="$STATE_DIR/.sync-needed-$channel"
|
||||
if [[ -f "$state_file" ]]; then
|
||||
queued=true
|
||||
since=$(date -r "$state_file" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "unknown")
|
||||
printf ' • %-7s queued since %s\n' "$channel" "$since"
|
||||
fi
|
||||
for arch in $(published_arches); do
|
||||
state_file=$(sync_queue_file "$channel" "$arch")
|
||||
[[ "$arch" == "x86_64" && ! -f "$state_file" ]] && state_file=$(legacy_sync_queue_file "$channel")
|
||||
if [[ -f "$state_file" ]]; then
|
||||
queued=true
|
||||
since=$(date -r "$state_file" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "unknown")
|
||||
printf ' • %-7s %-8s queued since %s\n' "$channel" "$arch" "$since"
|
||||
fi
|
||||
done
|
||||
done
|
||||
[[ "$queued" == false ]] && echo " (nothing queued — all channels up to date)"
|
||||
echo ""
|
||||
@@ -101,34 +104,37 @@ echo ""
|
||||
# say so plainly: it is queued but deliberately not being retried yet.
|
||||
paused=false
|
||||
for channel in edge rc stable; do
|
||||
fail_file="$STATE_DIR/.build-failed-$channel"
|
||||
[[ -f "$fail_file" ]] || continue
|
||||
if [[ "$paused" == false ]]; then
|
||||
print_error "Failing builds (backoff active)"
|
||||
paused=true
|
||||
fi
|
||||
FAILURE_COUNT=0 FAILURE_AT=0 FAILURE_FINGERPRINT=""
|
||||
# shellcheck disable=SC1090
|
||||
source "$fail_file" 2>/dev/null || true
|
||||
delay=600
|
||||
for ((i = 1; i < FAILURE_COUNT; i++)); do
|
||||
delay=$((delay * 2))
|
||||
((delay >= 21600)) && { delay=21600; break; }
|
||||
for arch in $(published_arches); do
|
||||
fail_file=$(sync_fail_file "$channel" "$arch")
|
||||
[[ "$arch" == "x86_64" && ! -f "$fail_file" ]] && fail_file=$(legacy_sync_fail_file "$channel")
|
||||
[[ -f "$fail_file" ]] || continue
|
||||
if [[ "$paused" == false ]]; then
|
||||
print_error "Failing builds (backoff active)"
|
||||
paused=true
|
||||
fi
|
||||
FAILURE_COUNT=0 FAILURE_AT=0 FAILURE_FINGERPRINT=""
|
||||
# shellcheck disable=SC1090
|
||||
source "$fail_file" 2>/dev/null || true
|
||||
delay=600
|
||||
for ((i = 1; i < FAILURE_COUNT; i++)); do
|
||||
delay=$((delay * 2))
|
||||
((delay >= 21600)) && { delay=21600; break; }
|
||||
done
|
||||
retry_at=$((FAILURE_AT + delay))
|
||||
now=$(date +%s)
|
||||
if ((now < retry_at)); then
|
||||
when="retries at $(date -d "@$retry_at" '+%H:%M:%S' 2>/dev/null || echo "+$((retry_at - now))s")"
|
||||
else
|
||||
when="retries on the next tick"
|
||||
fi
|
||||
printf ' ✗ %-7s %-8s %s consecutive failure(s), %s\n' "$channel" "$arch" "$FAILURE_COUNT" "$when"
|
||||
printf ' last attempt %s on commit %s\n' \
|
||||
"$(date -d "@$FAILURE_AT" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "$FAILURE_AT")" \
|
||||
"${FAILURE_FINGERPRINT:0:12}"
|
||||
done
|
||||
retry_at=$((FAILURE_AT + delay))
|
||||
now=$(date +%s)
|
||||
if ((now < retry_at)); then
|
||||
when="retries at $(date -d "@$retry_at" '+%H:%M:%S' 2>/dev/null || echo "+$((retry_at - now))s")"
|
||||
else
|
||||
when="retries on the next tick"
|
||||
fi
|
||||
printf ' ✗ %-7s %s consecutive failure(s), %s\n' "$channel" "$FAILURE_COUNT" "$when"
|
||||
printf ' last attempt %s on commit %s\n' \
|
||||
"$(date -d "@$FAILURE_AT" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "$FAILURE_AT")" \
|
||||
"${FAILURE_FINGERPRINT:0:12}"
|
||||
done
|
||||
if [[ "$paused" == true ]]; then
|
||||
echo " Any new commit clears the backoff; or: rm $STATE_DIR/.build-failed-<channel>"
|
||||
echo " Any new commit clears the backoff; or: rm $STATE_DIR/.build-failed-<channel>-<arch>"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
|
||||
+16
-12
@@ -11,12 +11,11 @@ source "$BUILD_ROOT/helpers/docker-helpers.sh"
|
||||
source "$BUILD_ROOT/helpers/paths.sh"
|
||||
source "$BUILD_ROOT/helpers/lock-helpers.sh"
|
||||
|
||||
# Function to update repository database using Docker
|
||||
# Function to update repository database using the selected container engine
|
||||
update_database() {
|
||||
print_info "Updating repository database in Docker container..."
|
||||
print_info "Updating repository database in a container..."
|
||||
|
||||
# Check Docker is available
|
||||
check_docker
|
||||
check_engine
|
||||
|
||||
# Ensure output directory exists
|
||||
if [[ ! -d "$REPO_DIR" ]]; then
|
||||
@@ -25,20 +24,25 @@ update_database() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make output directory writable for container
|
||||
make_dir_writable "$REPO_DIR"
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
make_dir_writable "$REPO_DIR"
|
||||
fi
|
||||
|
||||
# repo-add is architecture- and mirror-independent, so always use the edge
|
||||
# x86_64 image. This also lets bootstrap-rc build the rc database before the
|
||||
# rc channel exists remotely (an rc image can only build after it does).
|
||||
build_docker_image "$BUILD_DIR" "x86_64" "edge"
|
||||
# repo-add is architecture- and mirror-independent. Use the host-native edge
|
||||
# image, which also lets bootstrap-rc run before that channel exists remotely.
|
||||
local tool_arch
|
||||
tool_arch=$(docker_native_arch) || {
|
||||
print_error "Unsupported host architecture: $(uname -m)"
|
||||
exit 1
|
||||
}
|
||||
build_docker_image "$BUILD_DIR" "$tool_arch" "edge"
|
||||
|
||||
docker run --rm --platform linux/amd64 \
|
||||
"$CONTAINER_ENGINE" run "${CONTAINER_RUN_ARGS[@]}" --rm "$(get_platform_arg "$tool_arch")" \
|
||||
-e ARCH="$ARCH" \
|
||||
-e MIRROR="$MIRROR" \
|
||||
-v "$REPO_ROOT:/output" \
|
||||
-v "$BUILD_DIR:/build:ro" \
|
||||
omarchy-pkg-builder:latest-x86_64-edge /build/update-repo.sh
|
||||
"omarchy-pkg-builder:latest-$tool_arch-edge" /build/update-repo.sh
|
||||
}
|
||||
|
||||
# Main execution
|
||||
|
||||
+14
-6
@@ -45,9 +45,7 @@ RUN if [ "${TARGETARCH}" = "amd64" ]; then \
|
||||
printf 'Server = https://mirror.omarchy.org/$repo/os/$arch\n' > /etc/pacman.d/mirrorlist; \
|
||||
fi; \
|
||||
else \
|
||||
curl -L "https://raw.githubusercontent.com/archlinuxarm/PKGBUILDs/master/core/pacman-mirrorlist/mirrorlist" 2>/dev/null | \
|
||||
sed -E 's/^\s*#\s*Server\s*=/Server =/g' > /etc/pacman.d/mirrorlist && \
|
||||
sed -i 's/\$arch/aarch64/g' /etc/pacman.d/mirrorlist; \
|
||||
printf 'Server = https://fl.us.mirror.archlinuxarm.org/aarch64/$repo\n' > /etc/pacman.d/mirrorlist; \
|
||||
fi
|
||||
|
||||
# Bootstrap keyrings (required before pacstrap can verify packages)
|
||||
@@ -108,11 +106,16 @@ RUN ln -sf /usr/lib/os-release /etc/os-release && \
|
||||
# Setup Omarchy keyring manually before adding repo (avoids keyserver trust issues)
|
||||
# Note: Repository is removed at the end since build scripts add it dynamically.
|
||||
# The keyring comes from this image's own channel (the bare /$arch path is a
|
||||
# stale legacy layout); %s keeps pacman's $arch literal while MIRROR expands.
|
||||
# stale legacy layout). It is always taken from the x86_64 tree, whatever the
|
||||
# image's own architecture: omarchy-keyring is an arch=any package, and the
|
||||
# x86_64 tree is the one that exists before a new architecture has published
|
||||
# anything. Bootstrapping from the target's own tree would make the first
|
||||
# aarch64 build depend on an aarch64 repository that only that build can
|
||||
# create.
|
||||
ARG MIRROR=edge
|
||||
RUN pacman-key --recv-keys 40DFB630FF42BCFFB047046CF0134EE680CAC571 --keyserver keys.openpgp.org && \
|
||||
pacman-key --lsign-key 40DFB630FF42BCFFB047046CF0134EE680CAC571 && \
|
||||
printf '\n[omarchy]\nSigLevel = Optional\nServer = https://pkgs.omarchy.org/%s/$arch\n' "${MIRROR}" >> /etc/pacman.conf && \
|
||||
printf '\n[omarchy]\nSigLevel = Optional\nServer = https://pkgs.omarchy.org/%s/x86_64\n' "${MIRROR}" >> /etc/pacman.conf && \
|
||||
pacman -Sy --noconfirm && \
|
||||
pacman -S --noconfirm omarchy-keyring && \
|
||||
pacman-key --populate omarchy && \
|
||||
@@ -137,8 +140,13 @@ RUN useradd -m -G wheel -s /bin/bash builder && \
|
||||
chmod 700 /home/builder/.gnupg && \
|
||||
chown -R builder:builder /home/builder
|
||||
|
||||
# Arch Linux ARM's makepkg.conf still defaults PKGEXT to .pkg.tar.xz; every
|
||||
# tool downstream of the build (sign.sh, push-build, sync-rebuilds, the
|
||||
# notifier) expects .pkg.tar.zst, so an aarch64 package would build and then
|
||||
# be skipped at signing. Pin the extension so both architectures match.
|
||||
RUN sed -i 's/^#MAKEFLAGS=.*/MAKEFLAGS="-j$(nproc)"/' /etc/makepkg.conf && \
|
||||
sed -i 's/^COMPRESSZST=.*/COMPRESSZST=(zstd -c -z -q --threads=0 -)/' /etc/makepkg.conf
|
||||
sed -i 's/^COMPRESSZST=.*/COMPRESSZST=(zstd -c -z -q --threads=0 -)/' /etc/makepkg.conf && \
|
||||
sed -i "s|^PKGEXT=.*|PKGEXT='.pkg.tar.zst'|" /etc/makepkg.conf
|
||||
|
||||
# Pacman wrapper that auto-resolves package conflicts (e.g. rustup vs rust).
|
||||
# makepkg only passes --noconfirm to pacman, which defaults to 'N' on conflict
|
||||
|
||||
+146
-57
@@ -5,6 +5,10 @@
|
||||
|
||||
# Setup directories
|
||||
ARCH=${ARCH:-x86_64}
|
||||
# ARCH selects the repository target for this script, but make and Kbuild also
|
||||
# interpret an exported ARCH themselves (Linux calls this target "arm64").
|
||||
# Keep the shell variable local to the orchestrator so PKGBUILDs see CARCH only.
|
||||
export -n ARCH
|
||||
MIRROR=${MIRROR:-edge}
|
||||
DRY_RUN=${DRY_RUN:-false}
|
||||
PKGBUILDS_DIR=${PKGBUILDS_DIR:-/pkgbuilds}
|
||||
@@ -12,9 +16,37 @@ BUILD_OUTPUT_DIR=${BUILD_OUTPUT_DIR:-/build-output/$MIRROR/$ARCH}
|
||||
FINAL_OUTPUT_DIR=${FINAL_OUTPUT_DIR:-/pkgs.omarchy.org/$MIRROR/$ARCH}
|
||||
HELPERS_DIR=${HELPERS_DIR:-/helpers}
|
||||
SRC_DIR=${SRC_DIR:-/src}
|
||||
# Set by bin/build from OMARCHY_DEFER_RUNTIME_DEPS after it has checked the
|
||||
# request; re-checked here so the container never trusts a stray value.
|
||||
DEFER_RUNTIME_DEPS=${DEFER_RUNTIME_DEPS:-false}
|
||||
|
||||
source "$HELPERS_DIR/package-metadata.sh"
|
||||
|
||||
if [[ $DEFER_RUNTIME_DEPS != "false" && $DEFER_RUNTIME_DEPS != "true" ]]; then
|
||||
echo "DEFER_RUNTIME_DEPS must be true or false" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ $DEFER_RUNTIME_DEPS == "true" ]]; then
|
||||
deferred_runtime=0
|
||||
deferred_settings=0
|
||||
deferred_count=0
|
||||
for package in $PACKAGES; do
|
||||
((deferred_count += 1))
|
||||
case $package in
|
||||
omarchy|omarchy-dev) deferred_runtime=1 ;;
|
||||
omarchy-settings|omarchy-settings-dev) deferred_settings=1 ;;
|
||||
*)
|
||||
echo "Runtime dependency deferral only applies to the omarchy pair, not $package" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if (( deferred_runtime != 1 || deferred_settings != 1 || deferred_count != 2 )); then
|
||||
echo "Runtime dependency deferral requires exactly the omarchy pair" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" != true ]]; then
|
||||
# Import GPG keys
|
||||
/build/import-gpg-keys.sh || exit 1
|
||||
@@ -32,14 +64,11 @@ if [[ "$DRY_RUN" != true ]]; then
|
||||
# Configure Omarchy repositories for dependency resolution
|
||||
echo "==> Configuring Omarchy repositories for dependency resolution..."
|
||||
|
||||
# Always add omarchy-build repo (for incremental builds)
|
||||
# Packages in build-output are unsigned, so use SigLevel = Never
|
||||
sudo tee -a /etc/pacman.conf > /dev/null <<EOF
|
||||
|
||||
[omarchy-build]
|
||||
SigLevel = Never
|
||||
Server = file://$BUILD_OUTPUT_DIR
|
||||
EOF
|
||||
# Always add omarchy-build repo first (for incremental builds). Repository
|
||||
# order is pacman's priority order, so this must precede the official repos;
|
||||
# otherwise pacman can select an older official package with the same name.
|
||||
# Packages in build-output are unsigned, so use SigLevel = Never.
|
||||
sudo sed -i "/^\[core\]$/i [omarchy-build]\nSigLevel = Never\nServer = file://$BUILD_OUTPUT_DIR\n" /etc/pacman.conf
|
||||
echo " -> omarchy-build (priority 1): $BUILD_OUTPUT_DIR"
|
||||
|
||||
# Initialize empty build database if it doesn't exist
|
||||
@@ -48,23 +77,21 @@ EOF
|
||||
# Create an empty database
|
||||
repo-add omarchy-build.db.tar.zst >/dev/null 2>&1
|
||||
ln -sf omarchy-build.db.tar.zst omarchy-build.db
|
||||
else
|
||||
# Database exists, check if we need to rebuild it from packages
|
||||
if ls *.pkg.tar.* 2>/dev/null | grep -v '\.sig$' | grep -v 'omarchy-build\.db' | grep -q .; then
|
||||
echo "==> Rebuilding build database from existing packages..."
|
||||
ls *.pkg.tar.* | grep -v '\.sig$' | grep -v 'omarchy-build\.db' | xargs -r repo-add omarchy-build.db.tar.zst >/dev/null 2>&1
|
||||
ln -sf omarchy-build.db.tar.zst omarchy-build.db
|
||||
fi
|
||||
fi
|
||||
# Fold any packages already in the workspace into the database, whether
|
||||
# they came with an existing database or were dropped in by an earlier
|
||||
# workflow job (OMARCHY_KEEP_BUILD_WORKSPACE). Without this a seeded
|
||||
# workspace with no database would leave those packages invisible to
|
||||
# dependency resolution.
|
||||
if ls *.pkg.tar.* 2>/dev/null | grep -v '\.sig$' | grep -v 'omarchy-build\.db' | grep -q .; then
|
||||
echo "==> Rebuilding build database from existing packages..."
|
||||
ls *.pkg.tar.* | grep -v '\.sig$' | grep -v 'omarchy-build\.db' | xargs -r repo-add omarchy-build.db.tar.zst >/dev/null 2>&1
|
||||
ln -sf omarchy-build.db.tar.zst omarchy-build.db
|
||||
fi
|
||||
|
||||
# Add omarchy repo if it has a database (stable packages)
|
||||
if [[ -f "$FINAL_OUTPUT_DIR/omarchy.db.tar.zst" ]] || [[ -f "$FINAL_OUTPUT_DIR/omarchy.db" ]]; then
|
||||
sudo tee -a /etc/pacman.conf > /dev/null <<EOF
|
||||
|
||||
[omarchy]
|
||||
SigLevel = Optional TrustAll
|
||||
Server = file://$FINAL_OUTPUT_DIR
|
||||
EOF
|
||||
sudo sed -i "/^\[core\]$/i [omarchy]\nSigLevel = Optional TrustAll\nServer = file://$FINAL_OUTPUT_DIR\n" /etc/pacman.conf
|
||||
echo " -> omarchy (priority 2): $FINAL_OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
@@ -155,26 +182,9 @@ get_local_version() {
|
||||
# Returns 0 (success) if should build, 1 if should skip
|
||||
should_build_for_arch() {
|
||||
local pkg="$1"
|
||||
local current_arch="$ARCH"
|
||||
local pkgdir=$(find_package_dir "$pkg")
|
||||
local pkgbuild="$pkgdir/PKGBUILD"
|
||||
|
||||
[[ ! -f "$pkgbuild" ]] && return 1
|
||||
|
||||
# Check PKGBUILD arch=() array
|
||||
local pkgbuild_archs=$(cd "$pkgdir" && bash -c 'source PKGBUILD 2>/dev/null; echo "${arch[@]}"')
|
||||
|
||||
# If arch=('any'), build for all architectures
|
||||
if [[ "$pkgbuild_archs" == "any" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if current arch is in PKGBUILD arch=()
|
||||
if echo "$pkgbuild_archs" | grep -qw "$current_arch"; then
|
||||
return 0 # Build
|
||||
else
|
||||
return 1 # Skip
|
||||
fi
|
||||
local pkgdir
|
||||
pkgdir=$(find_package_dir "$pkg")
|
||||
[[ -n "$pkgdir" ]] && package_supports_arch "$pkgdir" "$ARCH"
|
||||
}
|
||||
|
||||
# For VCS packages, makepkg recalculates pkgver() before the build. If the
|
||||
@@ -224,6 +234,31 @@ refresh_vcs_pkgver_preserving_local_pkgrel() {
|
||||
fi
|
||||
}
|
||||
|
||||
# With runtime dependency checks deferred, makepkg runs --nodeps, so the
|
||||
# build-time dependencies it would normally install with -s have to be
|
||||
# installed explicitly: makedepends and checkdepends, including the
|
||||
# architecture-suffixed variants for the current CARCH.
|
||||
install_deferred_build_dependencies() {
|
||||
local pkg="$1"
|
||||
local -a build_deps=()
|
||||
|
||||
mapfile -t build_deps < <(
|
||||
CARCH="$ARCH" bash -c '
|
||||
source PKGBUILD
|
||||
arch_makedepends="makedepends_${CARCH}[@]"
|
||||
arch_checkdepends="checkdepends_${CARCH}[@]"
|
||||
printf "%s\n" \
|
||||
"${makedepends[@]}" "${!arch_makedepends}" \
|
||||
"${checkdepends[@]}" "${!arch_checkdepends}"
|
||||
' | awk 'NF && !seen[$0]++'
|
||||
)
|
||||
|
||||
if (( ${#build_deps[@]} )); then
|
||||
echo " Installing build-only dependencies for $pkg..."
|
||||
sudo pacman -S --needed --noconfirm -- "${build_deps[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Build a package
|
||||
build_package() {
|
||||
local pkg="$1"
|
||||
@@ -280,21 +315,64 @@ build_package() {
|
||||
# Build package without signing (signing is done separately)
|
||||
# PACMAN override uses a wrapper that adds --ask 4 to auto-resolve conflicts
|
||||
# (e.g. rustup replacing rust) since --noconfirm defaults to 'N' on those prompts
|
||||
MAKEPKG_FLAGS="-scf --noconfirm"
|
||||
local -a makepkg_flags=(-scf --noconfirm)
|
||||
if [[ $DEFER_RUNTIME_DEPS == "true" ]]; then
|
||||
# The pair's runtime dependencies (each other, and packages other jobs
|
||||
# of the same pipeline build) are not resolvable here; the assembled set
|
||||
# is installed in one verified transaction downstream. Only the
|
||||
# build-time dependencies are installed, then makepkg skips the check.
|
||||
install_deferred_build_dependencies "$pkg" || {
|
||||
FAILED_PACKAGES="$FAILED_PACKAGES $pkg"
|
||||
return 1
|
||||
}
|
||||
makepkg_flags=(-cf --noconfirm --nodeps)
|
||||
fi
|
||||
|
||||
if PACMAN=/usr/local/bin/pacman-for-makepkg makepkg $MAKEPKG_FLAGS; then
|
||||
if PACMAN=/usr/local/bin/pacman-for-makepkg makepkg "${makepkg_flags[@]}"; then
|
||||
# Ensure output directory exists
|
||||
mkdir -p "$BUILD_OUTPUT_DIR"
|
||||
|
||||
for pkg_file in *.pkg.tar.*; do
|
||||
[[ -f "$pkg_file" ]] && cp "$pkg_file" "$BUILD_OUTPUT_DIR/"
|
||||
|
||||
# Copy only the artifacts makepkg declares as outputs. A PKGBUILD may use
|
||||
# another pacman package as a source (schist-bin does); a *.pkg.tar.* glob
|
||||
# would mistake that source archive for one of our freshly built packages.
|
||||
local -a package_files=()
|
||||
mapfile -t package_files < <(makepkg --packagelist)
|
||||
|
||||
if [[ ${#package_files[@]} -eq 0 ]]; then
|
||||
echo " Makepkg produced no package files for $pkg"
|
||||
FAILED_PACKAGES="$FAILED_PACKAGES $pkg"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local dependency_pkg_file=""
|
||||
local -a new_pkgs=()
|
||||
local pkg_path pkg_file
|
||||
for pkg_path in "${package_files[@]}"; do
|
||||
pkg_file=${pkg_path##*/}
|
||||
if [[ ! -f "$pkg_file" ]]; then
|
||||
# makepkg predicts an automatic -debug output whenever debug is
|
||||
# enabled, but data-only packages may contain no symbols and therefore
|
||||
# legitimately produce no debug archive.
|
||||
if [[ "$pkg_file" == *-debug-*.pkg.tar.* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo " Expected package file was not produced: $pkg_file"
|
||||
FAILED_PACKAGES="$FAILED_PACKAGES $pkg"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cp "$pkg_file" "$BUILD_OUTPUT_DIR/"
|
||||
new_pkgs+=("$pkg_file")
|
||||
|
||||
if [[ "$(bsdtar -xOf "$pkg_file" .PKGINFO 2>/dev/null | sed -n 's/^pkgname = //p')" == "$pkg" ]]; then
|
||||
dependency_pkg_file="$BUILD_OUTPUT_DIR/$pkg_file"
|
||||
fi
|
||||
done
|
||||
|
||||
cd "$BUILD_OUTPUT_DIR"
|
||||
|
||||
# Find ALL package files (handles split packages)
|
||||
local new_pkgs=($(ls -t ${pkg}-*.pkg.tar.* 2>/dev/null | grep -v '\.sig$' | grep -v 'omarchy-build\.db'))
|
||||
|
||||
# Add every output from this build, including split packages.
|
||||
if [[ ${#new_pkgs[@]} -gt 0 ]]; then
|
||||
repo-add omarchy-build.db.tar.zst "${new_pkgs[@]}" >/dev/null 2>&1
|
||||
ln -sf omarchy-build.db.tar.zst omarchy-build.db
|
||||
@@ -303,6 +381,24 @@ build_package() {
|
||||
|
||||
cd /src/$pkg
|
||||
|
||||
# A lower-priority official repository may contain an older package with
|
||||
# the same name. Install the exact artifact we just built before building
|
||||
# its consumers, so pacman cannot select that older provider instead.
|
||||
if [[ "${INSTALL_PACKAGES[$pkg]:-}" == "1" ]]; then
|
||||
if [[ -z "$dependency_pkg_file" ]]; then
|
||||
echo " Could not find the built $pkg package to install as a dependency"
|
||||
FAILED_PACKAGES="$FAILED_PACKAGES $pkg"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo " Installing freshly built $pkg for dependent packages..."
|
||||
if ! sudo /usr/local/bin/pacman-for-makepkg -U --needed --noconfirm "$dependency_pkg_file"; then
|
||||
echo " Failed to install freshly built dependency $pkg"
|
||||
FAILED_PACKAGES="$FAILED_PACKAGES $pkg"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " Successfully built $pkg"
|
||||
SUCCESSFUL_PACKAGES="$SUCCESSFUL_PACKAGES $pkg"
|
||||
return 0
|
||||
@@ -421,7 +517,7 @@ check_needs_build() {
|
||||
|
||||
# Collect packages that should be built for the selected mirror
|
||||
collect_packages() {
|
||||
packages_for_unscoped_build "$MIRROR"
|
||||
packages_for_unscoped_build "$MIRROR" "$ARCH"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
@@ -473,13 +569,6 @@ if [[ -n "$PACKAGES" ]]; then
|
||||
else
|
||||
# Build all packages that need updates from the relevant directories
|
||||
while IFS= read -r pkg; do
|
||||
# Check if package should be built for this architecture
|
||||
if ! should_build_for_arch "$pkg"; then
|
||||
echo " - $pkg - not built for $ARCH"
|
||||
SKIPPED_PACKAGES="$SKIPPED_PACKAGES $pkg"
|
||||
continue
|
||||
fi
|
||||
|
||||
if check_needs_build "$pkg"; then
|
||||
PACKAGES_TO_BUILD+=("$pkg")
|
||||
else
|
||||
|
||||
+116
-25
@@ -1,25 +1,102 @@
|
||||
# Docker helper functions for Omarchy package build system
|
||||
# Container engine helpers for Omarchy package build system
|
||||
|
||||
check_docker() {
|
||||
if ! command -v docker &>/dev/null; then
|
||||
print_error "Docker is not installed"
|
||||
container_engine_supported() {
|
||||
[[ "$CONTAINER_ENGINE" == "docker" || "$CONTAINER_ENGINE" == "podman" ]]
|
||||
}
|
||||
|
||||
if [[ -z "${CONTAINER_ENGINE:-}" ]]; then
|
||||
for engine in docker podman; do
|
||||
if command -v "$engine" >/dev/null 2>&1 && "$engine" info >/dev/null 2>&1; then
|
||||
CONTAINER_ENGINE="$engine"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
export CONTAINER_ENGINE
|
||||
|
||||
# Rootless Podman otherwise maps the image's builder uid 1000 to a subordinate
|
||||
# host uid. keep-id makes files written through bind mounts belong to the user
|
||||
# who invoked the build.
|
||||
CONTAINER_RUN_ARGS=()
|
||||
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
||||
CONTAINER_RUN_ARGS+=("--userns=keep-id:uid=1000,gid=1000")
|
||||
fi
|
||||
|
||||
check_engine() {
|
||||
if [[ -n "$CONTAINER_ENGINE" ]] && ! container_engine_supported; then
|
||||
print_error "Unsupported CONTAINER_ENGINE: $CONTAINER_ENGINE (use docker or podman)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker info &>/dev/null; then
|
||||
print_error "Docker daemon is not running"
|
||||
print_warning "Start Docker with: sudo systemctl start docker"
|
||||
if [[ -z "$CONTAINER_ENGINE" ]]; then
|
||||
print_error "No working container engine found (tried Docker, then Podman)"
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
print_warning "Docker is installed but unavailable. Start it with: sudo systemctl start docker"
|
||||
elif command -v podman >/dev/null 2>&1; then
|
||||
print_warning "Podman is installed but 'podman info' failed"
|
||||
else
|
||||
print_warning "Install Docker or Podman"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v "$CONTAINER_ENGINE" >/dev/null 2>&1; then
|
||||
print_error "$CONTAINER_ENGINE is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! "$CONTAINER_ENGINE" info >/dev/null 2>&1; then
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
print_error "Docker daemon is not running or is not accessible"
|
||||
print_warning "Start Docker with: sudo systemctl start docker"
|
||||
else
|
||||
print_error "Podman is not available to the current user"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
docker_native_arch() {
|
||||
case "$(uname -m)" in
|
||||
x86_64) echo x86_64 ;;
|
||||
aarch64 | arm64) echo aarch64 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
setup_qemu() {
|
||||
# Setup QEMU for building ARM64 packages on x86_64 hosts
|
||||
if ! docker run --rm --privileged multiarch/qemu-user-static --reset -p yes --credential yes >/dev/null 2>&1; then
|
||||
print_error "Failed to setup QEMU for ARM64 emulation"
|
||||
local target_arch="${1:-aarch64}"
|
||||
|
||||
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
||||
local registration="/proc/sys/fs/binfmt_misc/qemu-$target_arch"
|
||||
local packaged_registration="/usr/lib/binfmt.d/qemu-$target_arch-static.conf"
|
||||
local flags=""
|
||||
|
||||
if [[ -r "$registration" ]]; then
|
||||
flags=$(sed -n 's/^flags: //p' "$registration")
|
||||
fi
|
||||
|
||||
if [[ "$flags" == *F* && "$flags" == *C* ]]; then
|
||||
print_success "QEMU $target_arch emulation is registered"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_error "Rootless Podman requires QEMU binfmt registration with the F and C flags"
|
||||
print_info "F keeps the emulator available inside containers; C lets container sudo preserve credentials."
|
||||
print_info "Configure it once with:"
|
||||
echo " sudo pacman -S --needed qemu-user-static qemu-user-static-binfmt"
|
||||
echo " sudo mkdir -p /etc/binfmt.d"
|
||||
echo " sed 's/:FP$/:FPC/' $packaged_registration | sudo tee /etc/binfmt.d/qemu-$target_arch-static.conf >/dev/null"
|
||||
echo " sudo systemctl restart systemd-binfmt"
|
||||
exit 1
|
||||
fi
|
||||
print_success "QEMU ARM64 emulation enabled"
|
||||
|
||||
# Register emulators for builds whose target differs from the host.
|
||||
if ! "$CONTAINER_ENGINE" run --rm --privileged docker.io/multiarch/qemu-user-static --reset -p yes --credential yes >/dev/null 2>&1; then
|
||||
print_error "Failed to set up QEMU emulation"
|
||||
exit 1
|
||||
fi
|
||||
print_success "QEMU emulation enabled"
|
||||
}
|
||||
|
||||
build_docker_image() {
|
||||
@@ -39,31 +116,45 @@ build_docker_image() {
|
||||
;;
|
||||
esac
|
||||
|
||||
print_info "Building Docker image for $arch ($platform) using $mirror mirror..."
|
||||
|
||||
docker buildx build \
|
||||
--platform "$platform" \
|
||||
--build-arg MIRROR="$mirror" \
|
||||
--load \
|
||||
-t "$image_tag" \
|
||||
-f "$build_dir/Dockerfile" \
|
||||
"$build_dir"
|
||||
print_info "Building container image for $arch ($platform) using $mirror mirror..."
|
||||
|
||||
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
||||
"$CONTAINER_ENGINE" buildx build \
|
||||
--platform "$platform" \
|
||||
--build-arg MIRROR="$mirror" \
|
||||
--load \
|
||||
-t "$image_tag" \
|
||||
-f "$build_dir/Dockerfile" \
|
||||
"$build_dir"
|
||||
else
|
||||
"$CONTAINER_ENGINE" build \
|
||||
--platform "$platform" \
|
||||
--build-arg MIRROR="$mirror" \
|
||||
-t "$image_tag" \
|
||||
-f "$build_dir/Dockerfile" \
|
||||
"$build_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
get_platform_arg() {
|
||||
local arch="$1"
|
||||
case "$arch" in
|
||||
x86_64) echo "--platform linux/amd64" ;;
|
||||
aarch64) echo "--platform linux/arm64" ;;
|
||||
*) echo "" ;;
|
||||
x86_64) echo "--platform=linux/amd64" ;;
|
||||
aarch64) echo "--platform=linux/arm64" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
make_dir_writable() {
|
||||
local dir="$1"
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
if (( EUID == 0 )); then
|
||||
chmod -R 777 "$dir"
|
||||
else
|
||||
sudo chown -R $(id -u):$(id -g) "$dir" 2>/dev/null || chmod -R 777 "$dir"
|
||||
# chown can succeed on part of the tree and fail on the rest (files a
|
||||
# previous container left behind as another uid); the old `|| chmod`
|
||||
# fallback only ran when chown failed outright, leaving those files
|
||||
# unwritable. Always follow with chmod so the whole tree is usable.
|
||||
sudo chown -R "$(id -u):$(id -g)" "$dir" 2>/dev/null || true
|
||||
chmod -R 777 "$dir"
|
||||
fi
|
||||
}
|
||||
+116
-11
@@ -15,7 +15,11 @@
|
||||
# { "source": "local", "channels": ["edge"] }
|
||||
# { "source": "local", "channels": ["edge", "rc", "stable"] }
|
||||
# { "source": "local", "min_release_age": "24h" }
|
||||
# { "source": "local", "upstream": { "github": "owner/repo", "checksums": "SHASUMS256.txt", "assets": { "x86_64": "name-{tag}-x64.tar.xz" } } }
|
||||
# { "source": "local", "upstream": { "github": "owner/repo", "checksums": "SHASUMS256.txt", "assets": { "x86_64": ["name-{tag}-x64.tar.xz"] } } }
|
||||
# { "source": "local", "upstream": { "github": "owner/repo", "digests": true, "assets": { "x86_64": "name-{tag}-x64.tar.xz" } } }
|
||||
# { "source": "local", "upstream": { "git_tags": "https://example/repo.git", "tag_pattern": "v{pkgver}", "sources": { "any": ["https://example/archive/{tag}.tar.gz"] } } }
|
||||
# { "source": "local", "upstream": { "npm": "@scope/package", "sources": { "any": ["{npm_tarball}"] } } }
|
||||
# { "source": "local", "upstream": { "debian": "https://example/debian/dists/stable/main/binary-amd64/Packages", "package": "example", "sources": { "any": ["https://example/releases/{pkgver}.tar.gz"] } } }
|
||||
#
|
||||
# bin/sync-aur also writes upstream_commit for AUR-backed packages, and
|
||||
# bin/sync-rebuilds writes rebuilt_against for packages declaring rebuild_on.
|
||||
@@ -140,6 +144,55 @@ package_has_pkgbuild() {
|
||||
[[ -f "$pkgdir/PKGBUILD" ]]
|
||||
}
|
||||
|
||||
# Read one variable from a PKGBUILD the way makepkg would see it.
|
||||
#
|
||||
# makepkg always exports CARCH, so PKGBUILDs may branch on it at file scope
|
||||
# (per-architecture sources, tarball suffixes, even `return` for an
|
||||
# unsupported architecture). Sourcing without CARCH takes the wrong branch or
|
||||
# aborts partway, which leaves pkgver and pkgrel empty — and an empty version
|
||||
# never equals the published one, so the package is queued for a rebuild that
|
||||
# promotion then refuses. Every read of a PKGBUILD goes through here.
|
||||
#
|
||||
# Prints the value; exit status is that of `source PKGBUILD` itself, so a
|
||||
# caller can tell "variable empty" from "PKGBUILD could not be read".
|
||||
package_pkgbuild_var() {
|
||||
local pkgdir="$1"
|
||||
local var="$2"
|
||||
local arch="${3:-${ARCH:-x86_64}}"
|
||||
|
||||
(cd "$pkgdir" && env -u OMARCHY_SRC CARCH="$arch" bash -c '
|
||||
source PKGBUILD >/dev/null 2>&1
|
||||
rc=$?
|
||||
printf "%s\n" "${!1:-}"
|
||||
exit "$rc"
|
||||
' _ "$var")
|
||||
}
|
||||
|
||||
# The architectures declared by a PKGBUILD. Set CARCH while reading it so a
|
||||
# conditional arch=() assignment is evaluated for the architecture we are
|
||||
# actually checking, even when the repository host is a different one.
|
||||
package_arches() {
|
||||
local pkgdir="$1"
|
||||
local arch="${2:-${ARCH:-x86_64}}"
|
||||
|
||||
(cd "$pkgdir" && env -u OMARCHY_SRC CARCH="$arch" bash -c '
|
||||
source PKGBUILD >/dev/null 2>&1
|
||||
printf "%s\n" "${arch[*]}"
|
||||
')
|
||||
}
|
||||
|
||||
package_supports_arch() {
|
||||
local pkgdir="$1"
|
||||
local target="${2:-${ARCH:-x86_64}}"
|
||||
local arches
|
||||
|
||||
arches=$(package_arches "$pkgdir" "$target") || return 1
|
||||
case " $arches " in
|
||||
*" any "* | *" $target "*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Channel membership: where a package may be published. Packages without a
|
||||
# `channels` key are members of every channel (they flow edge -> rc -> stable).
|
||||
package_has_channels() {
|
||||
@@ -298,9 +351,12 @@ packages_for_mirror() {
|
||||
|
||||
packages_for_unscoped_build() {
|
||||
local mirror="$1"
|
||||
local arch="${2:-${ARCH:-x86_64}}"
|
||||
|
||||
package_dirs | while IFS= read -r pkgdir; do
|
||||
if package_builds_for_mirror "$pkgdir" "$mirror" && ! package_build_skipped "$pkgdir"; then
|
||||
if package_builds_for_mirror "$pkgdir" "$mirror" &&
|
||||
! package_build_skipped "$pkgdir" &&
|
||||
package_supports_arch "$pkgdir" "$arch"; then
|
||||
basename "$pkgdir"
|
||||
fi
|
||||
done
|
||||
@@ -446,17 +502,50 @@ validate_package_metadata() {
|
||||
# `has` rather than `// {}`: jq's // treats false as absent, which would
|
||||
# let "upstream": false slip through as an empty declaration.
|
||||
if ! jq -e '
|
||||
def valid_sources:
|
||||
type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z"))
|
||||
and (.value | type == "array" and length > 0 and all(type == "string" and length > 0))
|
||||
));
|
||||
def valid_assets:
|
||||
type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z"))
|
||||
and (.value |
|
||||
(type == "string" and length > 0)
|
||||
or (type == "array" and length > 0 and all(type == "string" and length > 0) and (unique | length) == length)
|
||||
)
|
||||
));
|
||||
if has("upstream") | not then true
|
||||
elif (.upstream | type) != "object" then false
|
||||
else .upstream |
|
||||
((.github // "") | type == "string" and test("\\A[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+\\z"))
|
||||
and ((.checksums // "") | type == "string" and length > 0)
|
||||
and ((.assets // {}) | type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z")) and (.value | type == "string" and length > 0)
|
||||
)))
|
||||
([has("github"), has("git_tags"), has("npm"), has("debian")] | map(select(.)) | length) == 1
|
||||
and if has("github") then
|
||||
(.github | type == "string" and test("\\A[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+\\z"))
|
||||
and (if has("checksums") then (.checksums | type == "string" and length > 0) else true end)
|
||||
and (if has("digests") then (.digests | type == "boolean") else true end)
|
||||
and (if has("latest_only") then (.latest_only | type == "boolean") else true end)
|
||||
and (has("checksums") != (has("digests") and .digests == true))
|
||||
and (.assets | valid_assets)
|
||||
and (if has("sources") then
|
||||
(.sources | valid_sources)
|
||||
and ((.assets | keys) as $assets | (.sources | keys) as $sources | ($assets - $sources | length) == ($assets | length))
|
||||
else true end)
|
||||
elif has("git_tags") then
|
||||
(.git_tags | type == "string" and test("\\Ahttps://[^[:space:]]+\\.git\\z"))
|
||||
and (.tag_pattern | type == "string" and (split("{pkgver}") | length) == 2)
|
||||
and (.sources | valid_sources)
|
||||
elif has("npm") then
|
||||
(.npm | type == "string" and test("\\A(@[a-z0-9_.-]+/)?[a-z0-9_.-]+\\z"))
|
||||
and ((.dist_tag // "latest") | type == "string" and test("\\A[a-z0-9_.-]+\\z"))
|
||||
and (.sources | valid_sources)
|
||||
else
|
||||
(.debian | type == "string" and test("\\Ahttps://[^[:space:]]+\\z"))
|
||||
and (.package | type == "string" and test("\\A[a-z0-9][a-z0-9+.-]*\\z"))
|
||||
and (.sources | valid_sources)
|
||||
end
|
||||
end
|
||||
' "$metadata" >/dev/null; then
|
||||
echo "invalid upstream for $(basename "$pkgdir"): needs github owner/repo, checksums asset name, and an assets arch->name map"
|
||||
echo "invalid upstream for $(basename "$pkgdir"): configure exactly one valid github, git_tags, npm, or debian provider"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -481,12 +570,28 @@ validate_package_metadata() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! jq -e '(.rebuilt_against // {}) | type == "object" and (to_entries | all(.value | type == "string" and length > 0))' "$metadata" >/dev/null; then
|
||||
echo "invalid rebuilt_against for $(basename "$pkgdir"): must be an object mapping package names to versions"
|
||||
if ! jq -e '
|
||||
def version_map:
|
||||
type == "object" and (to_entries | all(.value | type == "string" and length > 0));
|
||||
(.rebuilt_against // {}) as $record |
|
||||
($record | version_map) or
|
||||
(($record | type) == "object"
|
||||
and ((($record | keys) - ["x86_64", "aarch64"]) | length == 0)
|
||||
and ($record | to_entries | all(.value | version_map)))
|
||||
' "$metadata" >/dev/null; then
|
||||
echo "invalid rebuilt_against for $(basename "$pkgdir"): must map architectures to package-version maps"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! jq -e '((.rebuilt_against // {}) | keys) - (.rebuild_on // []) | length == 0' "$metadata" >/dev/null; then
|
||||
if ! jq -e '
|
||||
(.rebuild_on // []) as $triggers |
|
||||
(.rebuilt_against // {}) as $record |
|
||||
if ($record | to_entries | all(.value | type == "string")) then
|
||||
((($record | keys) - $triggers) | length == 0)
|
||||
else
|
||||
($record | to_entries | all((((.value | keys) - $triggers) | length) == 0))
|
||||
end
|
||||
' "$metadata" >/dev/null; then
|
||||
echo "invalid rebuilt_against for $(basename "$pkgdir"): records a package that rebuild_on does not name"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -5,6 +5,62 @@
|
||||
ARCH=${ARCH:-x86_64}
|
||||
MIRROR=${MIRROR:-edge}
|
||||
|
||||
# Architectures the tooling knows how to build.
|
||||
VALID_ARCHES="x86_64 aarch64"
|
||||
|
||||
# Architectures this repository PUBLISHES. The scheduled pipeline (version
|
||||
# check, auto-release, channel advance with --arch all) runs once per entry,
|
||||
# in this order; the first entry is the reference architecture that the
|
||||
# release train observes channels through. Adding an architecture here is the
|
||||
# enablement step: the next check-versions tick queues its packages and the
|
||||
# next auto-release tick builds them. OMARCHY_ARCHES overrides it for a
|
||||
# one-off run.
|
||||
PUBLISHED_ARCHES="${OMARCHY_ARCHES:-x86_64}"
|
||||
|
||||
validate_arch() {
|
||||
case " $VALID_ARCHES " in
|
||||
*" $1 "*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
require_valid_arch() {
|
||||
if ! validate_arch "$1"; then
|
||||
echo "Invalid architecture: $1 (must be one of: $VALID_ARCHES)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
published_arches() {
|
||||
local arch
|
||||
for arch in $PUBLISHED_ARCHES; do
|
||||
require_valid_arch "$arch"
|
||||
echo "$arch"
|
||||
done
|
||||
}
|
||||
|
||||
reference_arch() {
|
||||
published_arches | head -1
|
||||
}
|
||||
|
||||
# Scheduled-pipeline state, one file per channel and architecture, so one
|
||||
# architecture's queue or backoff never gates another's.
|
||||
STATE_DIR="${OMARCHY_STATE_DIR:-/root/.state}"
|
||||
|
||||
sync_queue_file() { # sync_queue_file <mirror> <arch>
|
||||
echo "$STATE_DIR/.sync-needed-$1-$2"
|
||||
}
|
||||
|
||||
sync_fail_file() { # sync_fail_file <mirror> <arch>
|
||||
echo "$STATE_DIR/.build-failed-$1-$2"
|
||||
}
|
||||
|
||||
# The pre-architecture names, .sync-needed-<mirror> and .build-failed-<mirror>,
|
||||
# meant x86_64. A host upgraded mid-cycle may still hold one; readers treat
|
||||
# it as the x86_64 file until it is consumed.
|
||||
legacy_sync_queue_file() { echo "$STATE_DIR/.sync-needed-$1"; }
|
||||
legacy_sync_fail_file() { echo "$STATE_DIR/.build-failed-$1"; }
|
||||
|
||||
# Valid package channels, in pipeline order: packages move edge -> rc -> stable
|
||||
VALID_MIRRORS="edge rc stable"
|
||||
|
||||
|
||||
+321
-32
@@ -1,8 +1,7 @@
|
||||
# GitHub-releases upstream provider for bin/sync-upstream.
|
||||
# Declarative upstream providers for bin/sync-upstream.
|
||||
#
|
||||
# A package whose upstream ships tagged GitHub releases with a checksum
|
||||
# manifest asset needs no upstream.sh hook: the whole feed is data, declared
|
||||
# in .omarchy/package.json --
|
||||
# A package whose upstream ships tagged GitHub releases needs no upstream.sh
|
||||
# hook: the whole feed is data, declared in .omarchy/package.json --
|
||||
#
|
||||
# "upstream": {
|
||||
# "github": "jdx/mise",
|
||||
@@ -13,17 +12,28 @@
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# "checksums" names the vendor's manifest asset. A vendor publishing none can
|
||||
# set "digests": true instead, which reads the SHA-256 digest GitHub's release
|
||||
# API reports for every asset, so the sync never downloads the artifacts.
|
||||
#
|
||||
# {tag} and {pkgver} interpolate into asset names; tags may carry a leading
|
||||
# "v", which is stripped for pkgver. Drafts and prereleases are ignored. The
|
||||
# provider emits the same JSON contract as an upstream.sh hook, so
|
||||
# bin/sync-upstream's validation and min_release_age backstop apply
|
||||
# unchanged; a feed that fits no convention keeps a bespoke upstream.sh.
|
||||
# unchanged. Git-tag, npm, and Debian Packages providers below cover projects
|
||||
# without GitHub releases; a feed that fits no convention keeps a bespoke hook.
|
||||
|
||||
package_upstream_github_repo() {
|
||||
local pkgdir="$1"
|
||||
# `objects` drops a non-object upstream value (validation rejects those
|
||||
# separately) instead of erroring the jq pipeline.
|
||||
package_metadata_value "$pkgdir" '(.upstream? | objects | .github)' ""
|
||||
# Return the single declarative provider selected by a package. An empty
|
||||
# result means either no provider or an invalid/ambiguous declaration; the
|
||||
# caller distinguishes those through package_has_upstream_provider().
|
||||
package_upstream_provider() {
|
||||
local pkgdir="$1" metadata
|
||||
metadata=$(metadata_file_for_dir "$pkgdir")
|
||||
jq -r '
|
||||
(.upstream? | objects) as $u
|
||||
| [$u | keys[] | select(. == "github" or . == "git_tags" or . == "npm" or . == "debian")]
|
||||
| if length == 1 then .[0] else "" end
|
||||
' "$metadata"
|
||||
}
|
||||
|
||||
# Fetches sit behind functions so the self-test can replace them with fixture
|
||||
@@ -43,6 +53,221 @@ github_fetch_checksums() {
|
||||
curl -fsSL "https://github.com/$repo/releases/download/$tag/$asset"
|
||||
}
|
||||
|
||||
git_tags_fetch_refs() {
|
||||
local repo="$1"
|
||||
git ls-remote --tags "$repo"
|
||||
}
|
||||
|
||||
npm_fetch_metadata() {
|
||||
local package="$1" encoded
|
||||
encoded=$(jq -rn --arg package "$package" '$package | @uri')
|
||||
curl -fsSL "https://registry.npmjs.org/$encoded"
|
||||
}
|
||||
|
||||
debian_fetch_packages() {
|
||||
local url="$1"
|
||||
curl --proto '=https' --proto-redir '=https' -fsSL "$url"
|
||||
}
|
||||
|
||||
upstream_fetch_source() {
|
||||
local url="$1" output="$2"
|
||||
curl --proto '=https' --proto-redir '=https' -fsSL -o "$output" "$url"
|
||||
}
|
||||
|
||||
# Hash every URL template in upstream.sources and emit hook-contract JSON.
|
||||
# Templates may use {pkgver}, {tag}, and (for npm) {npm_tarball}. Downloads
|
||||
# happen only after discovery reports a version newer than the PKGBUILD.
|
||||
upstream_hash_sources() {
|
||||
local package_dir="$1" pkgver="$2" tag="${3:-}" npm_tarball="${4:-}"
|
||||
local metadata sources work result arch template url file sum sums index=0
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
sources=$(jq -c '.upstream.sources' "$metadata")
|
||||
work=$(mktemp -d)
|
||||
result=$(jq -n --arg pkgver "$pkgver" '{pkgver: $pkgver, sha256sums: {}}')
|
||||
|
||||
while IFS= read -r arch; do
|
||||
sums='[]'
|
||||
while IFS= read -r template; do
|
||||
if [[ "$template" == file:* ]]; then
|
||||
file=${template#file:}
|
||||
if [[ ! "$file" =~ ^[A-Za-z0-9._+-]+$ || ! -f "$package_dir/$file" ]]; then
|
||||
echo "upstream source names an unsafe or missing local file: '$file'" >&2
|
||||
rm -rf "$work"
|
||||
return 1
|
||||
fi
|
||||
sum=$(sha256sum "$package_dir/$file" | cut -d' ' -f1)
|
||||
sums=$(jq -c --arg sum "$sum" '. + [$sum]' <<<"$sums")
|
||||
continue
|
||||
fi
|
||||
url=${template//\{pkgver\}/$pkgver}
|
||||
url=${url//\{tag\}/$tag}
|
||||
url=${url//\{npm_tarball\}/$npm_tarball}
|
||||
if [[ ! "$url" =~ ^https://[^[:space:]{}]+$ ]]; then
|
||||
echo "upstream source template produced an unsafe URL: '$url'" >&2
|
||||
rm -rf "$work"
|
||||
return 1
|
||||
fi
|
||||
file="$work/source-$((index += 1))"
|
||||
if ! upstream_fetch_source "$url" "$file"; then
|
||||
echo "could not fetch upstream source: $url" >&2
|
||||
rm -rf "$work"
|
||||
return 1
|
||||
fi
|
||||
sum=$(sha256sum "$file" | cut -d' ' -f1)
|
||||
sums=$(jq -c --arg sum "$sum" '. + [$sum]' <<<"$sums")
|
||||
done < <(jq -r --arg arch "$arch" '.[$arch][]' <<<"$sources")
|
||||
result=$(jq -c --arg arch "$arch" --argjson sums "$sums" '.sha256sums[$arch] = $sums' <<<"$result")
|
||||
done < <(jq -r 'keys[]' <<<"$sources")
|
||||
|
||||
rm -rf "$work"
|
||||
printf '%s\n' "$result"
|
||||
}
|
||||
|
||||
git_tags_upstream_release() {
|
||||
local package_dir="$1" metadata repo pattern prefix suffix refs
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
repo=$(jq -r '.upstream.git_tags // ""' "$metadata")
|
||||
pattern=$(jq -r '.upstream.tag_pattern // ""' "$metadata")
|
||||
prefix=${pattern%%\{pkgver\}*}
|
||||
suffix=${pattern#*\{pkgver\}}
|
||||
|
||||
if [[ ! "$repo" =~ ^https://[^[:space:]]+\.git$ || "$pattern" != *'{pkgver}'* || "$suffix" == *'{pkgver}'* ]]; then
|
||||
echo "invalid git_tags provider configuration" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! refs=$(git_tags_fetch_refs "$repo"); then
|
||||
echo "could not fetch tags from $repo" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local best_pkgver="" best_tag="" tag candidate
|
||||
declare -A version_tags=()
|
||||
while read -r tag; do
|
||||
tag=${tag%\^\{\}}
|
||||
[[ "$tag" == "$prefix"*"$suffix" ]] || continue
|
||||
candidate=${tag#"$prefix"}
|
||||
[[ -z "$suffix" ]] || candidate=${candidate%"$suffix"}
|
||||
[[ "$candidate" =~ ^[A-Za-z0-9][A-Za-z0-9._+]*$ ]] || continue
|
||||
if [[ -n "${version_tags[$candidate]:-}" && "${version_tags[$candidate]}" != "$tag" ]]; then
|
||||
echo "multiple tags map to pkgver $candidate: ${version_tags[$candidate]} and $tag" >&2
|
||||
return 1
|
||||
fi
|
||||
version_tags[$candidate]="$tag"
|
||||
if [[ -z "$best_pkgver" || $(vercmp "$candidate" "$best_pkgver") -gt 0 ]]; then
|
||||
best_pkgver="$candidate"
|
||||
best_tag="$tag"
|
||||
fi
|
||||
done < <(sed -n 's#^.*refs/tags/##p' <<<"$refs")
|
||||
|
||||
[[ -n "$best_pkgver" ]] || { echo "no usable tags found at $repo" >&2; return 1; }
|
||||
local current_pkgver
|
||||
current_pkgver=$(grep -m1 '^pkgver=' "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best_pkgver" "$current_pkgver") -le 0 ]]; then
|
||||
echo '{}'
|
||||
return 0
|
||||
fi
|
||||
upstream_hash_sources "$package_dir" "$best_pkgver" "$best_tag"
|
||||
}
|
||||
|
||||
npm_upstream_release() {
|
||||
local package_dir="$1" metadata package dist_tag npm_metadata pkgver tarball published_at release
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
package=$(jq -r '.upstream.npm // ""' "$metadata")
|
||||
dist_tag=$(jq -r '.upstream.dist_tag // "latest"' "$metadata")
|
||||
if [[ ! "$package" =~ ^(@[a-z0-9_.-]+/)?[a-z0-9_.-]+$ || ! "$dist_tag" =~ ^[a-z0-9_.-]+$ ]]; then
|
||||
echo "invalid npm provider configuration" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! npm_metadata=$(npm_fetch_metadata "$package"); then
|
||||
echo "could not fetch npm metadata for $package" >&2
|
||||
return 1
|
||||
fi
|
||||
pkgver=$(jq -r --arg tag "$dist_tag" '."dist-tags"[$tag] // ""' <<<"$npm_metadata")
|
||||
tarball=$(jq -r --arg version "$pkgver" '.versions[$version].dist.tarball // ""' <<<"$npm_metadata")
|
||||
published_at=$(jq -r --arg version "$pkgver" '.time[$version] // ""' <<<"$npm_metadata")
|
||||
if [[ ! "$pkgver" =~ ^[A-Za-z0-9][A-Za-z0-9._+]*$ || ! "$tarball" =~ ^https://registry\.npmjs\.org/ ]]; then
|
||||
echo "npm returned an unusable $package release" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local current_pkgver
|
||||
current_pkgver=$(grep -m1 '^pkgver=' "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$pkgver" "$current_pkgver") -le 0 ]]; then
|
||||
echo '{}'
|
||||
return 0
|
||||
fi
|
||||
release=$(upstream_hash_sources "$package_dir" "$pkgver" "$pkgver" "$tarball") || return 1
|
||||
if [[ -n "$published_at" ]]; then
|
||||
release=$(jq -c --arg published_at "$published_at" '.published_at = $published_at' <<<"$release")
|
||||
fi
|
||||
printf '%s\n' "$release"
|
||||
}
|
||||
|
||||
# Discover a package version from a plain-text Debian Packages index, then
|
||||
# hash the declared immutable sources. This intentionally supports only
|
||||
# versions that are already valid Arch pkgver values; feeds needing Debian
|
||||
# epoch/revision translation keep a package-specific hook.
|
||||
debian_upstream_release() {
|
||||
local package_dir="$1" metadata index_url package packages
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
index_url=$(jq -r '.upstream.debian // ""' "$metadata")
|
||||
package=$(jq -r '.upstream.package // ""' "$metadata")
|
||||
|
||||
if [[ ! "$index_url" =~ ^https://[^[:space:]]+$ || ! "$package" =~ ^[a-z0-9][a-z0-9+.-]*$ ]]; then
|
||||
echo "invalid Debian Packages provider configuration" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! jq -e '
|
||||
.upstream.sources | type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z"))
|
||||
and (.value | type == "array" and length > 0 and all(type == "string" and length > 0))
|
||||
))
|
||||
' "$metadata" >/dev/null; then
|
||||
echo "invalid Debian Packages source mapping" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! packages=$(debian_fetch_packages "$index_url"); then
|
||||
echo "could not fetch Debian Packages index: $index_url" >&2
|
||||
return 1
|
||||
fi
|
||||
packages=${packages//$'\r'/}
|
||||
|
||||
local best_pkgver="" candidate
|
||||
while IFS= read -r candidate; do
|
||||
if [[ ! "$candidate" =~ ^[A-Za-z0-9][A-Za-z0-9._+]*$ ]]; then
|
||||
echo "$package has an unusable Debian version: ${candidate:-<empty>}" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "$best_pkgver" || $(vercmp "$candidate" "$best_pkgver") -gt 0 ]]; then
|
||||
best_pkgver="$candidate"
|
||||
fi
|
||||
done < <(awk -v target="$package" '
|
||||
BEGIN { RS = ""; FS = "\n" }
|
||||
{
|
||||
name = version = ""
|
||||
for (i = 1; i <= NF; i++) {
|
||||
if ($i ~ /^Package: /) name = substr($i, 10)
|
||||
if ($i ~ /^Version: /) version = substr($i, 10)
|
||||
}
|
||||
if (name == target) print version
|
||||
}
|
||||
' <<<"$packages")
|
||||
|
||||
[[ -n "$best_pkgver" ]] || {
|
||||
echo "no usable $package release found in $index_url" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
local current_pkgver
|
||||
current_pkgver=$(grep -m1 '^pkgver=' "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best_pkgver" "$current_pkgver") -le 0 ]]; then
|
||||
echo '{}'
|
||||
return 0
|
||||
fi
|
||||
|
||||
upstream_hash_sources "$package_dir" "$best_pkgver" "$best_pkgver"
|
||||
}
|
||||
|
||||
# Emits the newest qualifying release as hook-contract JSON. min_release_age
|
||||
# is honored during selection (newest release older than the window wins,
|
||||
# even when a younger one exists) and BYPASS_MIN_RELEASE_AGE=1 lifts it.
|
||||
@@ -51,7 +276,7 @@ github_fetch_checksums() {
|
||||
# not silently choose from.
|
||||
github_upstream_release() {
|
||||
local package_dir="$1" min_age="${2:-0}"
|
||||
local metadata repo checksums_name
|
||||
local metadata repo checksums_name use_digests latest_only
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
|
||||
repo=$(jq -r '(.upstream? | objects | .github) // ""' "$metadata")
|
||||
@@ -59,9 +284,46 @@ github_upstream_release() {
|
||||
echo "invalid upstream.github repository: '${repo:-<empty>}'" >&2
|
||||
return 1
|
||||
fi
|
||||
checksums_name=$(jq -r '(.upstream? | objects | .checksums) // ""' "$metadata")
|
||||
if [[ -z "$checksums_name" ]]; then
|
||||
echo "upstream.checksums names the checksum manifest asset and is required" >&2
|
||||
# Enforced here as well as in validate_package_metadata: the scheduled sync
|
||||
# reaches this provider without running the validator first.
|
||||
checksums_name=$(jq -r '(.upstream? | objects | .checksums) | strings' "$metadata")
|
||||
use_digests=$(jq -r '(.upstream? | objects | .digests) | if . == null then "false" elif type == "boolean" then tostring else "invalid" end' "$metadata")
|
||||
latest_only=$(jq -r '(.upstream? | objects | .latest_only) | if . == null then "false" elif type == "boolean" then tostring else "invalid" end' "$metadata")
|
||||
if [[ "$use_digests" == "invalid" ]]; then
|
||||
echo "upstream.digests must be true or false" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ "$latest_only" == "invalid" ]]; then
|
||||
echo "upstream.latest_only must be true or false" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -n "$checksums_name" && "$use_digests" == "true" ]]; then
|
||||
echo "upstream sets both checksums and digests; keep exactly one" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "$checksums_name" && "$use_digests" != "true" ]]; then
|
||||
echo "upstream needs either checksums (a manifest asset name) or digests: true" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! jq -e '
|
||||
def valid_sources:
|
||||
type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z"))
|
||||
and (.value | type == "array" and length > 0 and all(type == "string" and length > 0))
|
||||
));
|
||||
(.upstream.assets | type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z"))
|
||||
and (.value |
|
||||
(type == "string" and length > 0)
|
||||
or (type == "array" and length > 0 and all(type == "string" and length > 0) and (unique | length) == length)
|
||||
)
|
||||
)))
|
||||
and (if .upstream | has("sources") then
|
||||
(.upstream.sources | valid_sources)
|
||||
and ((.upstream.assets | keys) as $assets | (.upstream.sources | keys) as $sources | ($assets - $sources | length) == ($assets | length))
|
||||
else true end)
|
||||
' "$metadata" >/dev/null; then
|
||||
echo "invalid upstream.assets or upstream.sources mapping" >&2
|
||||
return 1
|
||||
fi
|
||||
local arches
|
||||
@@ -77,6 +339,9 @@ github_upstream_release() {
|
||||
echo "could not fetch the release feed for $repo" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ "$latest_only" == "true" ]]; then
|
||||
releases=$(jq '[.[] | select((.draft or .prerelease) | not)][0:1]' <<<"$releases")
|
||||
fi
|
||||
|
||||
local candidates=0 best_tag="" best_pkgver="" best_published_at=""
|
||||
local tag published_at pkgver published_epoch
|
||||
@@ -129,33 +394,57 @@ github_upstream_release() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
local checksums
|
||||
if ! checksums=$(github_fetch_checksums "$repo" "$best_tag" "$checksums_name"); then
|
||||
local checksums=""
|
||||
if [[ "$use_digests" != "true" ]] \
|
||||
&& ! checksums=$(github_fetch_checksums "$repo" "$best_tag" "$checksums_name"); then
|
||||
echo "could not fetch $checksums_name for $repo $best_tag" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local jq_args=(--arg pkgver "$best_pkgver" --arg published_at "$best_published_at")
|
||||
local jq_filter='{pkgver: $pkgver, published_at: $published_at, sha256sums: {}}'
|
||||
local arch template filename checksum
|
||||
local result
|
||||
result=$(jq -n --arg pkgver "$best_pkgver" --arg published_at "$best_published_at" \
|
||||
'{pkgver: $pkgver, published_at: $published_at, sha256sums: {}}')
|
||||
local arch template filename checksum checksum_source sums
|
||||
for arch in "${arches[@]}"; do
|
||||
if [[ ! "$arch" =~ ^[a-z0-9_]+$ ]]; then
|
||||
echo "invalid architecture key in upstream.assets: '$arch'" >&2
|
||||
return 1
|
||||
fi
|
||||
template=$(jq -r --arg arch "$arch" '.upstream.assets[$arch]' "$metadata")
|
||||
filename=${template//\{pkgver\}/$best_pkgver}
|
||||
filename=${filename//\{tag\}/$best_tag}
|
||||
# Manifest lines are "<sha256> <name>", with the name sometimes prefixed
|
||||
# "./" (sha256sum of a local path) or "*" (binary-mode marker).
|
||||
checksum=$(awk -v f="$filename" '$2 == f || $2 == "./" f || $2 == "*" f { print $1; exit }' <<<"$checksums")
|
||||
if [[ ! "$checksum" =~ ^[0-9a-f]{64}$ ]]; then
|
||||
echo "no valid checksum for $filename in $repo $best_tag $checksums_name" >&2
|
||||
return 1
|
||||
fi
|
||||
jq_args+=(--arg "sum_$arch" "$checksum")
|
||||
jq_filter+=" | .sha256sums[\"$arch\"] = [\$sum_$arch]"
|
||||
sums='[]'
|
||||
while IFS= read -r template; do
|
||||
filename=${template//\{pkgver\}/$best_pkgver}
|
||||
filename=${filename//\{tag\}/$best_tag}
|
||||
if [[ "$use_digests" == "true" ]]; then
|
||||
# Only a "sha256:<hex>" digest is stripped to its hex; any other shape
|
||||
# falls through empty and fails the check below.
|
||||
checksum=$(jq -r --arg tag "$best_tag" --arg name "$filename" '
|
||||
first(.[] | select(.tag_name == $tag)) | (.assets // [])[]
|
||||
| select(.name == $name) | (.digest // "")
|
||||
| if type == "string" and test("\\Asha256:[0-9a-f]{64}\\z") then ltrimstr("sha256:") else "" end
|
||||
' <<<"$releases")
|
||||
checksum_source="the release API digest"
|
||||
else
|
||||
# Manifest lines are "<sha256> <name>", with the name sometimes prefixed
|
||||
# "./" (sha256sum of a local path) or "*" (binary-mode marker).
|
||||
checksum=$(awk -v f="$filename" '$2 == f || $2 == "./" f || $2 == "*" f { print $1; exit }' <<<"$checksums")
|
||||
checksum_source="$checksums_name"
|
||||
fi
|
||||
if [[ ! "$checksum" =~ ^[0-9a-f]{64}$ ]]; then
|
||||
echo "no valid checksum for $filename in $repo $best_tag $checksum_source" >&2
|
||||
return 1
|
||||
fi
|
||||
sums=$(jq -c --arg checksum "$checksum" '. + [$checksum]' <<<"$sums")
|
||||
done < <(jq -r --arg arch "$arch" '
|
||||
.upstream.assets[$arch] | if type == "array" then .[] else . end
|
||||
' "$metadata")
|
||||
result=$(jq -c --arg arch "$arch" --argjson sums "$sums" '.sha256sums[$arch] = $sums' <<<"$result")
|
||||
done
|
||||
|
||||
jq -n "${jq_args[@]}" "$jq_filter"
|
||||
if jq -e '.upstream | has("sources")' "$metadata" >/dev/null; then
|
||||
local source_release
|
||||
source_release=$(upstream_hash_sources "$package_dir" "$best_pkgver" "$best_tag") || return 1
|
||||
result=$(jq -c --argjson source "$source_release" '.sha256sums += $source.sha256sums' <<<"$result")
|
||||
fi
|
||||
|
||||
printf '%s\n' "$result"
|
||||
}
|
||||
@@ -1,5 +1,18 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"upstream_commit": "e323d0d1f8dea6b75bb651ce14acc73904cd0326"
|
||||
"upstream": {
|
||||
"debian": "https://downloads.1password.com/linux/debian/amd64/dists/stable/main/binary-amd64/Packages",
|
||||
"package": "1password",
|
||||
"sources": {
|
||||
"x86_64": [
|
||||
"https://downloads.1password.com/linux/tar/stable/x86_64/1password-{pkgver}.x64.tar.gz",
|
||||
"https://downloads.1password.com/linux/tar/stable/x86_64/1password-{pkgver}.x64.tar.gz.sig"
|
||||
],
|
||||
"aarch64": [
|
||||
"https://downloads.1password.com/linux/tar/stable/aarch64/1password-{pkgver}.arm64.tar.gz",
|
||||
"https://downloads.1password.com/linux/tar/stable/aarch64/1password-{pkgver}.arm64.tar.gz.sig"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,45 @@
|
||||
pkgname=1password
|
||||
|
||||
_tarver=8.12.34
|
||||
_tar="1password-${_tarver}.x64.tar.gz"
|
||||
pkgver=${_tarver//-/_}
|
||||
pkgrel=34
|
||||
pkgver=8.12.34
|
||||
pkgrel=36
|
||||
conflicts=('1password-beta' '1password-beta-bin')
|
||||
pkgdesc="Password manager and secure wallet"
|
||||
arch=('x86_64')
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://1password.com'
|
||||
license=('LicenseRef-1Password-Proprietary')
|
||||
options=(!strip)
|
||||
install="1password.install"
|
||||
source=(https://downloads.1password.com/linux/tar/stable/${CARCH}/${_tar}{,.sig})
|
||||
sha256sums=('297784aa66770b645607a7f04c9ba2c4aebed4f46d21202487f521ba572b7b13'
|
||||
'ec085bef60de748895d3c51a8208301ba2ac8fb47db99334539ba4bd1d3260d7'
|
||||
source_x86_64=(
|
||||
"https://downloads.1password.com/linux/tar/stable/x86_64/1password-${pkgver}.x64.tar.gz"
|
||||
"https://downloads.1password.com/linux/tar/stable/x86_64/1password-${pkgver}.x64.tar.gz.sig"
|
||||
)
|
||||
source_aarch64=(
|
||||
"https://downloads.1password.com/linux/tar/stable/aarch64/1password-${pkgver}.arm64.tar.gz"
|
||||
"https://downloads.1password.com/linux/tar/stable/aarch64/1password-${pkgver}.arm64.tar.gz.sig"
|
||||
)
|
||||
sha256sums_x86_64=('297784aa66770b645607a7f04c9ba2c4aebed4f46d21202487f521ba572b7b13'
|
||||
'ec085bef60de748895d3c51a8208301ba2ac8fb47db99334539ba4bd1d3260d7'
|
||||
)
|
||||
sha256sums_aarch64=('ea5102363d6cf3442b96a7abd6743da8c1d261f56a628e1a3c183d84fa65fdcb'
|
||||
'f44db73fa44c3f68c3ab78a9cce140be9355de1dd9be4ce731c9d6597960c907'
|
||||
)
|
||||
validpgpkeys=('3FEF9748469ADBE15DA7CA80AC2D62742012EA22')
|
||||
|
||||
package() {
|
||||
depends=('hicolor-icon-theme' 'libgtk-3.so=0' 'nss' 'xdg-utils')
|
||||
|
||||
# 1Password names its tarballs by a vendor architecture suffix. arch=()
|
||||
# above already limits which architectures makepkg builds, so no fallback
|
||||
# branch is needed here; keeping this inside package() means sourcing the
|
||||
# PKGBUILD without CARCH (as the version check does) still reads the
|
||||
# version correctly.
|
||||
local _tararch
|
||||
case "$CARCH" in
|
||||
x86_64) _tararch=x64 ;;
|
||||
aarch64) _tararch=arm64 ;;
|
||||
esac
|
||||
|
||||
# Go to source directory
|
||||
cd "1password-${_tarver}.x64"
|
||||
cd "1password-${pkgver}.${_tararch}"
|
||||
|
||||
# Install icons
|
||||
resolutions=(32x32 64x64 256x256 512x512)
|
||||
@@ -33,6 +51,12 @@ package() {
|
||||
# Install desktop file
|
||||
install -Dm0644 resources/1password.desktop -t "${pkgdir}"/usr/share/applications/
|
||||
|
||||
# 1Password reads the display scale itself, the way Electron apps do, and
|
||||
# comes up oversized next to every other window on a scaled monitor. Pin it
|
||||
# and let the compositor do the scaling.
|
||||
sed -i 's|^Exec=.*|Exec=/opt/1Password/1password --force-device-scale-factor=1 %U|' \
|
||||
"${pkgdir}/usr/share/applications/1password.desktop"
|
||||
|
||||
# Fill in policy kit file with a list of (the first 10) human users of the system.
|
||||
export POLICY_OWNERS
|
||||
POLICY_OWNERS="$(cut -d: -f1,3 /etc/passwd | grep -E ':[0-9]{4}$' | cut -d: -f1 | head -n 10 | sed 's/^/unix-user:/' | tr '\n' ' ')"
|
||||
@@ -49,7 +73,7 @@ EOF" > ./com.1password.1Password.policy
|
||||
# Move package contents to /opt/1Password
|
||||
cd "${srcdir}"
|
||||
install -dm0755 "${pkgdir}"/opt
|
||||
mv "1password-${_tarver}.x64" "${pkgdir}/opt/1Password"
|
||||
mv "1password-${pkgver}.${_tararch}" "${pkgdir}/opt/1Password"
|
||||
|
||||
# Cleanup un-needed files
|
||||
rm "${pkgdir}"/opt/1Password/com.1password.1Password.policy "${pkgdir}"/opt/1Password/com.1password.1Password.policy.tpl "${pkgdir}"/opt/1Password/install_biometrics_policy.sh
|
||||
|
||||
@@ -4,7 +4,7 @@ epoch=1
|
||||
pkgver=0.6.0
|
||||
pkgrel=2
|
||||
pkgdesc="Control brightness on Apple Displays connected via USB-C"
|
||||
arch=('x86_64')
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/omakasui/asdcontrol"
|
||||
license=('GPL2')
|
||||
options=('!debug')
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[asusctl]
|
||||
source = "git"
|
||||
git = "https://gitlab.com/asus-linux/asusctl.git"
|
||||
|
||||
git = "https://github.com/OpenGamingCollective/asusctl.git"
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"upstream_commit": "ed336f7dbd5e8bee333aeaa6246da89241f1c8e6"
|
||||
"upstream_commit": "b0ec6ca495eb331a684db91b0fe12085a868b632"
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
diff --git a/PKGBUILD b/PKGBUILD
|
||||
index 55d0c22..8897aec 100644
|
||||
--- a/PKGBUILD
|
||||
+++ b/PKGBUILD
|
||||
@@ -6,7 +6,7 @@ pkgname=(
|
||||
asusctl
|
||||
rog-control-center
|
||||
)
|
||||
-pkgver=6.3.8
|
||||
+pkgver=6.4.0
|
||||
pkgrel=1
|
||||
pkgdesc="A control daemon, tools, and a collection of crates for interacting with ASUS ROG laptops"
|
||||
arch=('x86_64')
|
||||
@@ -28,2 +28,2 @@
|
||||
-source=("git+https://gitlab.com/asus-linux/asusctl.git#tag=$pkgver")
|
||||
-b2sums=('01269bc9fe63c1ce37568f9085c25dbcaaaa5cd9f51339d4c6904600d179ec826dace289d6e4e3501988fce5800da98e9cfa18b21c40da152d91c4f7fe821ffe')
|
||||
+source=("git+https://github.com/opengamingcollective/asusctl.git#tag=$pkgver")
|
||||
+b2sums=('0cfdc7f792fc6499cde9e4c9c6d82e484605e1b2878bb9f3a0e0696f5910b9ba7898f124fecd5fb3f39a0787f81e5163721606290099d757365dc3d6715a1bcf')
|
||||
+38
-87
@@ -1,108 +1,59 @@
|
||||
# Maintainer: Fabian Bornschein <fabiscafe@archlinux.org>
|
||||
# Maintainer: Mahdi Sarikhani <mahdisarikhani@outlook.com>
|
||||
# Contributor: Fabian Bornschein <fabiscafe@archlinux.org>
|
||||
# Contributor: Static_Rocket
|
||||
|
||||
pkgbase=asusctl
|
||||
pkgname=(
|
||||
asusctl
|
||||
rog-control-center
|
||||
)
|
||||
pkgname=(asusctl rog-control-center)
|
||||
pkgver=6.4.0
|
||||
pkgrel=1.1
|
||||
pkgdesc="A control daemon, tools, and a collection of crates for interacting with ASUS ROG laptops"
|
||||
pkgrel=1
|
||||
pkgdesc="Daemon and tools to control your ASUS ROG laptop"
|
||||
arch=('x86_64')
|
||||
url="https://asus-linux.org"
|
||||
license=('MPL-2.0')
|
||||
makedepends=(
|
||||
clang
|
||||
cmake
|
||||
fontconfig
|
||||
git
|
||||
hicolor-icon-theme
|
||||
libayatana-appindicator
|
||||
libinput
|
||||
libusb
|
||||
rust
|
||||
seatd
|
||||
systemd
|
||||
)
|
||||
source=("git+https://github.com/opengamingcollective/asusctl.git#tag=$pkgver")
|
||||
b2sums=('0cfdc7f792fc6499cde9e4c9c6d82e484605e1b2878bb9f3a0e0696f5910b9ba7898f124fecd5fb3f39a0787f81e5163721606290099d757365dc3d6715a1bcf')
|
||||
makedepends=('cargo' 'fontconfig')
|
||||
source=("${pkgbase}-${pkgver}.tar.gz::https://github.com/OpenGamingCollective/asusctl/archive/${pkgver}.tar.gz")
|
||||
b2sums=('e90074e904f364386ad661784bd9fc2e929e83ea06ac62fd1d34eb03490cefe8aae3bed2722162f1e8ea5d69248138cb5fd9f90c3a18443d1d8c04cf732b928a')
|
||||
|
||||
prepare() {
|
||||
cd "${pkgbase}"
|
||||
|
||||
# Keep rust/cargo build-dependency management inside the build directory
|
||||
export CARGO_HOME="${srcdir}/cargo"
|
||||
|
||||
# Follow Rust package guidelines
|
||||
## https://wiki.archlinux.org/title/Rust_package_guidelines
|
||||
export RUSTUP_TOOLCHAIN=stable
|
||||
cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
|
||||
cd "${pkgbase}-${pkgver}"
|
||||
export RUSTUP_TOOLCHAIN=stable
|
||||
cargo fetch --locked --target host-tuple
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${pkgbase}"
|
||||
|
||||
# Keep rust/cargo build-dependency management inside the build directory
|
||||
export CARGO_HOME="${srcdir}/cargo"
|
||||
|
||||
# Follow Rust package guidelines
|
||||
## https://wiki.archlinux.org/title/Rust_package_guidelines
|
||||
export RUSTUP_TOOLCHAIN=stable
|
||||
export CARGO_TARGET_DIR=target
|
||||
|
||||
make build
|
||||
cd "${pkgbase}-${pkgver}"
|
||||
export RUSTUP_TOOLCHAIN=stable
|
||||
export CARGO_TARGET_DIR=target
|
||||
make build
|
||||
}
|
||||
|
||||
package_asusctl() {
|
||||
pkgdesc="${pkgdesc/tools/CLI tools}"
|
||||
depends=(
|
||||
glibc
|
||||
libgcc
|
||||
libusb
|
||||
systemd
|
||||
systemd-libs
|
||||
)
|
||||
conflicts=(gnome-shell-extension-asusctl-gnome)
|
||||
install=asusctl.install
|
||||
optdepends=(
|
||||
'acpi_call: fan control'
|
||||
'asusctltray: tray profile switcher'
|
||||
'rog-control-center: app to control asusctl'
|
||||
'supergfxctl: hybrid GPU control'
|
||||
)
|
||||
pkgdesc="An utility for Linux to control many aspects of various ASUS laptops"
|
||||
depends=('glibc' 'libgcc' 'libusb' 'systemd-libs')
|
||||
optdepends=(
|
||||
'acpi_call: fan control'
|
||||
'asusctltray: tray profile switcher'
|
||||
'rog-control-center: graphical user interface for asusctl'
|
||||
'supergfxctl: hybrid GPU control'
|
||||
)
|
||||
install=asusctl.install
|
||||
|
||||
cd "${pkgbase}"
|
||||
export CARGO_HOME="${srcdir}/cargo"
|
||||
make DESTDIR="${pkgdir}" \
|
||||
install-asusctl \
|
||||
install-asusd \
|
||||
install-asusd_user \
|
||||
install-asus-shutdown \
|
||||
install-data-asusd \
|
||||
install-data-asusd_user
|
||||
cd "${pkgbase}-${pkgver}"
|
||||
make DESTDIR="${pkgdir}" \
|
||||
install-asusctl \
|
||||
install-asusd \
|
||||
install-asusd_user \
|
||||
install-asus-shutdown \
|
||||
install-data-asusd \
|
||||
install-data-asusd_user
|
||||
}
|
||||
|
||||
package_rog-control-center() {
|
||||
depends=(
|
||||
asusctl
|
||||
fontconfig
|
||||
freetype2
|
||||
glibc
|
||||
hicolor-icon-theme
|
||||
libayatana-appindicator
|
||||
libgcc
|
||||
libinput
|
||||
libxkbcommon
|
||||
mesa
|
||||
seatd
|
||||
systemd-libs
|
||||
)
|
||||
pkgdesc="App to control asusctl"
|
||||
pkgdesc="Graphical user interface for asusctl"
|
||||
depends=('asusctl' 'fontconfig' 'glibc' 'hicolor-icon-theme' 'libgcc' 'systemd-libs')
|
||||
|
||||
cd "${pkgbase}"
|
||||
export CARGO_HOME="${srcdir}/cargo"
|
||||
make DESTDIR="${pkgdir}" \
|
||||
install-data-rog_gui \
|
||||
install-rog_gui
|
||||
cd "${pkgbase}-${pkgver}"
|
||||
make DESTDIR="${pkgdir}" \
|
||||
install-rog_gui \
|
||||
install-data-rog_gui
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
post_install() {
|
||||
printf ":: asusd provides a service that is activated by an udev rule on\n"
|
||||
printf ":: startup. Please reboot the system or run\n"
|
||||
printf ":: # systemctl start asusd.service\n"
|
||||
printf ":: to make it work.\n"
|
||||
printf ":: See https://gitlab.com/asus-linux/asusctl#kernel-support.\n"
|
||||
printf ":: for latest required kernel patches/versions\n"
|
||||
printf ":: asusd provides a service that is activated by an udev rule on\n"
|
||||
printf ":: startup. Please reboot the system or run\n"
|
||||
printf ":: # systemctl start asusd.service\n"
|
||||
printf ":: to make it work.\n"
|
||||
printf ":: See https://github.com/OpenGamingCollective/asusctl#kernel-requirements\n"
|
||||
printf ":: for latest required kernel patches/versions\n"
|
||||
}
|
||||
|
||||
post_upgrade() {
|
||||
if systemctl is-active asusd.service --quiet
|
||||
then
|
||||
printf ":: asusd service will be restarted…\n"
|
||||
systemctl daemon-reload
|
||||
systemctl restart asusd.service
|
||||
fi
|
||||
printf ":: See https://gitlab.com/asus-linux/asusctl#kernel-support.\n"
|
||||
printf ":: for latest required kernel patches/versions\n"
|
||||
if systemctl is-active asusd.service --quiet; then
|
||||
printf ":: asusd service will be restarted…\n"
|
||||
systemctl daemon-reload
|
||||
systemctl restart asusd.service
|
||||
fi
|
||||
printf ":: See https://github.com/OpenGamingCollective/asusctl#kernel-requirements\n"
|
||||
printf ":: for latest required kernel patches/versions\n"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"release_ring": "fast",
|
||||
"upstream_commit": "fe2a6345e271f618dc3adf31e48557a717866395"
|
||||
"upstream_commit": "1e7bd48ef192b3d6a2854916e75e14ea43f6f0b7"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Basecamp <support@basecamp.com>
|
||||
pkgname=basecamp-cli
|
||||
pkgver=0.9.1
|
||||
pkgver=0.10.0
|
||||
pkgrel=1
|
||||
pkgdesc="CLI for Basecamp project management"
|
||||
arch=('x86_64' 'aarch64')
|
||||
@@ -13,10 +13,10 @@ optdepends=(
|
||||
'zsh: for zsh shell completions'
|
||||
'fish: for fish shell completions'
|
||||
)
|
||||
source_x86_64=("https://github.com/basecamp/basecamp-cli/releases/download/v0.9.1/basecamp_${pkgver}_linux_amd64.tar.gz")
|
||||
source_aarch64=("https://github.com/basecamp/basecamp-cli/releases/download/v0.9.1/basecamp_${pkgver}_linux_arm64.tar.gz")
|
||||
sha256sums_x86_64=('bcb1fa3a03e702bbf81a3004ded4bc7808605e41106cbc768ba4006b89e0db2f')
|
||||
sha256sums_aarch64=('ff50313024b6ca14e40146e30e1c9c9c00a4e4103fe55615eeee3e7c359d88d1')
|
||||
source_x86_64=("https://github.com/basecamp/basecamp-cli/releases/download/v0.10.0/basecamp_${pkgver}_linux_amd64.tar.gz")
|
||||
source_aarch64=("https://github.com/basecamp/basecamp-cli/releases/download/v0.10.0/basecamp_${pkgver}_linux_arm64.tar.gz")
|
||||
sha256sums_x86_64=('ca8b3a085f90323c8ab1694b83ff624cf10c459618ca6010ce204534f3f01987')
|
||||
sha256sums_aarch64=('dd1b5db88b9b309e95ae1ec0d642d23f4955a3abe159bffe00796a0ef6030c1d')
|
||||
|
||||
package() {
|
||||
install -Dm755 "basecamp" "${pkgdir}/usr/bin/basecamp"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"release_ring": "fast",
|
||||
"upstream_commit": "29ca1941149bbf080d7eb6d2bb53cddc76478a1a"
|
||||
"upstream_commit": "87aa5d5f2771c83dae737fe1bcfbc129110291fb"
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
# Automation repository: https://github.com/fabifont/claude-code-aur
|
||||
|
||||
pkgname=claude-code
|
||||
pkgver=2.1.252
|
||||
pkgver=2.1.263
|
||||
pkgrel=1
|
||||
pkgdesc="An agentic coding tool that lives in your terminal"
|
||||
arch=('x86_64' 'aarch64')
|
||||
@@ -29,8 +29,8 @@ source_x86_64=("claude-${pkgver}-x86_64::https://downloads.claude.ai/claude-code
|
||||
source_aarch64=("claude-${pkgver}-aarch64::https://downloads.claude.ai/claude-code-releases/${pkgver}/linux-arm64/claude")
|
||||
|
||||
sha256sums=('SKIP')
|
||||
sha256sums_x86_64=('a715a45105e593fc9808d035d77781f88480b9897975a9df41837f0c591bd4b3')
|
||||
sha256sums_aarch64=('6c0b32eaa936954a0f4d4ad2595f8416af288d9b3cbaf19e3cdd9a95d7c8853e')
|
||||
sha256sums_x86_64=('26d020351e8112f4006790f3cfce43b4c9df0c1bb1d0e542364d64151b81d5ba')
|
||||
sha256sums_aarch64=('7d25d7c8ae6c6e009cc7dae4e817f674179fd31fb7761bcd56fee4c2902b4c03')
|
||||
|
||||
package() {
|
||||
install -Dm755 "${srcdir}/claude-${pkgver}-${CARCH}" "${pkgdir}/opt/claude-code/bin/claude"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"upstream_commit": "76b9ce02837a49de0fa50cfa3da5d1c0c692ece5"
|
||||
"upstream_commit": "0e012cbfe1ea6cbbf15e2ada9cf93cca7aaa9ca0"
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
# Maintainer: bjarneo <https://github.com/bjarneo>
|
||||
pkgname=cliamp
|
||||
pkgver=1.63.2
|
||||
pkgver=2.0.1
|
||||
pkgrel=1
|
||||
pkgdesc='A retro terminal music player inspired by Winamp 2.x'
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://github.com/bjarneo/cliamp'
|
||||
license=('MIT')
|
||||
depends=('alsa-lib' 'flac' 'libvorbis' 'libogg' 'ffmpeg' 'yt-dlp')
|
||||
depends=('alsa-lib' 'flac' 'libvorbis' 'libogg' 'mpg123' 'ffmpeg' 'yt-dlp')
|
||||
optdepends=('pipewire-alsa: audio output on PipeWire systems'
|
||||
'pulseaudio-alsa: audio output on PulseAudio systems')
|
||||
makedepends=('go')
|
||||
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/bjarneo/cliamp/archive/refs/tags/v${pkgver}.tar.gz")
|
||||
sha256sums=('968ff98c1e49bae8a0ce63acf5c77a9621ef70756a048e3df5e79454b82a9eef')
|
||||
sha256sums=('2c5885665dba5ed2e8dc156bce64751199a92efed7f63959c65e985759b73732')
|
||||
|
||||
build() {
|
||||
cd "${pkgname}-${pkgver}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"release_ring": "fast",
|
||||
"upstream_commit": "00756d82c31b0056800bb98220c83800ebb85e72"
|
||||
"upstream_commit": "c5073d62f60f3973a14340eb1b40fc5b5a4ea9f0"
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
# Maintainer: Gunther Schulz <dev@guntherschulz.de>
|
||||
|
||||
pkgname=cursor-bin
|
||||
pkgver=3.18.25
|
||||
pkgver=3.19.13
|
||||
pkgrel=1
|
||||
pkgdesc='AI-first coding environment'
|
||||
arch=('x86_64')
|
||||
url="https://www.cursor.com"
|
||||
license=('LicenseRef-Cursor_EULA')
|
||||
# upstream uses Electron newer than internal VSCode
|
||||
_electron=electron40
|
||||
_electron=electron42
|
||||
depends=(xdg-utils ripgrep $_electron nodejs
|
||||
'gcc-libs' 'hicolor-icon-theme' 'libxkbfile')
|
||||
options=(!strip !debug) # Don't break ext of VSCode
|
||||
_commit=280eca2911f1774689696e5f1efa5a4f97a87af3
|
||||
_commit=dd066f332fcea7382764400fde902f61920648d5
|
||||
source=("https://downloads.cursor.com/production/${_commit}/linux/x64/deb/amd64/deb/cursor_${pkgver}_amd64.deb"
|
||||
"https://gitlab.archlinux.org/archlinux/packaging/packages/code/-/raw/main/code."{sh,mjs}
|
||||
rg.sh)
|
||||
@@ -20,7 +20,7 @@ sha512sums=('SKIP'
|
||||
'937299c6cb6be2f8d25f7dbc95cf77423875c5f8353b8bd6cd7cc8e5603cbf8405b14dbf8bd615db2e3b36ed680fc8e1909410815f7f8587b7267a699e00ab37'
|
||||
'793f9ff6306e3992ac89802d98110cba288ea1181a901467333293b7d76182ef9792c2a39ff49d9347a18a174b1f42bc58862091dff583f4146c2704eea28033'
|
||||
'e79fe7659f59d1ae02fc68816399bfd31587315df6cdb6ccf1d0ca76f7cdc692c2a42b30591c0091147bd97ef14b1c7745dc26bd7cb3ea6bba45698e5044fa2a')
|
||||
sha512sums[0]=5f25c9dccf75c764b6266e74136ad5cf6e99330804c7ae3ed22d4210304791b1ac1233efb07b291da490fbfe3d4801cb46680a171ddf6b2815e0267741ec339a
|
||||
sha512sums[0]=3c952035fa1809caded7059b7addbb01a9143cd248ecff27cdb3cb3af47d4bc824ed60dfd9757e105a342e53280e075d81f775790295a3272818bab5a994b305
|
||||
noextract=(cursor_${pkgver}_amd64.deb) # avoid double tarball
|
||||
_app=usr/share/cursor/resources/app
|
||||
package() {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/PKGBUILD
|
||||
+++ b/PKGBUILD
|
||||
@@ -11,7 +11,7 @@ pkgname=dropbox-cli
|
||||
pkgver=2024.04.17
|
||||
pkgrel=2
|
||||
pkgdesc="Command line interface for Dropbox"
|
||||
-arch=("any")
|
||||
+arch=("x86_64")
|
||||
url="https://www.dropbox.com"
|
||||
license=("GPL-3.0-or-later")
|
||||
makedepends=("gdk-pixbuf2")
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
pkgname=dropbox-cli
|
||||
pkgver=2024.04.17
|
||||
pkgrel=2
|
||||
pkgrel=2.1
|
||||
pkgdesc="Command line interface for Dropbox"
|
||||
arch=("any")
|
||||
arch=("x86_64")
|
||||
url="https://www.dropbox.com"
|
||||
license=("GPL-3.0-or-later")
|
||||
makedepends=("gdk-pixbuf2")
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"min_release_age": "24h"
|
||||
}
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
# Flea publishes signed source tags but no release artifacts or checksum manifest.
|
||||
# Check the small GitHub source tarball only when a newer stable release exists,
|
||||
# validate its expected root, then report its hash alongside the fixed hashes of
|
||||
# the four upstream security patches carried until a release includes them.
|
||||
set -euo pipefail
|
||||
|
||||
REPO='thisisgm/flea'
|
||||
RELEASES_URL="https://api.github.com/repos/$REPO/releases?per_page=100"
|
||||
PATCH_2BD7CC2='c610a9f44294b67341940203943c9c567003b65cc436d6013cd36754379183d8'
|
||||
PATCH_27D19CA='e457ef17e26f70057b1184eeb938fccc5906f48a7c77f1df573d55d13a845425'
|
||||
PATCH_23290CE='f8381456a3b5f39d341cc6610bf27beb8354892b17a1c8c6d7882db4e40824c3'
|
||||
PATCH_B4B7EE4='46bdbe43f135a052c893b1987f8b0928736445616a84b0c65d2181ee74b21b25'
|
||||
|
||||
current=$(awk -F= '/^pkgver=/ { print $2; exit }' PKGBUILD)
|
||||
releases=$(curl -fsSL "$RELEASES_URL")
|
||||
now=$(date +%s)
|
||||
min_age=${MIN_RELEASE_AGE_SECONDS:-0}
|
||||
|
||||
candidates=0
|
||||
best_version=''
|
||||
best_tag=''
|
||||
best_published_at=''
|
||||
|
||||
while IFS=$'\t' read -r tag published_at; do
|
||||
if [[ ! $tag =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
|
||||
printf '%s has an unusable stable release tag: %s\n' "$REPO" "${tag:-<empty>}" >&2
|
||||
exit 1
|
||||
fi
|
||||
version=${BASH_REMATCH[1]}
|
||||
|
||||
if [[ -z $published_at ]] || ! published_epoch=$(date --date="$published_at" +%s 2>/dev/null); then
|
||||
printf '%s release %s has an invalid publication time\n' "$REPO" "$tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
candidates=$((candidates + 1))
|
||||
|
||||
if (( now - published_epoch < min_age )) && [[ ${BYPASS_MIN_RELEASE_AGE:-} != 1 ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -z $best_version ]] || (( $(vercmp "$version" "$best_version") > 0 )); then
|
||||
best_version=$version
|
||||
best_tag=$tag
|
||||
best_published_at=$published_at
|
||||
fi
|
||||
done < <(jq -r '.[] | select((.draft or .prerelease) | not) | [.tag_name // "", .published_at // ""] | @tsv' <<<"$releases")
|
||||
|
||||
if (( candidates == 0 )); then
|
||||
printf 'No stable releases found for %s\n' "$REPO" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $best_version ]] || (( $(vercmp "$best_version" "$current") <= 0 )); then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
tarball=$(mktemp)
|
||||
trap 'rm -f "$tarball"' EXIT
|
||||
curl -fsSL -o "$tarball" "https://github.com/$REPO/archive/refs/tags/$best_tag.tar.gz"
|
||||
|
||||
expected_root="flea-$best_version"
|
||||
served_roots=$(tar -tzf "$tarball" | cut -d/ -f1 | sort -u)
|
||||
if [[ $served_roots != "$expected_root" ]]; then
|
||||
printf 'Release %s contains root %s, expected %s\n' "$best_tag" "$served_roots" "$expected_root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
archive_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/archive.rs")
|
||||
archiveops_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/archiveops.rs")
|
||||
run_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/run.rs")
|
||||
archivereq_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/archivereq.rs")
|
||||
archivework_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/archivework.rs")
|
||||
mediaprobe_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/mediaprobe.rs")
|
||||
metareq_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/metareq.rs")
|
||||
sharelink_qml=$(tar -xOzf "$tarball" "$expected_root/ui/ShareLink.qml")
|
||||
copyfile_rs=$(tar -xOzf "$tarball" "$expected_root/src/backend/copyfile.rs")
|
||||
|
||||
if ! grep -Fq 'a.push("--".to_string());' <<<"$archive_rs" ||
|
||||
! grep -Fq 'let input = std::fs::canonicalize(input)' <<<"$archiveops_rs" ||
|
||||
! grep -Fq 'if op != "compress" && op != "extract"' <<<"$run_rs$archivereq_rs" ||
|
||||
! grep -Fq 'the sandbox is unavailable: bwrap or prlimit is not on PATH' <<<"$archivework_rs" ||
|
||||
! grep -Fq 'if !sandbox::available()' <<<"$mediaprobe_rs" ||
|
||||
! grep -Fq 'if !sandbox::available()' <<<"$metareq_rs" ||
|
||||
! grep -Fq 'copyToClipboard.command = ["wl-copy", url]' <<<"$sharelink_qml" ||
|
||||
! grep -Fq '.custom_flags(O_NOFOLLOW)' <<<"$copyfile_rs"; then
|
||||
printf 'Release %s does not contain every required upstream security fix\n' "$best_tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jq -n \
|
||||
--arg pkgver "$best_version" \
|
||||
--arg published_at "$best_published_at" \
|
||||
--arg source "$(sha256sum "$tarball" | cut -d' ' -f1)" \
|
||||
--arg patch_2bd7cc2 "$PATCH_2BD7CC2" \
|
||||
--arg patch_27d19ca "$PATCH_27D19CA" \
|
||||
--arg patch_23290ce "$PATCH_23290CE" \
|
||||
--arg patch_b4b7ee4 "$PATCH_B4B7EE4" \
|
||||
'{pkgver: $pkgver, published_at: $published_at, sha256sums: {any: [$source, $patch_2bd7cc2, $patch_27d19ca, $patch_23290ce, $patch_b4b7ee4]}}'
|
||||
@@ -0,0 +1,163 @@
|
||||
# Maintainer: GM <gianmarcomorales@icloud.com>
|
||||
|
||||
pkgname=flea
|
||||
pkgver=0.1.3
|
||||
pkgrel=1
|
||||
pkgdesc='Fast, keyboard-first file manager for Omarchy'
|
||||
arch=('x86_64')
|
||||
url='https://github.com/thisisgm/flea'
|
||||
license=('MIT')
|
||||
|
||||
depends=(
|
||||
'bubblewrap'
|
||||
'gcc-libs'
|
||||
'glib2'
|
||||
'glibc'
|
||||
'hicolor-icon-theme'
|
||||
'omarchy'
|
||||
'quickshell'
|
||||
'qt6-multimedia'
|
||||
'qt6-webengine'
|
||||
'shared-mime-info'
|
||||
'util-linux'
|
||||
'xdg-utils'
|
||||
)
|
||||
makedepends=('cargo')
|
||||
optdepends=(
|
||||
'7zip: 7z archive support'
|
||||
'dropbox-cli: Dropbox browsing and share links'
|
||||
'ffmpeg: media metadata previews'
|
||||
'imagemagick: image conversion'
|
||||
'libarchive: archive listing and extraction'
|
||||
'tailscale: Taildrop sharing'
|
||||
'wl-clipboard: copy Dropbox share links to the clipboard'
|
||||
)
|
||||
conflicts=('flea-git')
|
||||
options=('!debug')
|
||||
|
||||
_security_patches=(
|
||||
'2bd7cc207c110ae3b3ea61a4d4e42336f1815111'
|
||||
'27d19ca4a38ef4a0a920fb78441ce662a0101327'
|
||||
'23290ce1917b0d7f0392dd09d04bf2a7504ec93a'
|
||||
'b4b7ee47244b52457eec2874e21a8656d8ace647'
|
||||
)
|
||||
source=(
|
||||
"$pkgname-$pkgver.tar.gz::$url/archive/refs/tags/v$pkgver.tar.gz"
|
||||
"security-2bd7cc2.patch::$url/commit/${_security_patches[0]}.patch"
|
||||
"security-27d19ca.patch::$url/commit/${_security_patches[1]}.patch"
|
||||
"security-23290ce.patch::$url/commit/${_security_patches[2]}.patch"
|
||||
"security-b4b7ee4.patch::$url/commit/${_security_patches[3]}.patch"
|
||||
)
|
||||
sha256sums=(
|
||||
'3599ab76253c444dea027f1ebe85b32612d9a174e60eb8aca33ee21d9e2d6973'
|
||||
'c610a9f44294b67341940203943c9c567003b65cc436d6013cd36754379183d8'
|
||||
'e457ef17e26f70057b1184eeb938fccc5906f48a7c77f1df573d55d13a845425'
|
||||
'f8381456a3b5f39d341cc6610bf27beb8354892b17a1c8c6d7882db4e40824c3'
|
||||
'46bdbe43f135a052c893b1987f8b0928736445616a84b0c65d2181ee74b21b25'
|
||||
)
|
||||
|
||||
prepare() {
|
||||
cd "$pkgname-$pkgver"
|
||||
|
||||
security_patch_present() {
|
||||
case "$1" in
|
||||
2bd7cc207c110ae3b3ea61a4d4e42336f1815111)
|
||||
grep -Fq 'a.push("--".to_string());' src/backend/archive.rs &&
|
||||
grep -Fq 'let input = std::fs::canonicalize(input)' src/backend/archiveops.rs &&
|
||||
grep -Fq 'if op != "compress" && op != "extract"' \
|
||||
src/backend/run.rs src/backend/archivereq.rs
|
||||
;;
|
||||
27d19ca4a38ef4a0a920fb78441ce662a0101327)
|
||||
grep -Fq 'the sandbox is unavailable: bwrap or prlimit is not on PATH' src/backend/archivework.rs &&
|
||||
grep -Fq 'if !sandbox::available()' src/backend/mediaprobe.rs &&
|
||||
grep -Fq 'if !sandbox::available()' src/backend/metareq.rs
|
||||
;;
|
||||
23290ce1917b0d7f0392dd09d04bf2a7504ec93a)
|
||||
grep -Fq 'copyToClipboard.command = ["wl-copy", url]' ui/ShareLink.qml
|
||||
;;
|
||||
b4b7ee47244b52457eec2874e21a8656d8ace647)
|
||||
grep -Fq '.custom_flags(O_NOFOLLOW)' src/backend/copyfile.rs
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
local commit patch_file
|
||||
for commit in "${_security_patches[@]}"; do
|
||||
patch_file="$srcdir/security-${commit:0:7}.patch"
|
||||
|
||||
if patch --batch --forward --dry-run -Np1 -i "$patch_file" >/dev/null 2>&1; then
|
||||
patch --batch --forward -Np1 -i "$patch_file"
|
||||
elif security_patch_present "$commit"; then
|
||||
printf 'Security patch %s is already present upstream\n' "$commit"
|
||||
else
|
||||
printf 'Security patch %s no longer applies and is not present upstream\n' "$commit" >&2
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$pkgname-$pkgver"
|
||||
|
||||
export CARGO_TARGET_DIR=target
|
||||
cargo build --frozen --release
|
||||
}
|
||||
|
||||
check() {
|
||||
cd "$pkgname-$pkgver"
|
||||
|
||||
export CARGO_TARGET_DIR=target
|
||||
|
||||
local -a test_args=()
|
||||
if ! /usr/bin/prlimit --cpu=30 --as=1073741824 \
|
||||
/usr/bin/bwrap --unshare-all --die-with-parent --new-session --clearenv \
|
||||
--ro-bind /usr /usr --ro-bind /etc /etc \
|
||||
--symlink usr/lib /lib --symlink usr/lib /lib64 \
|
||||
--symlink usr/bin /bin --symlink usr/bin /sbin \
|
||||
--proc /proc --dev /dev --tmpfs /tmp /usr/bin/true >/dev/null 2>&1; then
|
||||
printf 'Skipping sandbox integration tests: this builder cannot create an unprivileged namespace\n'
|
||||
test_args+=(
|
||||
--skip backend::archiveops::tests::a_tool_that_exits_zero_writing_nothing_is_caught_by_the_predicate
|
||||
--skip backend::archiveops::tests::an_empty_archive_extracts_to_an_empty_directory_and_that_is_success
|
||||
--skip backend::archiveops::tests::only_the_archive_root_extracts_to_nothing_while_nested_directories_do_not
|
||||
--skip backend::archiveops::tests::the_emptiness_check_reads_the_destination_and_the_index_separately
|
||||
--skip backend::thumbs::tests::a_cancelled_job_never_runs
|
||||
--skip backend::thumbs::tests::a_real_file_round_trips_to_a_stamped_cache_entry
|
||||
--skip backend::thumbs::tests::cancel_all_empties_the_queue
|
||||
--skip backend::thumbs::tests::the_queue_is_bounded_and_drops_the_oldest_rather_than_growing
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ ! -x /usr/bin/evince-thumbnailer ]] ||
|
||||
[[ ! -x /usr/bin/ffmpegthumbnailer ]] ||
|
||||
[[ ! -x /usr/bin/glycin-thumbnailer ]]; then
|
||||
printf 'Skipping thumbnailer fixture tests: this builder lacks their optional host programs\n'
|
||||
test_args+=(
|
||||
--skip backend::thumbspec::tests::a_type_two_files_declare_goes_to_the_first_in_path_order
|
||||
--skip backend::thumbspec::tests::the_heaviest_shipped_field_parses
|
||||
)
|
||||
fi
|
||||
|
||||
cargo test --frozen --release -- "${test_args[@]}"
|
||||
./tests/js.sh
|
||||
./tests/keymap-gen.sh
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$pkgname-$pkgver"
|
||||
|
||||
install -Dm755 target/release/flea "$pkgdir/usr/bin/flea"
|
||||
install -Dm644 packaging/com.thisisgm.flea.desktop \
|
||||
"$pkgdir/usr/share/applications/com.thisisgm.flea.desktop"
|
||||
install -Dm644 packaging/com.thisisgm.flea.svg \
|
||||
"$pkgdir/usr/share/icons/hicolor/scalable/apps/com.thisisgm.flea.svg"
|
||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||
|
||||
install -Dm644 ui/qmldir ui/*.qml -t "$pkgdir/usr/share/flea/ui"
|
||||
install -Dm644 ui/js/*.js -t "$pkgdir/usr/share/flea/ui/js"
|
||||
ln -s /usr/share/omarchy/shell/Commons "$pkgdir/usr/share/flea/ui/Commons"
|
||||
ln -s /usr/share/omarchy/shell/Ui "$pkgdir/usr/share/flea/ui/Ui"
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"upstream_commit": "fc4db00ecaf6c2669422b32c023a16bf6eb4e6c7"
|
||||
"upstream": {
|
||||
"npm": "@github/copilot",
|
||||
"sources": {
|
||||
"any": [
|
||||
"{npm_tarball}",
|
||||
"https://raw.githubusercontent.com/github/copilot-cli/v{pkgver}/changelog.md"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ _npmmodule=@github/copilot
|
||||
pkgname=github-copilot-cli
|
||||
_pkgexec=copilot
|
||||
|
||||
pkgver=1.0.82
|
||||
pkgver=1.0.83
|
||||
pkgrel=1
|
||||
|
||||
pkgdesc="GitHub Copilot CLI brings the power of Copilot coding agent directly to your terminal."
|
||||
@@ -14,7 +14,7 @@ pkgdesc="GitHub Copilot CLI brings the power of Copilot coding agent directly to
|
||||
url="https://github.com/github/copilot-cli"
|
||||
_urlraw="https://raw.githubusercontent.com/github/copilot-cli/v${pkgver}"
|
||||
|
||||
arch=("x86_64")
|
||||
arch=("x86_64" "aarch64")
|
||||
|
||||
license=("LicenseRef-GitHub-Copilot")
|
||||
|
||||
@@ -30,8 +30,10 @@ source=("https://registry.npmjs.org/${_npmmodule}/-/copilot-${pkgver}.tgz"
|
||||
"CHANGELOG-${pkgver}.md::${_urlraw}/changelog.md")
|
||||
noextract=("copilot-${pkgver}.tgz")
|
||||
|
||||
b2sums=('41c8306b58a142afe162bad9822b150babb0f3903fe7392aa7106fcb0ffce4483c0a2ebda8bb1d2036199deb52dc83d9a0e9408b8e11f7b0bc2a8f57c6841425'
|
||||
'5d2dfc870356f83b9b890d351b21bc9339100b0bfdce405ee77751e934dbeab0f8656f5eee85119a06aa3b01dcf3c91224ce28c24ff318eb1b13fdb6082037cd')
|
||||
sha256sums=(
|
||||
'135506fc2b13163ab55dbf76a06e2fbcbad04ecac76b4e9c6659f0ba309e6a86'
|
||||
'0c0064a10effac8adf9ad97338bafaa0d7d7d5bf191cc1c0384e05ff4366d36c'
|
||||
)
|
||||
|
||||
# Document: https://wiki.archlinux.org/title/Node.js_package_guidelines
|
||||
package() {
|
||||
@@ -124,4 +126,3 @@ package() {
|
||||
ln -sf "/usr/lib/node_modules/${_npmmodule}/LICENSE.md" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||
|
||||
}
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
# Maintainer: David Heinemeier Hansson <david@hey.com>
|
||||
|
||||
# Nous builds Hermes Desktop for macOS and Windows only -- their download page
|
||||
# offers a .dmg and an .exe and tells Linux users to install from a terminal --
|
||||
# so there is no vendor binary to repackage. Their electron-builder config does
|
||||
# carry a Linux target, though, and it works; this builds it.
|
||||
#
|
||||
# The app only runs against a Hermes runtime built from its own commit, so it
|
||||
# provisions one itself under ~/.hermes on first launch and the package stays
|
||||
# on the newest tag. Pairing it with the mise CLI instead was tried and does
|
||||
# not work: PyPI trails the tags, and the version gap fails the readiness probe
|
||||
# with a 401. Pinning back to the tag behind PyPI's release does not rescue it
|
||||
# either -- v2026.7.20's desktop hangs after "backend is ready" without ever
|
||||
# opening a window, against its own matching runtime.
|
||||
#
|
||||
# The app is only a shell: it runs `hermes serve` against a Hermes CLI it does
|
||||
# not ship, and clones its own copy with the upstream install script when it
|
||||
# finds none. /usr/bin/hermes-desktop heads that off. See hermes-desktop.sh.
|
||||
# Build a prebuilt release; Omarchy seeds it into the user's Hermes checkout
|
||||
# so the upstream updater can rebuild and relaunch it in place.
|
||||
|
||||
pkgname=hermes-desktop
|
||||
pkgver=2026.8.18
|
||||
pkgrel=2
|
||||
pkgver=2026.8.31
|
||||
pkgrel=3
|
||||
pkgdesc='Native desktop shell for Hermes Agent'
|
||||
arch=('x86_64')
|
||||
url='https://github.com/NousResearch/hermes-agent'
|
||||
@@ -32,7 +18,7 @@ depends=(
|
||||
'dbus'
|
||||
'expat'
|
||||
'curl'
|
||||
'gcc-libs'
|
||||
'gcc'
|
||||
'gdk-pixbuf2'
|
||||
'git'
|
||||
'glib2'
|
||||
@@ -52,19 +38,24 @@ depends=(
|
||||
'libxfixes'
|
||||
'libxkbcommon'
|
||||
'libxrandr'
|
||||
'make'
|
||||
'mesa'
|
||||
'nodejs'
|
||||
'npm'
|
||||
'nspr'
|
||||
'nss'
|
||||
'pango'
|
||||
'python'
|
||||
'systemd-libs'
|
||||
'util-linux'
|
||||
'xdg-utils'
|
||||
)
|
||||
|
||||
optdepends=('omarchy: installs the Hermes CLI the app needs on first launch')
|
||||
optdepends=('omarchy: sets up the user installation for in-app updates')
|
||||
|
||||
# The build runs the repo's own npm workspace install, which fetches Electron
|
||||
# and rebuilds node-pty against it.
|
||||
makedepends=('git' 'imagemagick' 'nodejs' 'npm' 'python')
|
||||
makedepends=('imagemagick')
|
||||
|
||||
# Electron bundles prebuilt binaries that stripping corrupts.
|
||||
options=('!strip' '!debug')
|
||||
@@ -74,23 +65,27 @@ options=('!strip' '!debug')
|
||||
# before falling back to `git rev-parse`. That fallback is wrong here: makepkg
|
||||
# builds inside this repository, so git ascends out of srcdir and stamps the
|
||||
# app with an omarchy-pkgs commit that means nothing upstream.
|
||||
_commit=e624e9fde561e1add9388384012b295fde669ade
|
||||
_commit=29112bef099274229cadff79cdff7bf7b99c4b77
|
||||
|
||||
_srcdir="hermes-agent-${pkgver}"
|
||||
source=("${pkgname}-${pkgver}.tar.gz::${url}/archive/refs/tags/v${pkgver}.tar.gz"
|
||||
'hermes-desktop.sh'
|
||||
'hermes-desktop.desktop'
|
||||
'hermes-desktop.png')
|
||||
sha256sums=('1e3d39d3638ec15fa9d31af262568a953e9272090deb1c50c44cd401175f5b80'
|
||||
'f5833b969ce451aadee9f08d92db55cce3c7c9213175080590bf37444854d676'
|
||||
'hermes-desktop.png'
|
||||
'runtime.patch'
|
||||
'runtime-test.py')
|
||||
sha256sums=('78fb3ff707ec1d17044b875ecac8bef28aa39d44242824f6871ca40afe7bf217'
|
||||
'094d5f3191109a80eea9f23053b78a2e00dbecf90d62d1ca04c8e48866251469'
|
||||
'3ef685bfcf366776b025d26c37d32854d8d4aa2023b2bd07c8e08b001ef1e8c4'
|
||||
'd60d164e24fdcf6532133b8ea43c77a201e4b9e9dbc396187b58d51d8590ef52')
|
||||
'd60d164e24fdcf6532133b8ea43c77a201e4b9e9dbc396187b58d51d8590ef52'
|
||||
'03b67e26c234c797a6b1d4c9f34a57502dba37f462540e47ce6c88f6ea79302a'
|
||||
'461e1120e7e6779f531c114d9926479e47fab79113d1b4646efea36bc771b3c5')
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${_srcdir}"
|
||||
|
||||
export GITHUB_SHA="${_commit}"
|
||||
export GITHUB_REF_NAME="v${pkgver}"
|
||||
export GITHUB_REF_NAME="main"
|
||||
|
||||
# The desktop workspace resolves against the repo root, so the install has to
|
||||
# happen there rather than in apps/desktop.
|
||||
@@ -100,6 +95,10 @@ build() {
|
||||
npm run pack
|
||||
}
|
||||
|
||||
check() {
|
||||
python "${srcdir}/runtime-test.py" "${srcdir}/${_srcdir}" "${srcdir}/runtime.patch" "${srcdir}/hermes-desktop.sh"
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${_srcdir}/apps/desktop/release/linux-unpacked"
|
||||
|
||||
@@ -108,6 +107,12 @@ package() {
|
||||
|
||||
install -Dm755 "${srcdir}/hermes-desktop.sh" "${pkgdir}/usr/bin/${pkgname}"
|
||||
|
||||
install -Dm644 "${srcdir}/${_srcdir}/scripts/install.sh" \
|
||||
"${pkgdir}/usr/share/${pkgname}/install.sh"
|
||||
# Let the release's first updater relaunch with the user-namespace sandbox.
|
||||
install -Dm644 "${srcdir}/runtime.patch" "${pkgdir}/usr/share/${pkgname}/runtime.patch"
|
||||
|
||||
|
||||
install -Dm644 "${srcdir}/hermes-desktop.desktop" \
|
||||
"${pkgdir}/usr/share/applications/${pkgname}.desktop"
|
||||
|
||||
@@ -125,11 +130,6 @@ package() {
|
||||
install -Dm644 "${pkgdir}/opt/${pkgname}/LICENSE.electron.txt" \
|
||||
"${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.electron.txt"
|
||||
|
||||
# Chromium's setuid sandbox is only needed where unprivileged user namespaces
|
||||
# are unavailable; where they work, setuid root is the worse of the two.
|
||||
if ! { [[ -L /proc/self/ns/user ]] && unshare --user true; }; then
|
||||
chmod 4755 "${pkgdir}/opt/${pkgname}/chrome-sandbox"
|
||||
else
|
||||
chmod 0755 "${pkgdir}/opt/${pkgname}/chrome-sandbox"
|
||||
fi
|
||||
# The launcher requires the namespace sandbox on the target host.
|
||||
chmod 0755 "${pkgdir}/opt/${pkgname}/chrome-sandbox"
|
||||
}
|
||||
@@ -1,41 +1,74 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Hermes Desktop is a shell around a Hermes runtime, and it only works against
|
||||
# one built from its own commit. A CLI from PyPI is always a different release
|
||||
# -- PyPI trails the tags -- and the mismatch fails the app's readiness probe
|
||||
# with 401 Unauthorized. So keep it away from whatever `hermes` is on PATH,
|
||||
# which on Omarchy is the mise CLI installed for the terminal agent, and let
|
||||
# the app provision and manage its own runtime under ~/.hermes. That is the
|
||||
# arrangement upstream ships, and the only one that starts.
|
||||
unset ELECTRON_RUN_AS_NODE PYTHONPATH PYTHONHOME
|
||||
export HERMES_DESKTOP_IGNORE_EXISTING=1
|
||||
|
||||
# Chromium cannot reliably infer the Secret Service password-store backend
|
||||
# from a Hyprland session, even when GNOME Keyring is already providing it.
|
||||
# Keep an explicit user choice (such as KWallet), otherwise select the
|
||||
# libsecret backend that this package depends on.
|
||||
export HERMES_DESKTOP_PASSWORD_STORE="${HERMES_DESKTOP_PASSWORD_STORE:-gnome-libsecret}"
|
||||
|
||||
# Reconcile every launch rather than trusting whatever installed us. A plain
|
||||
# `pacman -S hermes-desktop`, or an install interrupted partway, leaves any
|
||||
# Hermes the terminal agent had built still sitting there, and by then the
|
||||
# menu entry that would have tidied it up is disabled because we are present.
|
||||
# Reconcile direct package installs and interrupted Omarchy setup as well.
|
||||
if command -v omarchy-install-hermes-cli >/dev/null 2>&1; then
|
||||
omarchy-install-hermes-cli >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# Chromium's own Ozone detection falls back to XWayland often enough to matter,
|
||||
# and the result is a blurry window on every scaled display. Ask for Wayland
|
||||
# directly, unless the user has already picked a platform themselves.
|
||||
platform_flags=()
|
||||
if [[ -n "${WAYLAND_DISPLAY:-}" || ${XDG_SESSION_TYPE:-} == wayland ]]; then
|
||||
platform_flags=(--ozone-platform=wayland)
|
||||
|
||||
for flag in "$@"; do
|
||||
case "$flag" in
|
||||
--ozone-platform=* | --ozone-platform-hint=*) platform_flags=() ;;
|
||||
esac
|
||||
done
|
||||
hermes_home=$(realpath -ms -- "${HERMES_HOME:-$HOME/.hermes}")
|
||||
parent=${hermes_home%/*}
|
||||
if [[ ${parent##*/} == [Pp][Rr][Oo][Ff][Ii][Ll][Ee][Ss] ]]; then
|
||||
hermes_home=${parent%/*}
|
||||
hermes_home=${hermes_home:-/}
|
||||
fi
|
||||
export HERMES_HOME="$hermes_home"
|
||||
runtime="$hermes_home/hermes-agent"
|
||||
native="$runtime/apps/desktop/release/linux-unpacked/Hermes"
|
||||
if [[ ! -x $native || ! -x $runtime/venv/bin/hermes ]]; then
|
||||
native=/opt/hermes-desktop/Hermes
|
||||
fi
|
||||
|
||||
exec /opt/hermes-desktop/Hermes "${platform_flags[@]}" "$@"
|
||||
# Both app locations use namespaces, never a user-writable setuid helper.
|
||||
if ! timeout 5 unshare --user --map-root-user true 2>/dev/null; then
|
||||
echo "Hermes Desktop requires working unprivileged user namespaces for its sandbox." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python=/usr/bin/python
|
||||
if [[ -x $runtime/venv/bin/python && -f $runtime/hermes_cli/main.py ]]; then
|
||||
python="$runtime/venv/bin/python"
|
||||
else
|
||||
runtime=""
|
||||
fi
|
||||
exec "$python" - "$native" "$runtime" "$@" <<'PY'
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
native, runtime, *args = sys.argv[1:]
|
||||
env = os.environ.copy()
|
||||
flags, gpu, store, ozone = [], "auto", "auto", "auto"
|
||||
if runtime:
|
||||
sys.path.insert(0, runtime)
|
||||
try:
|
||||
# Upstream moved the helper out of main after the packaged release.
|
||||
if Path(runtime, "hermes_cli/main_desktop.py").is_file():
|
||||
from hermes_cli.main_desktop import _desktop_launch_options
|
||||
else:
|
||||
from hermes_cli.main import _desktop_launch_options
|
||||
from hermes_constants import with_hermes_node_path
|
||||
|
||||
flags, gpu, store, ozone = _desktop_launch_options()
|
||||
env = with_hermes_node_path(env)
|
||||
except ImportError:
|
||||
print("Could not load Hermes desktop settings; using launch defaults.", file=sys.stderr)
|
||||
|
||||
env["HERMES_DESKTOP_CWD"] = os.getcwd()
|
||||
if gpu != "auto":
|
||||
env.setdefault("HERMES_DESKTOP_DISABLE_GPU", gpu)
|
||||
if ozone != "auto":
|
||||
env.setdefault("ELECTRON_OZONE_PLATFORM_HINT", ozone)
|
||||
env.setdefault("HERMES_DESKTOP_PASSWORD_STORE", store if store != "auto" else "gnome-libsecret")
|
||||
|
||||
# Explicit config, environment and command-line choices override the Wayland default.
|
||||
if (env.get("WAYLAND_DISPLAY") or env.get("XDG_SESSION_TYPE") == "wayland") and (
|
||||
"ELECTRON_OZONE_PLATFORM_HINT" not in env
|
||||
and not any(arg.startswith(("--ozone-platform=", "--ozone-platform-hint=")) for arg in flags + args)
|
||||
):
|
||||
flags.insert(0, "--ozone-platform=wayland")
|
||||
os.execve(native, [native, "--disable-setuid-sandbox", *flags, *args], env)
|
||||
PY
|
||||
@@ -0,0 +1,162 @@
|
||||
"""Check launch settings and sandbox gates without running Hermes or sudo."""
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
source, patch_file, launcher = map(Path, sys.argv[1:])
|
||||
with tempfile.TemporaryDirectory(prefix="hermes-runtime-check-") as temporary:
|
||||
root = Path(temporary)
|
||||
destination = root / "scripts/desktop-update/posix.sh"
|
||||
destination.parent.mkdir(parents=True)
|
||||
shutil.copyfile(source / "scripts/desktop-update/posix.sh", destination)
|
||||
subprocess.run(["git", "apply", str(patch_file.resolve())], cwd=root, check=True)
|
||||
|
||||
home = root / "home with spaces"
|
||||
runtime = home / ".hermes/hermes-agent"
|
||||
native = runtime / "apps/desktop/release/linux-unpacked"
|
||||
native.mkdir(parents=True)
|
||||
executable = native / "Hermes"
|
||||
executable.write_text(f"#!{sys.executable}\n" + '''import json, os, sys
|
||||
from pathlib import Path
|
||||
Path(os.environ["TEST_OUTPUT"]).write_text(json.dumps({
|
||||
"args": sys.argv[1:], "home": os.environ["HERMES_HOME"],
|
||||
"store": os.environ["HERMES_DESKTOP_PASSWORD_STORE"],
|
||||
"gpu": os.environ.get("HERMES_DESKTOP_DISABLE_GPU"),
|
||||
"ozone": os.environ.get("ELECTRON_OZONE_PLATFORM_HINT"),
|
||||
"cwd": os.environ.get("HERMES_DESKTOP_CWD"),
|
||||
"inherited": [name for name in ("ELECTRON_RUN_AS_NODE", "PYTHONPATH", "PYTHONHOME") if name in os.environ],
|
||||
}))
|
||||
''')
|
||||
executable.chmod(0o755)
|
||||
sandbox = native / "chrome-sandbox"
|
||||
sandbox.write_text("fixture")
|
||||
sandbox.chmod(0o755)
|
||||
|
||||
# Execute the release's real option parser, isolating config I/O and avoiding
|
||||
# unrelated CLI imports, startup hooks and third-party dependencies.
|
||||
module = runtime / "hermes_cli"
|
||||
module.mkdir()
|
||||
(module / "__init__.py").touch()
|
||||
upstream = ast.parse((source / "hermes_cli/main.py").read_text())
|
||||
option_parser = next(node for node in upstream.body
|
||||
if isinstance(node, ast.FunctionDef) and node.name == "_desktop_launch_options")
|
||||
stores = next(node for node in upstream.body if isinstance(node, ast.Assign)
|
||||
and any(isinstance(target, ast.Name) and target.id == "_LINUX_PASSWORD_STORES"
|
||||
for target in node.targets))
|
||||
helper = "import os, shlex\n" + ast.unparse(stores) + "\n" + ast.unparse(option_parser) + "\n"
|
||||
(module / "main.py").write_text(helper)
|
||||
(module / "config.py").write_text('''import json, os
|
||||
from pathlib import Path
|
||||
def load_config():
|
||||
path = Path(os.environ["HERMES_HOME"], "config.yaml")
|
||||
return json.loads(path.read_text()) if path.exists() else {}
|
||||
''')
|
||||
(runtime / "hermes_constants.py").write_text('''import os
|
||||
def with_hermes_node_path(env=None):
|
||||
return (os.environ if env is None else env).copy()
|
||||
''')
|
||||
|
||||
mock_bin = root / "bin"
|
||||
mock_bin.mkdir()
|
||||
unshare = mock_bin / "unshare"
|
||||
unshare.write_text('#!/bin/bash\nexit "${TEST_NAMESPACE_RESULT:-0}"\n')
|
||||
unshare.chmod(0o755)
|
||||
forbidden = '#!/bin/bash\ntouch "$TEST_FORBIDDEN"\nexit 99\n'
|
||||
cli = runtime / "venv/bin/hermes"
|
||||
cli.parent.mkdir(parents=True)
|
||||
cli.write_text(forbidden)
|
||||
cli.chmod(0o755)
|
||||
(cli.parent / "python").symlink_to(sys.executable)
|
||||
for command in ("sudo", "omarchy-install-hermes-cli"):
|
||||
target = mock_bin / command
|
||||
target.write_text(forbidden if command == "sudo" else '#!/bin/bash\nexit 0\n')
|
||||
target.chmod(0o755)
|
||||
|
||||
output = root / "launch.json"
|
||||
forbidden_output = root / "forbidden"
|
||||
env = {"HOME": str(home), "PATH": f"{mock_bin}:/usr/bin:/bin",
|
||||
"TEST_OUTPUT": str(output), "TEST_FORBIDDEN": str(forbidden_output)}
|
||||
launch = ["bash", str(launcher.resolve())]
|
||||
|
||||
def check_launch(args=(), overrides=None, expected_args=(), store="gnome-libsecret", gpu=None, ozone=None):
|
||||
subprocess.run(launch + list(args), env={**env, **(overrides or {})}, cwd=home, check=True)
|
||||
result = json.loads(output.read_text())
|
||||
assert result == {"args": ["--disable-setuid-sandbox", *expected_args],
|
||||
"home": str(home / ".hermes"), "store": store, "gpu": gpu,
|
||||
"ozone": ozone, "cwd": str(home), "inherited": []}, result
|
||||
assert not forbidden_output.exists(), "launcher invoked CLI or sudo"
|
||||
output.unlink()
|
||||
|
||||
wayland = {"WAYLAND_DISPLAY": "wayland-1"}
|
||||
check_launch(overrides=wayland, expected_args=["--ozone-platform=wayland"])
|
||||
url = "hermes://open?text=a%20b"
|
||||
check_launch(["--ozone-platform=x11", url], {**wayland, "HERMES_DESKTOP_PASSWORD_STORE": "kwallet6"},
|
||||
["--ozone-platform=x11", url], store="kwallet6")
|
||||
check_launch(overrides={"HERMES_HOME": str(home / ".hermes/profiles/work"),
|
||||
"HERMES_DESKTOP_DISABLE_GPU": "1"}, gpu="1")
|
||||
check_launch(overrides={"ELECTRON_RUN_AS_NODE": "1", "PYTHONPATH": "/invalid", "PYTHONHOME": "/invalid"})
|
||||
|
||||
config = home / ".hermes/config.yaml"
|
||||
config.write_text(json.dumps({"desktop": {"disable_gpu": True, "password_store": "kwallet5",
|
||||
"ozone_platform_hint": "x11",
|
||||
"electron_flags": '--force-device-scale-factor=1.5 "--test=a b"'}}))
|
||||
config_flags = ["--force-device-scale-factor=1.5", "--test=a b"]
|
||||
for args in ([], [url]):
|
||||
check_launch(args, wayland, config_flags + args, store="kwallet5", gpu="1", ozone="x11")
|
||||
check_launch(overrides={**wayland, "HERMES_DESKTOP_DISABLE_GPU": "0",
|
||||
"HERMES_DESKTOP_PASSWORD_STORE": "basic", "ELECTRON_OZONE_PLATFORM_HINT": "wayland"},
|
||||
expected_args=config_flags, store="basic", gpu="0", ozone="wayland")
|
||||
config.write_text(json.dumps({"desktop": {"electron_flags": ["--ozone-platform=x11"], "disable_gpu": False}}))
|
||||
check_launch(overrides=wayland, expected_args=["--ozone-platform=x11"], gpu="0")
|
||||
# New upstream revisions expose the same helper from main_desktop instead.
|
||||
(module / "main_desktop.py").write_text(helper)
|
||||
(module / "main.py").write_text('raise AssertionError("old helper import after update")\n')
|
||||
check_launch([url], wayland, ["--ozone-platform=x11", url], gpu="0")
|
||||
config.unlink()
|
||||
(module / "main_desktop.py").write_text(helper + '\nimport os\nos.environ.update(' + repr({
|
||||
"ELECTRON_RUN_AS_NODE": "1", "PYTHONPATH": "/invalid", "PYTHONHOME": "/invalid",
|
||||
"HERMES_HOME": "/invalid", "HERMES_DESKTOP_DISABLE_GPU": "1",
|
||||
"HERMES_DESKTOP_PASSWORD_STORE": "basic", "ELECTRON_OZONE_PLATFORM_HINT": "x11",
|
||||
}) + ')\n')
|
||||
check_launch(overrides={**wayland, "HERMES_DESKTOP_DISABLE_GPU": "0"},
|
||||
expected_args=["--ozone-platform=wayland"], gpu="0")
|
||||
(module / "main_desktop.py").write_text(helper)
|
||||
|
||||
def check_namespace_failure():
|
||||
for code in ("1", "127"):
|
||||
for args in ([], [url]):
|
||||
result = subprocess.run(launch + args, env={**env, "TEST_NAMESPACE_RESULT": code},
|
||||
capture_output=True, text=True)
|
||||
assert result.returncode != 0 and "user namespaces" in result.stderr, result
|
||||
assert not output.exists() and not forbidden_output.exists()
|
||||
|
||||
check_namespace_failure()
|
||||
# Exercise the real fallback branch with only its absolute app path redirected.
|
||||
fallback = root / "packaged-Hermes"
|
||||
shutil.copyfile(executable, fallback)
|
||||
fallback.chmod(0o755)
|
||||
fallback_launcher = root / "fallback-launcher"
|
||||
fallback_launcher.write_text(launcher.read_text().replace("/opt/hermes-desktop/Hermes", str(fallback)))
|
||||
launch = ["bash", str(fallback_launcher)]
|
||||
executable.unlink()
|
||||
check_launch([url], wayland, ["--ozone-platform=wayland", url])
|
||||
(module / "main_desktop.py").write_text('raise ImportError("incomplete Python dependencies")\n')
|
||||
check_launch([url], wayland, ["--ozone-platform=wayland", url])
|
||||
shutil.rmtree(runtime / "venv")
|
||||
check_launch(overrides={"ELECTRON_RUN_AS_NODE": "1", "PYTHONPATH": "/invalid", "PYTHONHOME": "/invalid"})
|
||||
check_namespace_failure()
|
||||
|
||||
gate = ["bash", str(destination), "--self-test-gate", "--install-root", str(runtime),
|
||||
"--relaunch-target", str(executable)]
|
||||
executable.touch()
|
||||
executable.chmod(0o755)
|
||||
assert subprocess.check_output(gate, env=env, text=True).strip() == "relaunch"
|
||||
assert subprocess.check_output(gate, env={**env, "TEST_NAMESPACE_RESULT": "1"}, text=True).startswith("manual:")
|
||||
gate[-1] = "/opt/hermes-desktop/Hermes"
|
||||
assert subprocess.check_output(gate, env=env, text=True).startswith("skew:")
|
||||
print("PASS: desktop settings, environment, native/fallback namespace sandbox and updater gate")
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/scripts/desktop-update/posix.sh
|
||||
+++ b/scripts/desktop-update/posix.sh
|
||||
@@ -317,6 +317,8 @@
|
||||
if [ ! -e "$sb" ]; then GATE=relaunch; return; fi
|
||||
if [ -u "$sb" ] && [ "$(stat -c %u "$sb" 2>/dev/null)" = "0" ]; then GATE=relaunch; return; fi
|
||||
|
||||
+ if unshare --user --map-root-user true 2>/dev/null; then GATE=relaunch; return; fi
|
||||
+
|
||||
case "${ELECTRON_DISABLE_SANDBOX:-}" in 1|true|TRUE|True) GATE=relaunch; return ;; esac
|
||||
[ "$SANDBOX_FALLBACK" -eq 1 ] && { GATE=relaunch; return; }
|
||||
for arg in ${RELAUNCH_ARGS[@]+"${RELAUNCH_ARGS[@]}"}; do
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/hyprwm/hyprland-guiutils.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": [
|
||||
"https://github.com/hyprwm/hyprland-guiutils/archive/v{pkgver}/hyprland-guiutils-{pkgver}.tar.gz"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rebuild_on": [
|
||||
"aquamarine"
|
||||
],
|
||||
"rebuilt_against": {
|
||||
"aarch64": {
|
||||
"aquamarine": "0.15.0-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Maintainer: Caleb Maclennan <caleb@alerque.com>
|
||||
|
||||
pkgname=hyprland-guiutils
|
||||
pkgver=0.2.2
|
||||
pkgrel=3
|
||||
pkgdesc='Hyprland GUI utilities'
|
||||
arch=(aarch64)
|
||||
url="https://github.com/hyprwm/$pkgname"
|
||||
license=(BSD-3-Clause)
|
||||
depends=(
|
||||
libgcc
|
||||
libstdc++
|
||||
glibc # libc.so libm.so
|
||||
hyprlang
|
||||
hyprtoolkit libhyprtoolkit.so
|
||||
hyprutils libhyprutils.so
|
||||
libdrm
|
||||
pixman
|
||||
)
|
||||
makedepends=(cmake)
|
||||
replaces=(hyprland-qtutils)
|
||||
_archive="$pkgname-$pkgver"
|
||||
source=("$url/archive/v$pkgver/$_archive.tar.gz")
|
||||
sha256sums=('16f92a6c5a22ac58e1fc313f6b202c188da45e804e1f21ff57dfd0da5c1a01b7')
|
||||
|
||||
build() {
|
||||
cd "$_archive"
|
||||
local cmake_flags=(
|
||||
-D CMAKE_BUILD_TYPE=Release
|
||||
-D CMAKE_INSTALL_PREFIX=/usr
|
||||
)
|
||||
cmake -B build ${cmake_flags[@]}
|
||||
cmake --build build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$_archive"
|
||||
DESTDIR="$pkgdir" cmake --install build
|
||||
install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname" LICENSE
|
||||
}
|
||||
@@ -4,7 +4,7 @@ pkgname="hyprland-preview-share-picker"
|
||||
pkgver=0.2.1
|
||||
pkgrel=1
|
||||
pkgdesc="An alternative share picker for hyprland with window and monitor previews"
|
||||
arch=(x86_64)
|
||||
arch=(x86_64 aarch64)
|
||||
url="https://github.com/WhySoBad/hyprland-preview-share-picker"
|
||||
license=(MIT)
|
||||
depends=('gtk4' 'gtk4-layer-shell' 'xdg-desktop-portal-hyprland' 'hyprland')
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/hyprwm/Hyprland.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": [
|
||||
"https://github.com/hyprwm/Hyprland/releases/download/v{pkgver}/source-v{pkgver}.tar.gz"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rebuild_on": [
|
||||
"aquamarine"
|
||||
],
|
||||
"rebuilt_against": {
|
||||
"aarch64": {
|
||||
"aquamarine": "0.15.0-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
# Maintainer: Caleb Maclennan <caleb@alerque.com>
|
||||
# Contributor: ThatOneCalculator <kainoa@t1c.dev>
|
||||
# Contributor: Brenno Lemos <brenno@syndel.is>
|
||||
# Contributor: Gabriel Fox <inbox@gabrielfox.dev>
|
||||
|
||||
pkgname=(hyprland hyprpm)
|
||||
pkgver=0.56.2
|
||||
pkgrel=3
|
||||
pkgdesc='a highly customizable dynamic tiling Wayland compositor'
|
||||
arch=(aarch64)
|
||||
url="https://github.com/hyprwm/${pkgname^}"
|
||||
license=(BSD-3-Clause)
|
||||
depends=(cairo # libcairo.so
|
||||
aquamarine libaquamarine.so
|
||||
libgcc # libgcc_s.so
|
||||
'libstdc++' # libstdc++.so
|
||||
glibc # libc.so libm.so
|
||||
glib2 libgio-2.0.so libgobject-2.0.so
|
||||
glslang # libglslang-default-resource-limits.so libglslang.so
|
||||
hyprcursor libhyprcursor.so
|
||||
hyprgraphics libhyprgraphics.so
|
||||
hyprland-guiutils
|
||||
hyprlang libhyprlang.so
|
||||
hyprutils libhyprutils.so
|
||||
hyprwire libhyprwire.so
|
||||
lcms2 liblcms2.so
|
||||
libdrm # libdrm.so
|
||||
libglvnd libEGL.so libGLESv2.so
|
||||
libinput # libinput.so
|
||||
libx11
|
||||
libxcb # libxcb-dri3.so libxcb-present.so libxcb-render.so libxcb-res.so libxcb-shm.so libxcb.so libxcb-xfixes.so libxcb-xinput.so
|
||||
libxcomposite # libxcb-composite.so
|
||||
libxcursor # libXcursor.so
|
||||
libxfixes
|
||||
libxkbcommon libxkbcommon.so
|
||||
libxrender
|
||||
lua # liblua.so
|
||||
mesa # libgbm.so
|
||||
muparser # libmuparser.so
|
||||
opengl-driver
|
||||
pango libpango-1.0.so libpangocairo-1.0.so
|
||||
pixman libpixman-1.so
|
||||
re2 libre2.so
|
||||
tomlplusplus libtomlplusplus.so
|
||||
util-linux-libs libuuid.so
|
||||
wayland libwayland-server.so
|
||||
wayland-protocols
|
||||
xcb-proto
|
||||
xcb-util
|
||||
xcb-util-errors # libxcb-errors.so
|
||||
xcb-util-image
|
||||
xcb-util-keysyms
|
||||
xcb-util-renderutil # libxcb-render-util.so
|
||||
xcb-util-wm # libxcb-ewmh.so libxcb-icccm.so
|
||||
xorg-xwayland)
|
||||
makedepends=(cmake
|
||||
glaze
|
||||
hyprland-protocols
|
||||
hyprwayland-scanner
|
||||
meson
|
||||
ninja
|
||||
xorgproto)
|
||||
optdepends=('hyprpm: build and install plugins'
|
||||
'hyprshutdown: clean logout and shutdown helper'
|
||||
'xdg-desktop-portal-hyprland: xdg-desktop-portal backend for hyprland')
|
||||
provides=(wayland-compositor)
|
||||
_archive="${pkgname^}-$pkgver"
|
||||
source=("$_archive.tar.gz::$url/releases/download/v$pkgver/source-v$pkgver.tar.gz")
|
||||
sha256sums=('03ad3f5ef152ff44116ffd56fcf808486211ecabf4f0ba567108ee746ba5cd2e')
|
||||
|
||||
prepare() {
|
||||
ln -sf hyprland-source "$_archive"
|
||||
cd "$_archive"
|
||||
sed -i -e '/^release:/{n;s/-D/-DCMAKE_SKIP_RPATH=ON -D/}' Makefile
|
||||
sed -i -e '/find_package.glaze/s/7...<8 //' {.,hyprpm,start}/CMakeLists.txt
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$_archive"
|
||||
make release PREFIX=/usr
|
||||
}
|
||||
|
||||
package_hyprland() {
|
||||
cd "$_archive"
|
||||
make DESTDIR="$pkgdir" install
|
||||
rm -fv "$pkgdir/usr/include/hyprland/src/version.h.in"
|
||||
find $pkgdir -name '*hyprpm*' -delete
|
||||
install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname/" LICENSE
|
||||
}
|
||||
|
||||
package_hyprpm() {
|
||||
pkgdesc='Plugin manager for Hyprland'
|
||||
depends=(cmake
|
||||
cpio
|
||||
glaze
|
||||
hyprland
|
||||
hyprland-protocols
|
||||
hyprwayland-scanner
|
||||
meson)
|
||||
cd "$_archive"
|
||||
make DESTDIR="$pkgdir" install
|
||||
find $pkgdir -type f,l -not -name '*hyprpm*' -delete
|
||||
find $pkgdir -type d -empty -delete
|
||||
install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname/" LICENSE
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/hyprwm/hyprtoolkit.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": [
|
||||
"https://github.com/hyprwm/hyprtoolkit/archive/v{pkgver}/hyprtoolkit-{pkgver}.tar.gz"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rebuild_on": [
|
||||
"aquamarine"
|
||||
],
|
||||
"rebuilt_against": {
|
||||
"aarch64": {
|
||||
"aquamarine": "0.15.0-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
# Maintainer: Caleb Maclennan <caleb@alerque.com>
|
||||
|
||||
pkgname=hyprtoolkit
|
||||
pkgver=0.5.4
|
||||
pkgrel=5.1
|
||||
pkgdesc='A modern C++ Wayland-native GUI toolkit'
|
||||
arch=(aarch64)
|
||||
url="https://github.com/hyprwm/$pkgname"
|
||||
license=(BSD-3-Clause)
|
||||
depends=(
|
||||
libgcc
|
||||
libstdc++
|
||||
aquamarine libaquamarine.so
|
||||
cairo libcairo.so
|
||||
glib2 libglib-2.0.so
|
||||
glibc # libc.so libm.so
|
||||
hyprgraphics libhyprgraphics.so
|
||||
hyprlang libhyprlang.so
|
||||
hyprutils libhyprutils.so
|
||||
iniparser libiniparser.so
|
||||
libdrm # libdrm.so
|
||||
libglvnd libEGL.so libOpenGL.so
|
||||
libxkbcommon libxkbcommon.so
|
||||
mesa # libgbm.so
|
||||
pango libpango-1.0.so # libpango.so
|
||||
pixman libpixman-1.so
|
||||
wayland libwayland-client.so
|
||||
)
|
||||
makedepends=(cmake
|
||||
hyprwayland-scanner)
|
||||
provides=(libhyprtoolkit.so)
|
||||
_archive="$pkgname-$pkgver"
|
||||
source=("$url/archive/v$pkgver/$_archive.tar.gz")
|
||||
sha256sums=('2fb59789f231c1c4e9154ceffc1e7524c0cae154807c0d57e6166806255b570f')
|
||||
|
||||
build() {
|
||||
cd "$_archive"
|
||||
local cmake_options=(
|
||||
-D CMAKE_BUILD_TYPE=None
|
||||
-D CMAKE_INSTALL_PREFIX=/usr
|
||||
)
|
||||
cmake -B build -W no-dev ${cmake_options[@]}
|
||||
cmake --build build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$_archive"
|
||||
DESTDIR="$pkgdir" cmake --install build
|
||||
install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname/" LICENSE
|
||||
}
|
||||
@@ -1,22 +1,18 @@
|
||||
# Maintainer: Mikko Nyman <mikko@nyman.xyz>
|
||||
# Based on the Arch libfprint package by Jan Alexander Steffens (heftig).
|
||||
#
|
||||
# Carried the focaltech_moc driver and the FocalTech FT9349 device ID
|
||||
# (USB 2808:a97a, ASUS ExpertBook Ultra B9406CAA) while mainline libfprint
|
||||
# releases (1.94.x) lacked them. libfprint 1.94.100 ships both, so Omarchy
|
||||
# has moved back to stock libfprint and no longer installs this package.
|
||||
#
|
||||
# Kept around pinned to the last known good commit as an escape hatch;
|
||||
# the fallback patch stays for the conditional in prepare().
|
||||
# Omarchy's fingerprint setup installs this in place of stock libfprint, so
|
||||
# readers upstream supports ahead of an Arch release reach users by bumping
|
||||
# the pin here. Pinned to the commit adding the Synaptics reader USB
|
||||
# 06cb:010b, missing from stock libfprint 1.94.100; the FocalTech MOC support
|
||||
# carried by the previous pin is retained.
|
||||
|
||||
pkgname=libfprint-git
|
||||
pkgver=1.94.10.r12.gd79f157
|
||||
pkgrel=1.1
|
||||
# The repo already carries an untested 1.94.10.r220.g695663f build that sorts
|
||||
# above the pinned pkgver; the epoch makes the pinned build win the version
|
||||
# comparison and gives it a fresh filename that can be promoted.
|
||||
pkgver=1.94.100.r10.g6f9479c
|
||||
pkgrel=1
|
||||
# Retain the epoch used to supersede the previously published untested build.
|
||||
epoch=1
|
||||
pkgdesc="Library for fingerprint readers (libfprint master with FocalTech MOC updates)"
|
||||
pkgdesc="Library for fingerprint readers (pinned upstream snapshot with FocalTech and Synaptics 06cb:010b support)"
|
||||
url="https://fprint.freedesktop.org/"
|
||||
arch=(x86_64)
|
||||
license=(LGPL-2.1-or-later)
|
||||
@@ -47,7 +43,7 @@ provides=(libfprint libfprint-2.so)
|
||||
conflicts=(libfprint)
|
||||
groups=(fprint)
|
||||
source=(
|
||||
"git+https://gitlab.freedesktop.org/libfprint/libfprint.git#commit=d79f157282085738ea8ffbe8c2ae96fb8b3ad831"
|
||||
"git+https://gitlab.freedesktop.org/libfprint/libfprint.git#commit=6f9479c3d55f847c1b3769f28ceb99227f9858cf"
|
||||
"focaltech_moc-add-pid-0xA97A.patch"
|
||||
)
|
||||
b2sums=(
|
||||
@@ -79,9 +75,6 @@ build() {
|
||||
)
|
||||
arch-meson libfprint build "${meson_options[@]}"
|
||||
meson compile -C build
|
||||
# Regenerate autosuspend.hwdb from the patched id_table[] so the
|
||||
# udev-hwdb test in check() doesn't fail on the new PID 0xA97A.
|
||||
ninja -C build sync-udev-hwdb
|
||||
}
|
||||
|
||||
check() {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
--- a/PKGBUILD
|
||||
+++ b/PKGBUILD
|
||||
@@ -3,6 +3,7 @@
|
||||
pkgname="limine-mkinitcpio-hook"
|
||||
_pkgver=1.38.0
|
||||
_extver=""
|
||||
+_gradle_version=9.7.1
|
||||
pkgver="${_pkgver}${_extver}"
|
||||
pkgrel=1
|
||||
pkgdesc="Install kernels for the Limine bootloader."
|
||||
@@ -10,7 +11,8 @@
|
||||
url="https://gitlab.com/Zesko/limine-entry-tool"
|
||||
source=("${_pkgname}::git+${url}.git#tag=${pkgver}")
|
||||
source_x86_64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/graal-25.2.4/graalvm-community-jdk-25i2-25.0.4_linux-x64_bin.tar.gz")
|
||||
-source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/graal-25.2.4/graalvm-community-jdk-25i2-25.0.4_linux-aarch64_bin.tar.gz")
|
||||
+source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/graal-25.2.4/graalvm-community-jdk-25i2-25.0.4_linux-aarch64_bin.tar.gz"
|
||||
+ "https://services.gradle.org/distributions/gradle-${_gradle_version}-bin.zip")
|
||||
license=("GPL3")
|
||||
provides=('limine-entry-tool')
|
||||
options=(!debug !strip)
|
||||
@@ -27,12 +29,14 @@
|
||||
'sbctl: Signs UEFI boot files for Secure Boot when enabled'
|
||||
'journalctl-desktop-notification: Sends desktop notifications when errors occur'
|
||||
)
|
||||
-makedepends=('git' 'gradle')
|
||||
+makedepends=('git')
|
||||
+makedepends_x86_64=('gradle')
|
||||
backup=(etc/limine-entry-tool.conf)
|
||||
conflicts=('limine-entry-tool')
|
||||
sha256sums=('11dd8211898585f79d8361d97606965bb2ca214dccace5b133dc5121e4bb4d01')
|
||||
sha256sums_x86_64=('3f4a89de8eaa96f2ed677f09957c7e872cd8467aad3537f8b5394c1b8c4b942e')
|
||||
-sha256sums_aarch64=('22286f7ecd21b9aedb3226b9bf797469e1bd3eefc491e12ef3dd49b452d230b7')
|
||||
+sha256sums_aarch64=('22286f7ecd21b9aedb3226b9bf797469e1bd3eefc491e12ef3dd49b452d230b7'
|
||||
+ 'acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a')
|
||||
|
||||
prepare() {
|
||||
[[ -d "${_graalvm_version}" ]] && rm -rf "${_graalvm_version}"
|
||||
@@ -48,7 +52,9 @@
|
||||
export GRAALVM_HOME="$srcdir/${_graalvm_version}"
|
||||
export JAVA_HOME="${GRAALVM_HOME}"
|
||||
export NATIVE_IMAGE_OPTIONS="-march=compatibility --future-defaults=all"
|
||||
- /usr/bin/gradle clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
+ local gradle=/usr/bin/gradle
|
||||
+ [[ $CARCH == aarch64 ]] && gradle="$srcdir/gradle-${_gradle_version}/bin/gradle"
|
||||
+ "$gradle" clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
}
|
||||
|
||||
package() {
|
||||
@@ -3,14 +3,16 @@ _pkgname="limine-entry-tool"
|
||||
pkgname="limine-mkinitcpio-hook"
|
||||
_pkgver=1.38.0
|
||||
_extver=""
|
||||
_gradle_version=9.7.1
|
||||
pkgver="${_pkgver}${_extver}"
|
||||
pkgrel=1
|
||||
pkgrel=1.1
|
||||
pkgdesc="Install kernels for the Limine bootloader."
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://gitlab.com/Zesko/limine-entry-tool"
|
||||
source=("${_pkgname}::git+${url}.git#tag=${pkgver}")
|
||||
source_x86_64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/graal-25.2.4/graalvm-community-jdk-25i2-25.0.4_linux-x64_bin.tar.gz")
|
||||
source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/graal-25.2.4/graalvm-community-jdk-25i2-25.0.4_linux-aarch64_bin.tar.gz")
|
||||
source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/graal-25.2.4/graalvm-community-jdk-25i2-25.0.4_linux-aarch64_bin.tar.gz"
|
||||
"https://services.gradle.org/distributions/gradle-${_gradle_version}-bin.zip")
|
||||
license=("GPL3")
|
||||
provides=('limine-entry-tool')
|
||||
options=(!debug !strip)
|
||||
@@ -27,12 +29,14 @@ optdepends=(
|
||||
'sbctl: Signs UEFI boot files for Secure Boot when enabled'
|
||||
'journalctl-desktop-notification: Sends desktop notifications when errors occur'
|
||||
)
|
||||
makedepends=('git' 'gradle')
|
||||
makedepends=('git')
|
||||
makedepends_x86_64=('gradle')
|
||||
backup=(etc/limine-entry-tool.conf)
|
||||
conflicts=('limine-entry-tool')
|
||||
sha256sums=('11dd8211898585f79d8361d97606965bb2ca214dccace5b133dc5121e4bb4d01')
|
||||
sha256sums_x86_64=('3f4a89de8eaa96f2ed677f09957c7e872cd8467aad3537f8b5394c1b8c4b942e')
|
||||
sha256sums_aarch64=('22286f7ecd21b9aedb3226b9bf797469e1bd3eefc491e12ef3dd49b452d230b7')
|
||||
sha256sums_aarch64=('22286f7ecd21b9aedb3226b9bf797469e1bd3eefc491e12ef3dd49b452d230b7'
|
||||
'acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a')
|
||||
|
||||
prepare() {
|
||||
[[ -d "${_graalvm_version}" ]] && rm -rf "${_graalvm_version}"
|
||||
@@ -48,7 +52,9 @@ build() {
|
||||
export GRAALVM_HOME="$srcdir/${_graalvm_version}"
|
||||
export JAVA_HOME="${GRAALVM_HOME}"
|
||||
export NATIVE_IMAGE_OPTIONS="-march=compatibility --future-defaults=all"
|
||||
/usr/bin/gradle clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
local gradle=/usr/bin/gradle
|
||||
[[ $CARCH == aarch64 ]] && gradle="$srcdir/gradle-${_gradle_version}/bin/gradle"
|
||||
"$gradle" clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
}
|
||||
|
||||
package() {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
--- a/PKGBUILD
|
||||
+++ b/PKGBUILD
|
||||
@@ -2,12 +2,14 @@
|
||||
pkgname="limine-snapper-sync"
|
||||
pkgver=1.31.0
|
||||
pkgrel=1
|
||||
+_gradle_version=9.7.1
|
||||
pkgdesc="Integrates Limine boot entries with Snapper snapshots."
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://gitlab.com/Zesko/limine-snapper-sync"
|
||||
source=("${pkgname}::git+${url}.git#tag=${pkgver}")
|
||||
source_x86_64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-25.0.2/graalvm-community-jdk-25.0.2_linux-x64_bin.tar.gz")
|
||||
-source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-25.0.2/graalvm-community-jdk-25.0.2_linux-aarch64_bin.tar.gz")
|
||||
+source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-25.0.2/graalvm-community-jdk-25.0.2_linux-aarch64_bin.tar.gz"
|
||||
+ "https://services.gradle.org/distributions/gradle-${_gradle_version}-bin.zip")
|
||||
license=("GPL3")
|
||||
options=(!debug !strip)
|
||||
_graalvm_version=graalvm_ce_jdk25
|
||||
@@ -25,12 +27,14 @@
|
||||
'b3sum: Fast Blake3 hash function to prevent duplication.'
|
||||
'xxhash: Fast hashing utility for deduplication with shorter hashes.'
|
||||
)
|
||||
-makedepends=('git' 'gradle')
|
||||
+makedepends=('git')
|
||||
+makedepends_x86_64=('gradle')
|
||||
backup=(etc/limine-snapper-sync.conf)
|
||||
conflicts=('limine-snapper-cli' 'limine-snapper-sync-git')
|
||||
sha256sums=('ed236f1bbab966950bf11ba5a7958e97a76e66db7fd647b7737bab4b48c9fc40')
|
||||
sha256sums_x86_64=('e0be791c8fda4d03b6b0a0cb824fef3149736170057b3a515252b44419606af0')
|
||||
-sha256sums_aarch64=('b4580d9f223d0a4b3a1757e58b18ff4c1db950e67e105fc5cb741457d2384a71')
|
||||
+sha256sums_aarch64=('b4580d9f223d0a4b3a1757e58b18ff4c1db950e67e105fc5cb741457d2384a71'
|
||||
+ 'acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a')
|
||||
|
||||
prepare() {
|
||||
[[ -d "${_graalvm_version}" ]] && rm -rf "${_graalvm_version}"
|
||||
@@ -46,7 +50,9 @@
|
||||
export GRAALVM_HOME="$srcdir/${_graalvm_version}"
|
||||
export JAVA_HOME="${GRAALVM_HOME}"
|
||||
export NATIVE_IMAGE_OPTIONS="-march=compatibility"
|
||||
- /usr/bin/gradle clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
+ local gradle=/usr/bin/gradle
|
||||
+ [[ $CARCH == aarch64 ]] && gradle="$srcdir/gradle-${_gradle_version}/bin/gradle"
|
||||
+ "$gradle" clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
}
|
||||
|
||||
package() {
|
||||
@@ -1,13 +1,15 @@
|
||||
# Maintainer: Zesko
|
||||
pkgname="limine-snapper-sync"
|
||||
pkgver=1.31.0
|
||||
pkgrel=1
|
||||
pkgrel=1.1
|
||||
_gradle_version=9.7.1
|
||||
pkgdesc="Integrates Limine boot entries with Snapper snapshots."
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://gitlab.com/Zesko/limine-snapper-sync"
|
||||
source=("${pkgname}::git+${url}.git#tag=${pkgver}")
|
||||
source_x86_64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-25.0.2/graalvm-community-jdk-25.0.2_linux-x64_bin.tar.gz")
|
||||
source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-25.0.2/graalvm-community-jdk-25.0.2_linux-aarch64_bin.tar.gz")
|
||||
source_aarch64=("https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-25.0.2/graalvm-community-jdk-25.0.2_linux-aarch64_bin.tar.gz"
|
||||
"https://services.gradle.org/distributions/gradle-${_gradle_version}-bin.zip")
|
||||
license=("GPL3")
|
||||
options=(!debug !strip)
|
||||
_graalvm_version=graalvm_ce_jdk25
|
||||
@@ -25,12 +27,14 @@ optdepends=(
|
||||
'b3sum: Fast Blake3 hash function to prevent duplication.'
|
||||
'xxhash: Fast hashing utility for deduplication with shorter hashes.'
|
||||
)
|
||||
makedepends=('git' 'gradle')
|
||||
makedepends=('git')
|
||||
makedepends_x86_64=('gradle')
|
||||
backup=(etc/limine-snapper-sync.conf)
|
||||
conflicts=('limine-snapper-cli' 'limine-snapper-sync-git')
|
||||
sha256sums=('ed236f1bbab966950bf11ba5a7958e97a76e66db7fd647b7737bab4b48c9fc40')
|
||||
sha256sums_x86_64=('e0be791c8fda4d03b6b0a0cb824fef3149736170057b3a515252b44419606af0')
|
||||
sha256sums_aarch64=('b4580d9f223d0a4b3a1757e58b18ff4c1db950e67e105fc5cb741457d2384a71')
|
||||
sha256sums_aarch64=('b4580d9f223d0a4b3a1757e58b18ff4c1db950e67e105fc5cb741457d2384a71'
|
||||
'acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a')
|
||||
|
||||
prepare() {
|
||||
[[ -d "${_graalvm_version}" ]] && rm -rf "${_graalvm_version}"
|
||||
@@ -46,7 +50,9 @@ build() {
|
||||
export GRAALVM_HOME="$srcdir/${_graalvm_version}"
|
||||
export JAVA_HOME="${GRAALVM_HOME}"
|
||||
export NATIVE_IMAGE_OPTIONS="-march=compatibility"
|
||||
/usr/bin/gradle clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
local gradle=/usr/bin/gradle
|
||||
[[ $CARCH == aarch64 ]] && gradle="$srcdir/gradle-${_gradle_version}/bin/gradle"
|
||||
"$gradle" clean nativeCompile -Dorg.gradle.java.home="${JAVA_HOME}"
|
||||
}
|
||||
|
||||
package() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Jake Weaver <jakeweaver at hey dot com>
|
||||
pkgname=link-studio
|
||||
pkgver=1.0.2
|
||||
pkgver=1.0.4
|
||||
pkgrel=1
|
||||
pkgdesc="Native Linux controller for Insta360 Link webcams"
|
||||
arch=('x86_64')
|
||||
@@ -28,7 +28,7 @@ optdepends=(
|
||||
'whisper-cpp: offline meeting transcription'
|
||||
)
|
||||
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/jweaver60/link-studio/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
||||
sha256sums=('b0fc912d8b7924661b57e427280c9766cbb0f01b7a2b3f3cdb1885969f8cfdc6')
|
||||
sha256sums=('f04156d34ecf5e858bd259dca824f970af53ff177185516fafff15766a0880e9')
|
||||
|
||||
build() {
|
||||
cd "link_studio-${pkgver}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Jeff Dickey <releases@mise.jdx.dev>
|
||||
pkgname=mise-bin
|
||||
pkgver=2026.8.15
|
||||
pkgver=2026.9.1
|
||||
pkgrel=1
|
||||
pkgdesc="dev tools, env vars, task runner"
|
||||
arch=('x86_64' 'aarch64')
|
||||
@@ -14,8 +14,8 @@ provides=('mise')
|
||||
conflicts=('mise')
|
||||
source_x86_64=("https://github.com/jdx/mise/releases/download/v${pkgver}/mise-v${pkgver}-linux-x64.tar.xz")
|
||||
source_aarch64=("https://github.com/jdx/mise/releases/download/v${pkgver}/mise-v${pkgver}-linux-arm64.tar.xz")
|
||||
sha256sums_x86_64=('0ed4ee8bcf229718bead0d0aa83de865803f3fe25cc6c71a41e3a8bd57c40a33')
|
||||
sha256sums_aarch64=('d5f9b7e6b36b5cf5aaab0dc4d7e29ee74224281b1a81a228bdc1cd1f3edf9d49')
|
||||
sha256sums_x86_64=('bbc21f8fe9b2aa09f74250be15f9bf32e87562e1039d858ad91d7944f057c8e2')
|
||||
sha256sums_aarch64=('7d0c28d44bd7e1c5444a7d867146afabe43592c728329bc0ed5ec59ca7106c48')
|
||||
|
||||
package() {
|
||||
install -Dm755 "${srcdir}/mise/bin/mise" "${pkgdir}/usr/bin/mise"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"upstream": {
|
||||
"github": "tsouth89/omakade",
|
||||
"github": "btsouth/omakade",
|
||||
"checksums": "SHA256SUMS",
|
||||
"assets": {
|
||||
"any": "omakade-{pkgver}.tar.gz"
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
pkgname=omakade
|
||||
pkgver=1.2.3
|
||||
pkgver=1.7.0
|
||||
pkgrel=1
|
||||
pkgdesc='A beautiful, local-first game library for Omarchy'
|
||||
arch=('x86_64')
|
||||
url='https://tsouth89.github.io/omakade/'
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://btsouth.github.io/omakade/'
|
||||
license=('GPL-3.0-or-later')
|
||||
depends=('glib2' 'libsecret' 'qt6-base' 'qt6-declarative' 'qt6-wayland' 'sdl3')
|
||||
makedepends=('cmake' 'ninja' 'pkgconf')
|
||||
depends=('glib2' 'hicolor-icon-theme' 'libsecret' 'libzip' 'openssl' 'qt6-base' 'qt6-declarative' 'qt6-imageformats' 'qt6-svg' 'qt6-wayland' 'sdl3' 'wayland' 'zstd')
|
||||
# wayland-protocols turns the optional idle-inhibit feature on
|
||||
# deterministically instead of leaving it to what the chroot happens to carry.
|
||||
makedepends=('cmake' 'ninja' 'pkgconf' 'wayland-protocols')
|
||||
options=('!debug')
|
||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/tsouth89/omakade/releases/download/v$pkgver/$pkgname-$pkgver.tar.gz")
|
||||
sha256sums=('dcbb57caf982317ae0fd75a1a97c48b80d2b02f92d65b38030876a172eb25606')
|
||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/btsouth/omakade/releases/download/v$pkgver/$pkgname-$pkgver.tar.gz")
|
||||
sha256sums=('715cd5e0cb860514276b1af57fe08ced71c1c69a6aeebd93aa51f1ca367eefa8')
|
||||
|
||||
build() {
|
||||
cmake -S "$pkgname-$pkgver" -B build -G Ninja \
|
||||
|
||||
@@ -5,7 +5,10 @@ pkgrel=1
|
||||
_pkgver_base=4.0.0
|
||||
_pkgver_base_tag=v3.8.2
|
||||
pkgdesc='Beautiful, modern, and opinionated Arch Linux by DHH (quattro branch tip)'
|
||||
arch=('any')
|
||||
# The payload is architecture-independent, but the dependency set is not: the
|
||||
# boot stack differs per architecture (see depends_x86_64 / depends_aarch64),
|
||||
# and makepkg only honours arch-suffixed arrays on arch-specific packages.
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://github.com/basecamp/omarchy'
|
||||
license=('MIT')
|
||||
provides=('omarchy')
|
||||
@@ -17,18 +20,6 @@ depends=(
|
||||
'omarchy-keyring'
|
||||
'omarchy-settings-dev'
|
||||
|
||||
# Bootloader stack. Lives here rather than on omarchy-settings because
|
||||
# omarchy-settings is also installed into the live ISO env (for plymouth
|
||||
# / /etc/skel seeding), where the limine-mkinitcpio-hook would fail with
|
||||
# 'Cannot detect an ESP path' inside the chroot. The omarchy-settings
|
||||
# config drop-ins under /etc/mkinitcpio.conf.d/, /etc/limine-entry-tool.d/,
|
||||
# and /etc/snapper/config-templates/ only do anything when these are
|
||||
# installed alongside.
|
||||
'limine'
|
||||
'limine-mkinitcpio-hook'
|
||||
'limine-snapper-sync'
|
||||
'snapper'
|
||||
|
||||
# Wayland / Hyprland core
|
||||
'hyprland'
|
||||
'quickshell'
|
||||
@@ -55,6 +46,29 @@ depends=(
|
||||
'ttf-jetbrains-mono-nerd-basic'
|
||||
)
|
||||
|
||||
# Bootloader stack. Lives here rather than on omarchy-settings because
|
||||
# omarchy-settings is also installed into the live ISO env (for plymouth
|
||||
# / /etc/skel seeding), where the limine-mkinitcpio-hook would fail with
|
||||
# 'Cannot detect an ESP path' inside the chroot. The omarchy-settings
|
||||
# config drop-ins under /etc/mkinitcpio.conf.d/, /etc/limine-entry-tool.d/,
|
||||
# and /etc/snapper/config-templates/ only do anything when these are
|
||||
# installed alongside.
|
||||
depends_x86_64=(
|
||||
'limine'
|
||||
'limine-mkinitcpio-hook'
|
||||
'limine-snapper-sync'
|
||||
'snapper'
|
||||
)
|
||||
|
||||
# Apple Silicon boots through m1n1 + GRUB from the Asahi packages and keeps
|
||||
# Arch Linux ARM's kernel and boot layout, so the Limine/Snapper stack does not
|
||||
# apply. Wi-Fi on the Broadcom parts only scans reliably through the iwd
|
||||
# backend, which install/hardware/network.sh selects on Apple Silicon.
|
||||
depends_aarch64=(
|
||||
'iwd'
|
||||
'networkmanager'
|
||||
)
|
||||
|
||||
makedepends=(
|
||||
'git'
|
||||
)
|
||||
|
||||
@@ -5,7 +5,12 @@ pkgrel=1
|
||||
_pkgver_base=4.0.0
|
||||
_pkgver_base_tag=v3.8.2
|
||||
pkgdesc='Omarchy user defaults, /etc/skel content, fonts, plymouth theme, and support helpers (quattro branch tip)'
|
||||
arch=('any')
|
||||
# Arch-specific because the shipped /etc tree is not the same on every
|
||||
# architecture: the Limine, mkinitcpio, zram and oomd drop-ins belong to the
|
||||
# x86_64 boot and memory stack and are left out of the aarch64 package (see
|
||||
# package()). makepkg only honours the arch-suffixed arrays below on
|
||||
# arch-specific packages.
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://github.com/basecamp/omarchy'
|
||||
license=('MIT')
|
||||
provides=('omarchy-settings')
|
||||
@@ -44,15 +49,10 @@ makedepends=(
|
||||
# scriptlet WILL clobber user edits on each upgrade (documented limitation).
|
||||
backup=(
|
||||
'etc/fastfetch/config.jsonc'
|
||||
'etc/mkinitcpio.conf.d/omarchy_hooks.conf'
|
||||
'etc/mkinitcpio.conf.d/thunderbolt_module.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-defaults.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-uki.conf'
|
||||
'etc/docker/daemon.json'
|
||||
'etc/gnupg/dirmngr.conf'
|
||||
'etc/sysctl.d/99-omarchy-sysctl.conf'
|
||||
'etc/sysctl.d/90-omarchy-file-watchers.conf'
|
||||
'etc/modprobe.d/omarchy-usb-autosuspend.conf'
|
||||
'etc/systemd/logind.conf.d/10-ignore-power-button.conf'
|
||||
'etc/systemd/logind.conf.d/20-inhibit-delay.conf'
|
||||
'etc/systemd/resolved.conf.d/10-disable-multicast.conf'
|
||||
@@ -63,18 +63,31 @@ backup=(
|
||||
'etc/systemd/system/plocate-updatedb.service.d/ac-only.conf'
|
||||
'etc/systemd/system.conf.d/20-omarchy-nofile.conf'
|
||||
'etc/systemd/user.conf.d/20-omarchy-nofile.conf'
|
||||
'etc/systemd/oomd.conf.d/10-omarchy.conf'
|
||||
'etc/systemd/zram-generator.conf'
|
||||
'etc/sddm.conf.d/10-theme.conf'
|
||||
'etc/sddm.conf.d/10-wayland.conf'
|
||||
'etc/udev/rules.d/99-omarchy-power-profile.rules'
|
||||
'etc/udev/rules.d/99-omarchy-wifi-powersave.rules'
|
||||
)
|
||||
# backup has no arch-suffixed form, so the x86_64-only drop-ins join it here.
|
||||
# Each of these paths is removed from the aarch64 package in package().
|
||||
if [[ $CARCH == x86_64 ]]; then
|
||||
backup+=(
|
||||
'etc/mkinitcpio.conf.d/omarchy_hooks.conf'
|
||||
'etc/mkinitcpio.conf.d/thunderbolt_module.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-defaults.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-uki.conf'
|
||||
'etc/modprobe.d/omarchy-usb-autosuspend.conf'
|
||||
'etc/systemd/oomd.conf.d/10-omarchy.conf'
|
||||
'etc/systemd/zram-generator.conf'
|
||||
)
|
||||
fi
|
||||
|
||||
optdepends=(
|
||||
'omarchy-dev: Full Omarchy desktop (quattro branch tip)'
|
||||
'inxi: System information for omarchy-debug'
|
||||
'fastfetch: System information for omarchy-upload-log'
|
||||
)
|
||||
optdepends_x86_64=(
|
||||
'limine: Bootloader the shipped /etc/mkinitcpio.conf.d/ and /etc/limine-entry-tool.d/ drop-ins are for'
|
||||
'limine-mkinitcpio-hook: Picks up the shipped /etc/mkinitcpio.conf.d/omarchy_hooks.conf'
|
||||
'limine-snapper-sync: Boot-entry sync for snapper snapshots'
|
||||
@@ -147,6 +160,14 @@ package() {
|
||||
install -d "$pkgdir/usr/share/omarchy/config"
|
||||
cp -a config/. "$pkgdir/usr/share/omarchy/config/"
|
||||
|
||||
# The Limine/Snapper notifier has nothing to notify about without the x86_64
|
||||
# boot stack; drop it from both seeds so aarch64 users don't autostart a
|
||||
# helper whose backing tool is not installed.
|
||||
if [[ $CARCH == aarch64 ]]; then
|
||||
rm -f "$pkgdir/etc/skel/.config/autostart/limine-snapper-notify.desktop" \
|
||||
"$pkgdir/usr/share/omarchy/config/autostart/limine-snapper-notify.desktop"
|
||||
fi
|
||||
|
||||
# Package-owned defaults with real system/XDG locations. User config remains
|
||||
# higher priority: ~/.config/uwsm/default, ~/.config/uwsm/env.d,
|
||||
# ~/.config/environment.d, ~/.config/fontconfig, ~/.config/xdg-terminals.list,
|
||||
@@ -174,9 +195,14 @@ package() {
|
||||
install -Dm644 default/systemd/user/omarchy-crash-watch.service "$pkgdir/usr/lib/systemd/user/omarchy-crash-watch.service"
|
||||
# Marks app.slice (and only app.slice) as a systemd-oomd kill candidate, so
|
||||
# memory pressure costs one app scope instead of the compositor session.
|
||||
# Thresholds live in etc/systemd/oomd.conf.d/10-omarchy.conf.
|
||||
install -Dm644 default/systemd/user/app.slice.d/10-oomd.conf "$pkgdir/usr/lib/systemd/user/app.slice.d/10-oomd.conf"
|
||||
install -Dm644 default/systemd/zram-generator.conf.d/90-omarchy.conf "$pkgdir/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf"
|
||||
# Thresholds live in etc/systemd/oomd.conf.d/10-omarchy.conf. Both this and
|
||||
# the zram vendor drop-in belong to the x86_64 memory stack: the aarch64
|
||||
# install neither enables systemd-oomd nor configures zram swap.
|
||||
if [[ $CARCH == x86_64 ]]; then
|
||||
install -Dm644 default/systemd/user/app.slice.d/10-oomd.conf "$pkgdir/usr/lib/systemd/user/app.slice.d/10-oomd.conf"
|
||||
install -Dm644 default/systemd/zram-generator.conf.d/90-omarchy.conf "$pkgdir/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf"
|
||||
fi
|
||||
install -Dm644 default/systemd/system/plocate-updatedb.service.d/10-omarchy.conf "$pkgdir/usr/lib/systemd/system/plocate-updatedb.service.d/10-omarchy.conf"
|
||||
|
||||
# Same for applications/** — used by omarchy-refresh-applications,
|
||||
# omarchy-install-gaming-*, etc. to copy .desktop files into ~/.local/share.
|
||||
@@ -190,6 +216,25 @@ package() {
|
||||
# stage separately below).
|
||||
install -d "$pkgdir/etc"
|
||||
cp -a etc/. "$pkgdir/etc/"
|
||||
if [[ $CARCH == aarch64 ]]; then
|
||||
# The x86_64 boot stack's drop-ins must not ship on aarch64: mkinitcpio
|
||||
# reads every file under /etc/mkinitcpio.conf.d/, so omarchy_hooks.conf
|
||||
# would inject the Limine hooks into the Asahi kernel's initramfs, and the
|
||||
# Limine entry-tool config has no consumer without Limine.
|
||||
rm -rf "$pkgdir/etc/limine-entry-tool.d" "$pkgdir/etc/mkinitcpio.conf.d"
|
||||
# Memory stack: no zram device or zswap on the aarch64 install, and
|
||||
# systemd-oomd is not enabled there, so the vm.* reclaim tuning written
|
||||
# for zram would be wrong for it. Keep only the network tuning.
|
||||
rm -rf "$pkgdir/etc/systemd/oomd.conf.d"
|
||||
rm -f "$pkgdir/etc/systemd/zram-generator.conf" "$pkgdir/etc/tmpfiles.d/omarchy-zswap.conf"
|
||||
cat >"$pkgdir/etc/sysctl.d/99-omarchy-sysctl.conf" <<'EOF'
|
||||
# Solve common flakiness with SSH (MTU discovery on flaky links).
|
||||
net.ipv4.tcp_mtu_probing=1
|
||||
EOF
|
||||
# USB autosuspend is left at the kernel default on Apple Silicon.
|
||||
rm -f "$pkgdir/etc/modprobe.d/omarchy-usb-autosuspend.conf"
|
||||
rmdir "$pkgdir/etc/modprobe.d" "$pkgdir/etc/tmpfiles.d" 2>/dev/null || true
|
||||
fi
|
||||
# sudoers.d files must be mode 0440 or sudo will refuse them, and the
|
||||
# directory must be 0750 to match the Arch sudo package's filesystem
|
||||
# convention (otherwise pacman warns about dir-mode drift on every install).
|
||||
@@ -280,6 +325,10 @@ EOF
|
||||
# live root config.
|
||||
install -d "$pkgdir/usr/share/omarchy/default"
|
||||
cp -a default/. "$pkgdir/usr/share/omarchy/default/"
|
||||
# The Limine template is read by the x86_64 ISO orchestrator only.
|
||||
if [[ $CARCH == aarch64 ]]; then
|
||||
rm -rf "$pkgdir/usr/share/omarchy/default/limine"
|
||||
fi
|
||||
|
||||
# Snapper config template used by the install-time `snapper create-config`.
|
||||
install -Dm644 default/snapper/root \
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
_apple_silicon() {
|
||||
[[ $(uname -m) == aarch64 ]] && grep -aq 'apple,' /proc/device-tree/compatible 2>/dev/null
|
||||
}
|
||||
|
||||
_etc_overrides_apply() {
|
||||
echo "Applying Omarchy etc-overrides..."
|
||||
|
||||
# The hardened CUPS authorization applies on every platform. It waits for the
|
||||
# file the cups package owns: an ISO bootstrap without cups installed is left
|
||||
# alone and picks it up once cups lands.
|
||||
if [[ -f /etc/cups/cups-files.conf && -f /usr/share/omarchy/etc-overrides/cups-cups-files.conf ]]; then
|
||||
systemd-sysusers /etc/sysusers.d/omarchy-cups-browsed.conf
|
||||
install -m 0640 -o root -g cups /usr/share/omarchy/etc-overrides/cups-cups-files.conf /etc/cups/cups-files.conf
|
||||
fi
|
||||
|
||||
# Apple Silicon installs run on Arch Linux ARM's base with the Asahi
|
||||
# packages, and keep that system identity: /etc/os-release stays the
|
||||
# symlink to the distribution's /usr/lib/os-release, and the PAM, NSS,
|
||||
# plymouth and skel overrides below are not applied there.
|
||||
if _apple_silicon; then
|
||||
echo "Preserving Arch Linux ARM system configuration on Apple Silicon..."
|
||||
if [[ -f /usr/lib/os-release ]]; then
|
||||
rm -f /etc/os-release
|
||||
ln -s ../usr/lib/os-release /etc/os-release
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Ensure parent dirs exist. cups-browsed may not be installed yet during ISO
|
||||
# bootstrap; do not create /etc/cups/cups-browsed.conf before the package is
|
||||
# installed or pacman will preserve its packaged file as a noisy .pacnew.
|
||||
@@ -21,10 +46,6 @@ _etc_overrides_apply() {
|
||||
install -d /etc/cups
|
||||
cp -f /usr/share/omarchy/etc-overrides/cups-cups-browsed.conf /etc/cups/cups-browsed.conf
|
||||
fi
|
||||
if [[ -f /etc/cups/cups-files.conf && -f /usr/share/omarchy/etc-overrides/cups-cups-files.conf ]]; then
|
||||
systemd-sysusers /etc/sysusers.d/omarchy-cups-browsed.conf
|
||||
install -m 0640 -o root -g cups /usr/share/omarchy/etc-overrides/cups-cups-files.conf /etc/cups/cups-files.conf
|
||||
fi
|
||||
cp -f /usr/share/omarchy/etc-overrides/plymouth-plymouthd.conf /etc/plymouth/plymouthd.conf
|
||||
cp -f /usr/share/omarchy/etc-overrides/dot.bashrc /etc/skel/.bashrc
|
||||
chmod 0644 /etc/os-release /etc/security/faillock.conf /etc/nsswitch.conf \
|
||||
|
||||
@@ -15,7 +15,12 @@ _commit='346e69e1cec6c4e8924531874af6ba010a1bc99e'
|
||||
pkgver=4.0.2
|
||||
pkgrel=1
|
||||
pkgdesc='Omarchy user defaults, /etc/skel content, fonts, plymouth theme, and support helpers'
|
||||
arch=('any')
|
||||
# Arch-specific because the shipped /etc tree is not the same on every
|
||||
# architecture: the Limine, mkinitcpio, zram and oomd drop-ins belong to the
|
||||
# x86_64 boot and memory stack and are left out of the aarch64 package (see
|
||||
# package()). makepkg only honours the arch-suffixed arrays below on
|
||||
# arch-specific packages.
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://github.com/basecamp/omarchy'
|
||||
license=('MIT')
|
||||
conflicts=('omarchy-settings-dev')
|
||||
@@ -53,15 +58,10 @@ makedepends=(
|
||||
# scriptlet WILL clobber user edits on each upgrade (documented limitation).
|
||||
backup=(
|
||||
'etc/fastfetch/config.jsonc'
|
||||
'etc/mkinitcpio.conf.d/omarchy_hooks.conf'
|
||||
'etc/mkinitcpio.conf.d/thunderbolt_module.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-defaults.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-uki.conf'
|
||||
'etc/docker/daemon.json'
|
||||
'etc/gnupg/dirmngr.conf'
|
||||
'etc/sysctl.d/99-omarchy-sysctl.conf'
|
||||
'etc/sysctl.d/90-omarchy-file-watchers.conf'
|
||||
'etc/modprobe.d/omarchy-usb-autosuspend.conf'
|
||||
'etc/systemd/logind.conf.d/10-ignore-power-button.conf'
|
||||
'etc/systemd/logind.conf.d/20-inhibit-delay.conf'
|
||||
'etc/systemd/resolved.conf.d/10-disable-multicast.conf'
|
||||
@@ -72,18 +72,31 @@ backup=(
|
||||
'etc/systemd/system/plocate-updatedb.service.d/ac-only.conf'
|
||||
'etc/systemd/system.conf.d/20-omarchy-nofile.conf'
|
||||
'etc/systemd/user.conf.d/20-omarchy-nofile.conf'
|
||||
'etc/systemd/oomd.conf.d/10-omarchy.conf'
|
||||
'etc/systemd/zram-generator.conf'
|
||||
'etc/sddm.conf.d/10-theme.conf'
|
||||
'etc/sddm.conf.d/10-wayland.conf'
|
||||
'etc/udev/rules.d/99-omarchy-power-profile.rules'
|
||||
'etc/udev/rules.d/99-omarchy-wifi-powersave.rules'
|
||||
)
|
||||
# backup has no arch-suffixed form, so the x86_64-only drop-ins join it here.
|
||||
# Each of these paths is removed from the aarch64 package in package().
|
||||
if [[ $CARCH == x86_64 ]]; then
|
||||
backup+=(
|
||||
'etc/mkinitcpio.conf.d/omarchy_hooks.conf'
|
||||
'etc/mkinitcpio.conf.d/thunderbolt_module.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-defaults.conf'
|
||||
'etc/limine-entry-tool.d/omarchy-uki.conf'
|
||||
'etc/modprobe.d/omarchy-usb-autosuspend.conf'
|
||||
'etc/systemd/oomd.conf.d/10-omarchy.conf'
|
||||
'etc/systemd/zram-generator.conf'
|
||||
)
|
||||
fi
|
||||
|
||||
optdepends=(
|
||||
'omarchy: Full Omarchy desktop'
|
||||
'inxi: System information for omarchy-debug'
|
||||
'fastfetch: System information for omarchy-upload-log'
|
||||
)
|
||||
optdepends_x86_64=(
|
||||
'limine: Bootloader the shipped /etc/mkinitcpio.conf.d/ and /etc/limine-entry-tool.d/ drop-ins are for'
|
||||
'limine-mkinitcpio-hook: Picks up the shipped /etc/mkinitcpio.conf.d/omarchy_hooks.conf'
|
||||
'limine-snapper-sync: Boot-entry sync for snapper snapshots'
|
||||
@@ -142,6 +155,14 @@ package() {
|
||||
install -d "$pkgdir/usr/share/omarchy/config"
|
||||
cp -a config/. "$pkgdir/usr/share/omarchy/config/"
|
||||
|
||||
# The Limine/Snapper notifier has nothing to notify about without the x86_64
|
||||
# boot stack; drop it from both seeds so aarch64 users don't autostart a
|
||||
# helper whose backing tool is not installed.
|
||||
if [[ $CARCH == aarch64 ]]; then
|
||||
rm -f "$pkgdir/etc/skel/.config/autostart/limine-snapper-notify.desktop" \
|
||||
"$pkgdir/usr/share/omarchy/config/autostart/limine-snapper-notify.desktop"
|
||||
fi
|
||||
|
||||
# Package-owned defaults with real system/XDG locations. User config remains
|
||||
# higher priority: ~/.config/uwsm/default, ~/.config/uwsm/env.d,
|
||||
# ~/.config/environment.d, ~/.config/fontconfig, ~/.config/xdg-terminals.list,
|
||||
@@ -169,9 +190,17 @@ package() {
|
||||
install -Dm644 default/systemd/user/omarchy-crash-watch.service "$pkgdir/usr/lib/systemd/user/omarchy-crash-watch.service"
|
||||
# Marks app.slice (and only app.slice) as a systemd-oomd kill candidate, so
|
||||
# memory pressure costs one app scope instead of the compositor session.
|
||||
# Thresholds live in etc/systemd/oomd.conf.d/10-omarchy.conf.
|
||||
install -Dm644 default/systemd/user/app.slice.d/10-oomd.conf "$pkgdir/usr/lib/systemd/user/app.slice.d/10-oomd.conf"
|
||||
install -Dm644 default/systemd/zram-generator.conf.d/90-omarchy.conf "$pkgdir/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf"
|
||||
# Thresholds live in etc/systemd/oomd.conf.d/10-omarchy.conf. Both this and
|
||||
# the zram vendor drop-in belong to the x86_64 memory stack: the aarch64
|
||||
# install neither enables systemd-oomd nor configures zram swap.
|
||||
if [[ $CARCH == x86_64 ]]; then
|
||||
install -Dm644 default/systemd/user/app.slice.d/10-oomd.conf "$pkgdir/usr/lib/systemd/user/app.slice.d/10-oomd.conf"
|
||||
install -Dm644 default/systemd/zram-generator.conf.d/90-omarchy.conf "$pkgdir/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf"
|
||||
fi
|
||||
# Older release pins still configure locate through install/config/locate.sh.
|
||||
if [[ -f default/systemd/system/plocate-updatedb.service.d/10-omarchy.conf ]]; then
|
||||
install -Dm644 default/systemd/system/plocate-updatedb.service.d/10-omarchy.conf "$pkgdir/usr/lib/systemd/system/plocate-updatedb.service.d/10-omarchy.conf"
|
||||
fi
|
||||
|
||||
# Same for applications/** — used by omarchy-refresh-applications,
|
||||
# omarchy-install-gaming-*, etc. to copy .desktop files into ~/.local/share.
|
||||
@@ -185,6 +214,25 @@ package() {
|
||||
# stage separately below).
|
||||
install -d "$pkgdir/etc"
|
||||
cp -a etc/. "$pkgdir/etc/"
|
||||
if [[ $CARCH == aarch64 ]]; then
|
||||
# The x86_64 boot stack's drop-ins must not ship on aarch64: mkinitcpio
|
||||
# reads every file under /etc/mkinitcpio.conf.d/, so omarchy_hooks.conf
|
||||
# would inject the Limine hooks into the Asahi kernel's initramfs, and the
|
||||
# Limine entry-tool config has no consumer without Limine.
|
||||
rm -rf "$pkgdir/etc/limine-entry-tool.d" "$pkgdir/etc/mkinitcpio.conf.d"
|
||||
# Memory stack: no zram device or zswap on the aarch64 install, and
|
||||
# systemd-oomd is not enabled there, so the vm.* reclaim tuning written
|
||||
# for zram would be wrong for it. Keep only the network tuning.
|
||||
rm -rf "$pkgdir/etc/systemd/oomd.conf.d"
|
||||
rm -f "$pkgdir/etc/systemd/zram-generator.conf" "$pkgdir/etc/tmpfiles.d/omarchy-zswap.conf"
|
||||
cat >"$pkgdir/etc/sysctl.d/99-omarchy-sysctl.conf" <<'EOF'
|
||||
# Solve common flakiness with SSH (MTU discovery on flaky links).
|
||||
net.ipv4.tcp_mtu_probing=1
|
||||
EOF
|
||||
# USB autosuspend is left at the kernel default on Apple Silicon.
|
||||
rm -f "$pkgdir/etc/modprobe.d/omarchy-usb-autosuspend.conf"
|
||||
rmdir "$pkgdir/etc/modprobe.d" "$pkgdir/etc/tmpfiles.d" 2>/dev/null || true
|
||||
fi
|
||||
# sudoers.d files must be mode 0440 or sudo will refuse them, and the
|
||||
# directory must be 0750 to match the Arch sudo package's filesystem
|
||||
# convention (otherwise pacman warns about dir-mode drift on every install).
|
||||
@@ -275,6 +323,10 @@ EOF
|
||||
# live root config.
|
||||
install -d "$pkgdir/usr/share/omarchy/default"
|
||||
cp -a default/. "$pkgdir/usr/share/omarchy/default/"
|
||||
# The Limine template is read by the x86_64 ISO orchestrator only.
|
||||
if [[ $CARCH == aarch64 ]]; then
|
||||
rm -rf "$pkgdir/usr/share/omarchy/default/limine"
|
||||
fi
|
||||
|
||||
# Snapper config template used by the install-time `snapper create-config`.
|
||||
install -Dm644 default/snapper/root \
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
_apple_silicon() {
|
||||
[[ $(uname -m) == aarch64 ]] && grep -aq 'apple,' /proc/device-tree/compatible 2>/dev/null
|
||||
}
|
||||
|
||||
_etc_overrides_apply() {
|
||||
echo "Applying Omarchy etc-overrides..."
|
||||
|
||||
# The hardened CUPS authorization applies on every platform. It waits for the
|
||||
# file the cups package owns: an ISO bootstrap without cups installed is left
|
||||
# alone and picks it up once cups lands.
|
||||
if [[ -f /etc/cups/cups-files.conf && -f /usr/share/omarchy/etc-overrides/cups-cups-files.conf ]]; then
|
||||
systemd-sysusers /etc/sysusers.d/omarchy-cups-browsed.conf
|
||||
install -m 0640 -o root -g cups /usr/share/omarchy/etc-overrides/cups-cups-files.conf /etc/cups/cups-files.conf
|
||||
fi
|
||||
|
||||
# Apple Silicon installs run on Arch Linux ARM's base with the Asahi
|
||||
# packages, and keep that system identity: /etc/os-release stays the
|
||||
# symlink to the distribution's /usr/lib/os-release, and the PAM, NSS,
|
||||
# plymouth and skel overrides below are not applied there.
|
||||
if _apple_silicon; then
|
||||
echo "Preserving Arch Linux ARM system configuration on Apple Silicon..."
|
||||
if [[ -f /usr/lib/os-release ]]; then
|
||||
rm -f /etc/os-release
|
||||
ln -s ../usr/lib/os-release /etc/os-release
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Ensure parent dirs exist. cups-browsed may not be installed yet during ISO
|
||||
# bootstrap; do not create /etc/cups/cups-browsed.conf before the package is
|
||||
# installed or pacman will preserve its packaged file as a noisy .pacnew.
|
||||
@@ -21,10 +46,6 @@ _etc_overrides_apply() {
|
||||
install -d /etc/cups
|
||||
cp -f /usr/share/omarchy/etc-overrides/cups-cups-browsed.conf /etc/cups/cups-browsed.conf
|
||||
fi
|
||||
if [[ -f /etc/cups/cups-files.conf && -f /usr/share/omarchy/etc-overrides/cups-cups-files.conf ]]; then
|
||||
systemd-sysusers /etc/sysusers.d/omarchy-cups-browsed.conf
|
||||
install -m 0640 -o root -g cups /usr/share/omarchy/etc-overrides/cups-cups-files.conf /etc/cups/cups-files.conf
|
||||
fi
|
||||
cp -f /usr/share/omarchy/etc-overrides/plymouth-plymouthd.conf /etc/plymouth/plymouthd.conf
|
||||
cp -f /usr/share/omarchy/etc-overrides/dot.bashrc /etc/skel/.bashrc
|
||||
chmod 0644 /etc/os-release /etc/security/faillock.conf /etc/nsswitch.conf \
|
||||
|
||||
+27
-13
@@ -15,7 +15,10 @@ _commit='346e69e1cec6c4e8924531874af6ba010a1bc99e'
|
||||
pkgver=4.0.2
|
||||
pkgrel=1
|
||||
pkgdesc='Beautiful, modern, and opinionated Arch Linux by DHH'
|
||||
arch=('any')
|
||||
# The payload is architecture-independent, but the dependency set is not: the
|
||||
# boot stack differs per architecture (see depends_x86_64 / depends_aarch64),
|
||||
# and makepkg only honours arch-suffixed arrays on arch-specific packages.
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://github.com/basecamp/omarchy'
|
||||
license=('MIT')
|
||||
conflicts=('omarchy-dev')
|
||||
@@ -31,18 +34,6 @@ depends=(
|
||||
# from the same _commit, and forces the pair to upgrade together.
|
||||
"omarchy-settings=${pkgver}"
|
||||
|
||||
# Bootloader stack. Lives here rather than on omarchy-settings because
|
||||
# omarchy-settings is also installed into the live ISO env (for plymouth
|
||||
# / /etc/skel seeding), where the limine-mkinitcpio-hook would fail with
|
||||
# 'Cannot detect an ESP path' inside the chroot. The omarchy-settings
|
||||
# config drop-ins under /etc/mkinitcpio.conf.d/, /etc/limine-entry-tool.d/,
|
||||
# and /etc/snapper/config-templates/ only do anything when these are
|
||||
# installed alongside.
|
||||
'limine'
|
||||
'limine-mkinitcpio-hook'
|
||||
'limine-snapper-sync'
|
||||
'snapper'
|
||||
|
||||
# Wayland / Hyprland core
|
||||
'hyprland'
|
||||
'quickshell'
|
||||
@@ -69,6 +60,29 @@ depends=(
|
||||
'ttf-jetbrains-mono-nerd-basic'
|
||||
)
|
||||
|
||||
# Bootloader stack. Lives here rather than on omarchy-settings because
|
||||
# omarchy-settings is also installed into the live ISO env (for plymouth
|
||||
# / /etc/skel seeding), where the limine-mkinitcpio-hook would fail with
|
||||
# 'Cannot detect an ESP path' inside the chroot. The omarchy-settings
|
||||
# config drop-ins under /etc/mkinitcpio.conf.d/, /etc/limine-entry-tool.d/,
|
||||
# and /etc/snapper/config-templates/ only do anything when these are
|
||||
# installed alongside.
|
||||
depends_x86_64=(
|
||||
'limine'
|
||||
'limine-mkinitcpio-hook'
|
||||
'limine-snapper-sync'
|
||||
'snapper'
|
||||
)
|
||||
|
||||
# Apple Silicon boots through m1n1 + GRUB from the Asahi packages and keeps
|
||||
# Arch Linux ARM's kernel and boot layout, so the Limine/Snapper stack does not
|
||||
# apply. Wi-Fi on the Broadcom parts only scans reliably through the iwd
|
||||
# backend, which install/hardware/network.sh selects on Apple Silicon.
|
||||
depends_aarch64=(
|
||||
'iwd'
|
||||
'networkmanager'
|
||||
)
|
||||
|
||||
makedepends=(
|
||||
'git'
|
||||
)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"source": "local",
|
||||
"rebuild_on": [
|
||||
"hyprland"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
# Maintainer: Ryan <ryan@heyoodle.com>
|
||||
|
||||
pkgname=omareel
|
||||
pkgver=0.1.0
|
||||
pkgrel=1
|
||||
pkgdesc='Screen recorder and editor for Omarchy with a synthetic cursor, auto zooms, and a camera bubble'
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://github.com/omacom/omareel'
|
||||
license=('MIT')
|
||||
install='omareel.install'
|
||||
options=('!debug')
|
||||
depends=(
|
||||
'ffmpeg'
|
||||
'gpu-screen-recorder'
|
||||
'hicolor-icon-theme'
|
||||
'hyprland'
|
||||
'layer-shell-qt'
|
||||
'libevdev'
|
||||
'libjpeg-turbo'
|
||||
'qt6-base'
|
||||
'qt6-declarative'
|
||||
'qt6-multimedia'
|
||||
'qt6-svg'
|
||||
'slurp'
|
||||
'xdg-desktop-portal'
|
||||
)
|
||||
makedepends=(
|
||||
'cmake'
|
||||
'ninja'
|
||||
'pkgconf'
|
||||
'qt6-shadertools'
|
||||
'wayland'
|
||||
)
|
||||
optdepends=('gifsicle: optimize exported GIF files')
|
||||
conflicts=('omarecord')
|
||||
source=("$pkgname-$pkgver.tar.gz::$url/archive/refs/tags/v$pkgver.tar.gz")
|
||||
sha256sums=('330d8e2805135af33bf35378e2e961094fc375075d38120c8270bd42fe04ce5b')
|
||||
|
||||
build() {
|
||||
cd "$srcdir/$pkgname-$pkgver"
|
||||
./bin/build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/$pkgname-$pkgver"
|
||||
install -Dm755 build/omareel "$pkgdir/usr/bin/omareel"
|
||||
ln -s omareel "$pkgdir/usr/bin/omarecord"
|
||||
# The capture-exclusion plugin is bound to the Hyprland commit it was built
|
||||
# against; rebuild_on hyprland keeps this package in step with the compositor.
|
||||
install -Dm755 build/plugin/omareel-capture-exclude.so "$pkgdir/usr/lib/omareel/omareel-capture-exclude.so"
|
||||
install -Dm644 build/plugin/omareel-capture-exclude.so.hash "$pkgdir/usr/lib/omareel/omareel-capture-exclude.so.hash"
|
||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||
install -Dm644 LICENSES/lucide.txt "$pkgdir/usr/share/licenses/$pkgname/lucide.txt"
|
||||
install -Dm644 pkg/omareel.svg "$pkgdir/usr/share/icons/hicolor/scalable/apps/omareel.svg"
|
||||
local size
|
||||
for size in 16 32 48 64 128 256 512; do
|
||||
install -Dm644 "pkg/icons/omareel-$size.png" \
|
||||
"$pkgdir/usr/share/icons/hicolor/${size}x${size}/apps/omareel.png"
|
||||
done
|
||||
install -Dm644 pkg/omareel.desktop "$pkgdir/usr/share/applications/omareel.desktop"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
post_install() {
|
||||
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database -q
|
||||
command -v gtk-update-icon-cache >/dev/null 2>&1 && gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
|
||||
return 0
|
||||
}
|
||||
|
||||
post_upgrade() {
|
||||
post_install
|
||||
}
|
||||
|
||||
post_remove() {
|
||||
post_install
|
||||
}
|
||||
@@ -4,7 +4,7 @@ pkgname=omasnap
|
||||
pkgver=1.20.1
|
||||
pkgrel=1
|
||||
pkgdesc="Native Wayland screenshot and annotation overlay for Hyprland"
|
||||
arch=('x86_64')
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/tobi/omasnap"
|
||||
license=('MIT' 'OFL-1.1')
|
||||
depends=(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"upstream_commit": "e2a85e53e2a73cec9170a5fa631805f62b98bb36"
|
||||
"upstream_commit": "cbc25a60a791ccda07ed5e8300e8acb267d23007"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
pkgname=omazed
|
||||
pkgver=2.1.1
|
||||
pkgver=2.1.2
|
||||
pkgrel=1
|
||||
pkgdesc="Live theme switching for Zed in Omarchy - automatically synchronize your Zed editor theme with your Omarchy system theme"
|
||||
arch=('any')
|
||||
@@ -10,7 +10,7 @@ makedepends=('git')
|
||||
backup=()
|
||||
install=omazed.install
|
||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/aps6/$pkgname/archive/refs/tags/v$pkgver.tar.gz")
|
||||
sha256sums=('083757c5385179f241ac0c6e9dde05ba0c7f465c1fed617779d1ebe2a6dfe036')
|
||||
sha256sums=('ca0708c86969547b14958a307ae3df89f63d92ffa68af3b5c6bf79c036b8cab9')
|
||||
|
||||
package() {
|
||||
cd "$srcdir/$pkgname-$pkgver"
|
||||
|
||||
@@ -17,11 +17,6 @@ post_upgrade() {
|
||||
echo ""
|
||||
echo "==> Omazed updated to $(pacman -Q omazed | cut -d' ' -f2)"
|
||||
echo ""
|
||||
echo " Complete the update!"
|
||||
echo ""
|
||||
echo " To complete this update, run:"
|
||||
echo ""
|
||||
echo " omazed setup"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"release_ring": "fast",
|
||||
"upstream_commit": "7298bbbde771f2f33d0942fc429bd27643a9986a"
|
||||
"upstream_commit": "134a0e93624d39306f94dc4384dbd102b8d37bb2"
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# shellcheck disable=SC2034
|
||||
# Maintainer: Chmouel Boudjnah <chmouel@chmouel.com>
|
||||
pkgname=openai-codex-bin
|
||||
pkgver=0.152.0
|
||||
pkgver=0.153.4
|
||||
pkgrel=1
|
||||
pkgdesc="Arch Linux package for OpenAI's Codex CLI - Auto Updated"
|
||||
arch=('x86_64' 'aarch64')
|
||||
@@ -21,10 +21,10 @@ source_x86_64=(
|
||||
"codex-${pkgver}-x86_64.tar.gz::https://github.com/openai/codex/releases/download/rust-v${pkgver}/codex-x86_64-unknown-linux-musl.tar.gz"
|
||||
"codex-code-mode-host-${pkgver}-x86_64.tar.gz::https://github.com/openai/codex/releases/download/rust-v${pkgver}/codex-code-mode-host-x86_64-unknown-linux-musl.tar.gz"
|
||||
)
|
||||
sha256sums_x86_64=('05f942d3d3c5b5acd9edad56ce2797b6fe72dbb1462b24e5c9bf7dcec9a28a11'
|
||||
'449cefe35b9f347e3fdbf121e816339b37825eb0bfee7de8298a0a61b6687cba')
|
||||
sha256sums_aarch64=('37da6b486503c8a42cc4604d2a3d80d388df896dd251e9225f4f3d49b08c2e8c'
|
||||
'134183c7f5bb2245ed4bb15cfcf00d1a64950adbdd089d33c003c8bcf13267e9')
|
||||
sha256sums_x86_64=('f479424eca092484dc40d87ae28c44f4cc40234a60045d6131e493800d814a30'
|
||||
'f95830a869590957664bbfc67bccb08773806b693670baf15908176f89b4cd31')
|
||||
sha256sums_aarch64=('5cda6182bd94c3a30f2eb63a495489ebf7f691fddb14d70f48c6c1a5071b6cde'
|
||||
'd8047b8d33370d6090e729d27eb76de60a2686baa1c143c138c9b05dc70d813b')
|
||||
|
||||
source_aarch64=(
|
||||
"codex-${pkgver}-aarch64.tar.gz::https://github.com/openai/codex/releases/download/rust-v${pkgver}/codex-aarch64-unknown-linux-musl.tar.gz"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# the version and checksums below from that repository's package index.
|
||||
|
||||
pkgname=openai-codex-desktop
|
||||
pkgver=26.825.51511
|
||||
pkgver=26.901.51231
|
||||
pkgrel=1
|
||||
pkgdesc="Official ChatGPT desktop app with Codex"
|
||||
arch=('x86_64' 'aarch64')
|
||||
@@ -71,8 +71,8 @@ source_x86_64=("${_deb_x86_64}::${_pool}/${_deb_x86_64}")
|
||||
source_aarch64=("${_deb_aarch64}::${_pool}/${_deb_aarch64}")
|
||||
noextract=("${_deb_x86_64}" "${_deb_aarch64}")
|
||||
sha256sums=('b3a4503b5931f102444bc7015c3cf4e40266cf034e0d682bd2a407dc5b3ee58c')
|
||||
sha256sums_x86_64=('3554b0022c6cfb513326f43fd11f718835a77086ac4d7ca2ff3ebbba2d4c7f45')
|
||||
sha256sums_aarch64=('125e36522d43c75bd7958477846ba6b1cddf2eb19cefcb57dda80be1742f917f')
|
||||
sha256sums_x86_64=('62580188d87c3d3a9369dab7c73b42a8a32518d4df8a2d5bae6466ddeac5c05e')
|
||||
sha256sums_aarch64=('02a2f5c6cb69509c62abcbdd13c76b139cdb2ca9edde7537239ddde024077ea0')
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"min_release_age": "24h",
|
||||
"upstream": {
|
||||
"npm": "openclaw",
|
||||
"sources": {
|
||||
"any": ["{npm_tarball}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
# Based on the AUR openclaw package:
|
||||
# Maintainer: Ralph Torres <mail at ralphptorr dot es>
|
||||
# Contributor: Evert Vorster <evorster@gmail.com>
|
||||
# Contributor: Emir-Eins <emir-eins@outlook.com>
|
||||
# Contributor: Wuxxin <wuxxin@gmail.com>
|
||||
# Followed here straight from the npm registry (see .omarchy/package.json), since
|
||||
# upstream's release cadence outruns the AUR.
|
||||
|
||||
pkgname=openclaw
|
||||
pkgver=2026.9.2
|
||||
pkgrel=1
|
||||
pkgdesc='Multi-channel AI gateway with extensible messaging integrations'
|
||||
arch=(x86_64 aarch64)
|
||||
url=https://github.com/openclaw/openclaw
|
||||
license=(MIT)
|
||||
|
||||
depends=('nodejs>=22')
|
||||
makedepends=(npm)
|
||||
optdepends=(
|
||||
'1password-cli: 1password skill'
|
||||
'curl: weather, openai-whisper-api skills'
|
||||
'ffmpeg: video-frames skill'
|
||||
'github-cli: github, gh-issues skills'
|
||||
'jq: session-logs, trello skills'
|
||||
'python-openai-whisper: openai-whisper skill'
|
||||
'ripgrep: session-logs skill'
|
||||
'tmux: tmux skill'
|
||||
'uv: nano-pdf skill'
|
||||
'go: for installing skill tools not packaged for Arch'
|
||||
)
|
||||
source=($pkgname-$pkgver.tgz::https://registry.npmjs.org/$pkgname/-/$pkgname-$pkgver.tgz)
|
||||
sha256sums=('3431f4cd2d8dbd6b936def2694ac27e19fa0256295cf4ada0f652ecf1c9ee520')
|
||||
options=(!debug !strip)
|
||||
install=$pkgname.install
|
||||
noextract=($pkgname-$pkgver.tgz)
|
||||
|
||||
package() {
|
||||
export SHARP_IGNORE_GLOBAL_LIBVIPS=1
|
||||
# npm 12 blocks install-time lifecycle scripts unless the package is
|
||||
# allow-listed, and for a local tarball the allow-list key is the tarball's
|
||||
# own file: spec, not the package name (arborist matches node.resolved).
|
||||
# Upstream's postinstall prunes stale dist files and clears the
|
||||
# .openclaw-lifecycle-pending marker the tarball ships with; without it,
|
||||
# every openclaw invocation tries to finish that lifecycle itself and dies
|
||||
# with EACCES on the root-owned install.
|
||||
# That postinstall also migrates legacy state under whatever home it sees
|
||||
# (pruning plugin-runtime-deps in ~/.openclaw and friends), so it gets a
|
||||
# scratch home: a maintainer's own OpenClaw is not the build's to touch.
|
||||
mkdir -p "$srcdir"/home
|
||||
env -u OPENCLAW_HOME -u OPENCLAW_STATE_DIR -u OPENCLAW_CONFIG_PATH HOME="$srcdir"/home \
|
||||
npm install --silent --global --cache "$srcdir"/npm-cache \
|
||||
--allow-scripts="file:$srcdir/$pkgname-$pkgver.tgz" \
|
||||
--prefix "$pkgdir"/usr "$srcdir"/$pkgname-$pkgver.tgz
|
||||
if [[ -e "$pkgdir"/usr/lib/node_modules/$pkgname/.openclaw-lifecycle-pending ]]; then
|
||||
error "openclaw's postinstall did not run; the package would fail on first use"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cat > $pkgname <<'EOF'
|
||||
#!/bin/sh
|
||||
export SHARP_IGNORE_GLOBAL_LIBVIPS=1
|
||||
exec node /usr/lib/node_modules/openclaw/openclaw.mjs "$@"
|
||||
EOF
|
||||
install -Dm755 -t "$pkgdir"/usr/bin $pkgname
|
||||
|
||||
cd "$pkgdir"/usr/lib/node_modules/$pkgname
|
||||
install -Dm644 -t "$pkgdir"/usr/share/licenses/$pkgname LICENSE
|
||||
install -Dm644 -t "$pkgdir"/usr/share/doc/$pkgname README.md CHANGELOG.md
|
||||
for f in docs/*
|
||||
do ln -s /usr/lib/node_modules/$pkgname/"$f" "$pkgdir"/usr/share/doc/$pkgname/
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
post_install() {
|
||||
printf "%s\n" \
|
||||
"==> Install gateway service: openclaw gateway install --force" \
|
||||
"==> Perform onboarding once: openclaw onboard"
|
||||
}
|
||||
|
||||
post_upgrade() {
|
||||
# The gateway runs as a systemd user unit (openclaw-gateway.service in
|
||||
# ~/.config/systemd/user), which a root pacman hook has no session bus
|
||||
# to reach, so it cannot be restarted from here and keeps running the
|
||||
# old code until the user restarts it.
|
||||
printf "%s\n" \
|
||||
"==> Restart the gateway to apply updates:" \
|
||||
" openclaw gateway restart" \
|
||||
"==> Run doctor to migrate configs, check gateway health, etc.:" \
|
||||
" openclaw doctor"
|
||||
}
|
||||
File renamed without changes.
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
# Perplexity ships its desktop app from its own Debian repository. The
|
||||
# per-architecture package index carries the filename and SHA256 of every deb,
|
||||
# so an update costs two small HTTP requests instead of a 175 MB download. The
|
||||
# index's Version field drops the build number the pool filename carries, and
|
||||
# upstream rebuilds under the same marketing version, so the version of record
|
||||
# here is the full string embedded in the filename.
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="https://packages.perplexity.ai/deb"
|
||||
declare -A DEB_ARCHES=([x86_64]=amd64 [aarch64]=arm64)
|
||||
|
||||
# Print "<version> <sha256>" for the newest stanza in a Packages index, version
|
||||
# meaning the full string from the pool filename. Newest is vercmp's opinion,
|
||||
# which is the one bin/sync-upstream and pacman both use; sort -V disagrees
|
||||
# with it over versions like 1.0a.
|
||||
newest_release() {
|
||||
local index="$1"
|
||||
local debarch="$2"
|
||||
local filename sha256 version best_version="" best_sha256=""
|
||||
local prefix="pool/main/p/perplexity/perplexity_"
|
||||
local suffix="_${debarch}.deb"
|
||||
|
||||
while read -r filename sha256; do
|
||||
# The PKGBUILD reconstructs the pool URL from pkgver alone, so a stanza
|
||||
# naming anything else -- a rename, or a new pool layout -- has to stop
|
||||
# the sync rather than pin a checksum to a URL nobody will fetch.
|
||||
if [[ "$filename" != "${prefix}"*"${suffix}" ]]; then
|
||||
echo "Unexpected pool filename in the upstream index: $filename" >&2
|
||||
return 1
|
||||
fi
|
||||
version="${filename#"$prefix"}"
|
||||
version="${version%"$suffix"}"
|
||||
|
||||
if [[ -z "$best_version" ]] || [[ "$(vercmp "$version" "$best_version")" -gt 0 ]]; then
|
||||
best_version="$version"
|
||||
best_sha256="$sha256"
|
||||
fi
|
||||
done < <(awk '
|
||||
{ sub(/\r$/, "") }
|
||||
/^Filename:/ { filename = $2 }
|
||||
/^SHA256:/ { sha256 = $2 }
|
||||
/^$/ { if (filename && sha256) print filename, sha256; filename = sha256 = "" }
|
||||
END { if (filename && sha256) print filename, sha256 }
|
||||
' <<<"$index")
|
||||
|
||||
[[ -n "$best_version" ]] || return 1
|
||||
echo "$best_version $best_sha256"
|
||||
}
|
||||
|
||||
versions=()
|
||||
declare -A checksums=()
|
||||
|
||||
for arch in "${!DEB_ARCHES[@]}"; do
|
||||
index=$(curl -fsSL "$BASE_URL/dists/stable/main/binary-${DEB_ARCHES[$arch]}/Packages")
|
||||
|
||||
read -r version sha256 <<<"$(newest_release "$index" "${DEB_ARCHES[$arch]}")"
|
||||
if [[ -z "${version:-}" || -z "${sha256:-}" ]]; then
|
||||
echo "No usable release found for $arch in the upstream package index" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
versions+=("$version")
|
||||
checksums[$arch]="$sha256"
|
||||
done
|
||||
|
||||
# A release lands one architecture at a time, and a single pkgver has to cover
|
||||
# both -- including the build number, since that is what the download URLs are
|
||||
# built from. Report no update until they agree; the next run picks it up.
|
||||
for version in "${versions[@]}"; do
|
||||
if [[ "$version" != "${versions[0]}" ]]; then
|
||||
echo "Upstream architectures are mid-release (${versions[*]}); skipping" >&2
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
jq -n \
|
||||
--arg pkgver "${versions[0]}" \
|
||||
--arg x86_64 "${checksums[x86_64]}" \
|
||||
--arg aarch64 "${checksums[aarch64]}" \
|
||||
'{pkgver: $pkgver, sha256sums: {x86_64: [$x86_64], aarch64: [$aarch64]}}'
|
||||
@@ -0,0 +1,139 @@
|
||||
# Maintainer: Spencer Bull <spencer@omarchy.org>
|
||||
|
||||
# Omarchy tracks Perplexity's own Debian repository, the feed the app updates
|
||||
# itself from. .omarchy/upstream.sh rewrites the version and checksums below
|
||||
# from that repository's package index.
|
||||
|
||||
pkgname=perplexity
|
||||
pkgver=26.9.1+build61614
|
||||
pkgrel=2
|
||||
pkgdesc="Official Perplexity desktop app"
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://www.perplexity.ai"
|
||||
# Upstream ships no license text with the app; its terms live at
|
||||
# https://www.perplexity.ai/hub/legal/terms-of-service
|
||||
license=('custom')
|
||||
|
||||
depends=(
|
||||
'alsa-lib'
|
||||
'at-spi2-core'
|
||||
'bash'
|
||||
'bubblewrap'
|
||||
'cairo'
|
||||
'dbus'
|
||||
'expat'
|
||||
'gcc-libs'
|
||||
'gdk-pixbuf2'
|
||||
'glib2'
|
||||
'glibc'
|
||||
'gtk3'
|
||||
'hicolor-icon-theme'
|
||||
'libcups'
|
||||
'libdrm'
|
||||
'libglvnd'
|
||||
'libnotify'
|
||||
'libsecret'
|
||||
'libx11'
|
||||
'libxcb'
|
||||
'libxcomposite'
|
||||
'libxdamage'
|
||||
'libxext'
|
||||
'libxfixes'
|
||||
'libxkbcommon'
|
||||
'libxrandr'
|
||||
'libxss'
|
||||
'libxtst'
|
||||
'mesa'
|
||||
'nspr'
|
||||
'nss'
|
||||
'pango'
|
||||
'systemd-libs'
|
||||
'util-linux-libs'
|
||||
'vulkan-icd-loader'
|
||||
'xdg-utils'
|
||||
)
|
||||
|
||||
optdepends=(
|
||||
'apparmor: confine the app with the bundled user-namespace profile'
|
||||
'libappindicator-gtk3: tray icon support'
|
||||
'docker: containerized local GPU runtime for on-device models'
|
||||
'nvidia-container-toolkit: containerized local GPU runtime for on-device models'
|
||||
)
|
||||
|
||||
makedepends=('libarchive')
|
||||
options=('!debug' '!strip')
|
||||
|
||||
# Omarchy: the build image compresses with zstd at its default level. Maximum
|
||||
# zstd buys roughly a third off this ~600 MB Electron tree for a few extra
|
||||
# minutes of build time -- worth it for a package this large on the fast ring,
|
||||
# same reasoning as openai-codex-desktop.
|
||||
COMPRESSZST=(zstd -c -z -q --ultra -22 --threads=0 -)
|
||||
|
||||
# The pool filename carries a build number the index's Version field drops, and
|
||||
# upstream rebuilds under the same marketing version, so pkgver is the full
|
||||
# string from the filename. The pool's storage treats a literal '+' in a URL as
|
||||
# a space and answers 403, hence the %2B in the download URL only.
|
||||
_deb_x86_64="perplexity_${pkgver}_amd64.deb"
|
||||
_deb_aarch64="perplexity_${pkgver}_arm64.deb"
|
||||
_pool="https://packages.perplexity.ai/deb/pool/main/p/perplexity"
|
||||
source=('perplexity-launcher.sh')
|
||||
source_x86_64=("${_deb_x86_64}::${_pool}/${_deb_x86_64//+/%2B}")
|
||||
source_aarch64=("${_deb_aarch64}::${_pool}/${_deb_aarch64//+/%2B}")
|
||||
noextract=("${_deb_x86_64}" "${_deb_aarch64}")
|
||||
sha256sums=('b180ca6fbd268712a277a34d4215f176001c0031a4f6360686458623f47fad65')
|
||||
sha256sums_x86_64=('2fc95f5500335e661af6901bbad5c95e8805cc9f43d9f0b979787c7249c15c33')
|
||||
sha256sums_aarch64=('917562bad5ab319612c22fca49773cdee163b2e7c9f0c3dd5569fc4878f10237')
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
local deb_var="_deb_${CARCH}"
|
||||
local deb="${!deb_var}"
|
||||
|
||||
bsdtar -xOf "${deb}" data.tar.xz |
|
||||
bsdtar --no-same-owner -xf - -C "${pkgdir}"
|
||||
|
||||
# 26.9.1 started shipping a systemd unit under /lib, and owning /lib -- a
|
||||
# symlink owned by the filesystem package -- makes pacman refuse the whole
|
||||
# transaction. The unit is also a no-op here: its setup script apt-installs
|
||||
# Docker and the NVIDIA Container Toolkit and exits on any distro but Ubuntu
|
||||
# (install those yourself; see optdepends). Delete it, and its parents once
|
||||
# emptied; then anything else left outside opt/ and usr/ -- whatever its
|
||||
# type, an empty bin/ or lib64/ included, since those are filesystem-owned
|
||||
# symlinks too -- stops the build rather than shipping the next conflict.
|
||||
(
|
||||
cd "${pkgdir}"
|
||||
rm -f lib/systemd/system/perplexity-local-runtime-setup.service
|
||||
rmdir -p lib/systemd/system 2>/dev/null || true
|
||||
)
|
||||
|
||||
local unexpected
|
||||
unexpected=$(cd "${pkgdir}" && find . -mindepth 1 \
|
||||
-path ./opt -prune -o -path ./usr -prune -o -print)
|
||||
if [[ -n "${unexpected}" ]]; then
|
||||
echo "Unexpected entries outside opt/ and usr/ in the upstream deb:" >&2
|
||||
echo "${unexpected}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# pacman never runs the deb's postinst, so the /usr/bin entry it would have
|
||||
# symlinked is a launcher here instead, and the menu entry goes through it so
|
||||
# the flags file applies there too. The scheme handler stays upstream's.
|
||||
install -Dm755 perplexity-launcher.sh "${pkgdir}/usr/bin/perplexity"
|
||||
sed -i 's|^Exec=.*|Exec=perplexity %U|' \
|
||||
"${pkgdir}/usr/share/applications/perplexity.desktop"
|
||||
|
||||
# Arch ships Chromium's and Electron's own sandbox helper setuid, which is
|
||||
# what keeps the sandbox up on a kernel that denies unprivileged user
|
||||
# namespaces -- linux-hardened, mainly -- instead of aborting the app. The
|
||||
# deb leaves this bit to its postinst.
|
||||
chmod 4755 "${pkgdir}/opt/Perplexity/chrome-sandbox"
|
||||
|
||||
# The profile upstream's postinst would install. It names /opt/Perplexity
|
||||
# paths, which this package keeps.
|
||||
install -Dm644 "${pkgdir}/opt/Perplexity/resources/apparmor-profile" \
|
||||
"${pkgdir}/etc/apparmor.d/perplexity"
|
||||
|
||||
# Debian package-policy files are not used on Arch Linux.
|
||||
rm -rf "${pkgdir}/usr/share/doc"
|
||||
}
|
||||
Regular → Executable
+4
-3
@@ -4,7 +4,7 @@ set -euo pipefail
|
||||
user_flags=()
|
||||
config_home="${XDG_CONFIG_HOME:-}"
|
||||
[[ -n "$config_home" || -z "${HOME:-}" ]] || config_home="$HOME/.config"
|
||||
flags_file="${config_home:+$config_home/t3code-flags.conf}"
|
||||
flags_file="${config_home:+$config_home/perplexity-flags.conf}"
|
||||
|
||||
if [[ -n "$flags_file" && -f "$flags_file" && -r "$flags_file" ]]; then
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
@@ -16,7 +16,8 @@ if [[ -n "$flags_file" && -f "$flags_file" && -r "$flags_file" ]]; then
|
||||
fi
|
||||
|
||||
# Chromium's own Ozone detection falls back to XWayland often enough to matter,
|
||||
# and the result is a blurry window on every scaled display.
|
||||
# and the result is a blurry window on every scaled display. Ask for Wayland
|
||||
# directly, unless the user has already picked a platform themselves.
|
||||
platform_flags=()
|
||||
if [[ -n "${WAYLAND_DISPLAY:-}" || "${XDG_SESSION_TYPE:-}" == wayland ]]; then
|
||||
platform_flags=(--ozone-platform=wayland)
|
||||
@@ -28,4 +29,4 @@ if [[ -n "${WAYLAND_DISPLAY:-}" || "${XDG_SESSION_TYPE:-}" == wayland ]]; then
|
||||
done
|
||||
fi
|
||||
|
||||
exec /usr/lib/t3code/t3code "${platform_flags[@]}" "${user_flags[@]}" "$@"
|
||||
exec /opt/Perplexity/perplexity "${platform_flags[@]}" "${user_flags[@]}" "$@"
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"upstream_commit": "a850f2d07e825f61cb01b87931d2ae5f1802dde1"
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/FrameworkComputer/qmk_hid.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://github.com/FrameworkComputer/qmk_hid/archive/refs/tags/{tag}.tar.gz"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
pkgname=qmk-hid
|
||||
_srcname=qmk_hid
|
||||
pkgver=0.1.11
|
||||
pkgrel=3
|
||||
pkgver=0.1.13
|
||||
pkgrel=1
|
||||
pkgdesc="Commandline tool for interacting with QMK devices over HID"
|
||||
arch=('x86_64')
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/FrameworkComputer/qmk_hid"
|
||||
license=('BSD')
|
||||
depends=('gcc-libs' 'systemd-libs' 'libcap')
|
||||
makedepends=('cargo')
|
||||
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
|
||||
b2sums=('e898d27cfe8350f4a8cd2938a3d066935093daf1292f41fc10b8f1937059f2b59e4ac34a987f26c8258a5d3b15a900059024fe3a18ed793f7e3b524939ab4c71')
|
||||
sha256sums=('8a058395b8ba56ff54308a681223f11a6032c54df42b4d0223143ccf09d0c858')
|
||||
options=('!lto')
|
||||
|
||||
prepare() {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"qt6-wayland"
|
||||
],
|
||||
"rebuilt_against": {
|
||||
"qt6-base": "6.11.2-2",
|
||||
"qt6-base": "6.11.2-3",
|
||||
"qt6-declarative": "6.11.2-1",
|
||||
"qt6-wayland": "6.11.2-1"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
_pkgname=quickshell
|
||||
pkgname="$_pkgname-git"
|
||||
pkgver=0.3.0.r20.g28771c7
|
||||
pkgrel=2
|
||||
pkgrel=3
|
||||
pkgdesc='Flexible toolkit for making desktop shells with QtQuick'
|
||||
arch=(x86_64 aarch64)
|
||||
url='https://git.outfoxxed.me/quickshell/quickshell'
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{
|
||||
"source": "aur",
|
||||
"upstream_commit": "80c65c27a9d5511d2b4ce2ca7ad2396ad528f0da"
|
||||
"source": "local"
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
# Maintainer: Alexandre Bouvier <contact@amb.tf>
|
||||
_pkgname=retroarch-joypad-autoconfig
|
||||
# Pinned so every architecture packages the same tree and a rebuild of the
|
||||
# same pkgver reproduces the same contents; bump both together.
|
||||
_commit=033151045d378b64e712a92592467800d7924227
|
||||
pkgname=$_pkgname-git
|
||||
pkgver=1.22.0.r24.g739cee1
|
||||
pkgver=1.22.0.r96.g0331510
|
||||
pkgrel=1
|
||||
pkgdesc="RetroArch joypad autoconfig files"
|
||||
arch=('any')
|
||||
@@ -12,7 +15,7 @@ makedepends=('git')
|
||||
optdepends=('retroarch')
|
||||
provides=("$_pkgname")
|
||||
conflicts=("$_pkgname")
|
||||
source=("$_pkgname::git+$url.git")
|
||||
source=("$_pkgname::git+$url.git#commit=$_commit")
|
||||
b2sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast",
|
||||
"min_release_age": "24h",
|
||||
"upstream": {
|
||||
"github": "Infrawrench/schist",
|
||||
"digests": true,
|
||||
"assets": {
|
||||
"x86_64": "schist-{pkgver}-1-x86_64.pkg.tar.zst",
|
||||
"aarch64": "schist-{pkgver}-1-aarch64.pkg.tar.zst"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 143 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user