41 Commits
Author SHA1 Message Date
ZacharyZhang-NY a4cc32340c Merge upstream master so local Omarchy builds carry the published version 2026-10-08 23:48:13 -04:00
ZacharyZhang-NY 44d4d231be Revert "Add rime-ice-installer with offline assets and no sudo when its packages are present"
This reverts commit 5e0ff0df95.
2026-10-08 23:48:13 -04:00
ZacharyZhang-NY 7000c95661 Revert "Write fcitx5 config as key=value so fcitx5 reads the Ctrl+Space trigger"
This reverts commit a84ad64c9e.
2026-10-08 23:48:13 -04:00
Spencer Bull 5c6444e604 Update cua-driver-bin to 0.33.4, which captures multi-monitor Hyprland desktops again (#807)
Driver 0.28.3 through 0.33.3 refused desktop capture on Hyprland with more than one output or one output away from the origin (trycua/cua#4161), which is why the package was held at 0.28.2; 0.33.4 fixes it (trycua/cua#4305). The plugin sources are unchanged from 0.32.0 through 0.33.4 and speak the same input protocol, so the plugin package stays and only its README names the new pairing.
2026-10-08 22:08:08 -05:00
Gabriel AramburuandClaude 17ae27fb21 Add OmaKeyboard: keyboard remapping and shortcuts (#564)
A Qt Quick application for remapping keys, building Fn-style layers and
managing shortcuts, per keyboard. It generates real XKB keymaps with
libxkbcommon and loads them through Hyprland's per-device kb_file; no
input daemon or third-party remapping engine is involved.

Builds from the published v0.1.0 tag. check() runs the project's tests,
which need no display.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-09 01:10:24 +00:00
Ryan Hughes 5abe08fbab Merge pull request #697 from omacom/auto/sync-rebuilds
chore: rebuild against updated dependencies
2026-10-08 19:39:59 -04:00
dhh 3a0d01876f chore: rebuild against updated dependencies 2026-10-08 23:32:58 +00:00
Emir Beganović 0aa4c721c1 Merge pull request #851 from omacom/t3code/appimage-lib-names
T3 Code: accept the AppImage's compatibility libraries under their new names
2026-10-09 00:36:48 +02:00
Marcelo Alcantara c71cfabed6 Re-pin omarchy-mac-boot to omarchy-mac-pkgs 162f3599e (#873)
main now has omarchy-mac-pkgs#20: a factory reset's reboot unlocks the disk
with a key from the Boot partition, and systemd could mount that partition
again just before switching to the real root without unmounting it
(systemd/systemd#28021), leaving /boot read-only so owner setup's re-key
failed. An initramfs drop-in makes the unmount finish before the switch. It
also has #18 (first-boot encryption progress on the splash) and test-only
changes (#11, #19). New UTC commit date, so 20261008-1. omarchy-mac stays at
2a3ed89.
2026-10-08 22:06:39 +00:00
Ryan Hughes 7d18e16925 Merge pull request #860 from omacom/auto/track-branches
Track upstream branches: omarchy-dev 4.0.0.r6815.g50d687a, omarchy-settings-dev 4.0.0.r6815.g50d687a
2026-10-08 16:23:28 -04:00
Ryan Hughes 2cce621d95 Retire the elephant packages and omarchy-walker (#872)
Omarchy 4 no longer uses Elephant or the omarchy-walker meta package, and
omarchy-upgrade-to-quattro removes them; every channel serves Omarchy 4.0.4.
Nothing else here depends on them. walker itself stays.

Deleting a recipe stops it building but leaves it in the channel databases,
and the only removal tool worked on the old repository host's local tree.
Add bin/unpublish-packages, publish-artifact's counterpart: pull the channel
database, repo-remove every entry built from the named pkgbases, upload it.
Package files stay in the bucket. unpublish.yml runs it per channel and
architecture under the publish lock, for packages with no recipe on master.
2026-10-08 16:18:30 -04:00
ryanrhughes 2ac2319b55 Track upstream branches: omarchy-dev 4.0.0.r6815.g50d687a, omarchy-settings-dev 4.0.0.r6815.g50d687a 2026-10-08 20:02:51 +00:00
Timothy Wright cb3909f052 Automate Grok Bot releases (#583)
* Automate Grok Bot releases

* Refresh Grok Bot to apt 0.66.0 and harden upstream.sh

Bump both architectures to Cursor apt 0.66.0 with matching SHA256s,
introduce a versioned _pool URL helper, and filter Packages stanzas by
Package: grok-bot so sync stays correct if the index grows.

* grok-bot: bump to 0.68.1, drop manual hold, validate pool filename

Bump both architectures to Cursor apt 0.68.1 with the SHA256s from the
amd64/arm64 Packages indexes (verified against the downloaded debs).

Drop grok-bot from the manual holds list in docs/upstream-sources.md and
have upstream.sh check that the newest stanza's Filename is the versioned
pool path the PKGBUILD downloads from. Both additions come from #848.
2026-10-08 15:50:44 -04:00
Ryan Hughes 678d7400ed Don't ask for a builder to rebuild what is already published (#870)
The split in #869 sent every tree without an artifact to the rebuild job,
so a dispatch whose x86 halves were already published waited eight minutes
for eleven droplets that each found nothing to build in five seconds. Make
the publish job's plan check in the changes job, on its hosted runner,
before a builder is requested.
2026-10-08 15:16:31 -04:00
Ryan Hughes ebd2d6a766 Publish in a minute: build outside the lock, sign on a hosted runner (#869)
A one-package merge took 9 to 15 minutes to publish for about 15 seconds of
signing and upload. The run-wide concurrency group made each merge wait for
every earlier run, builds included (#854 waited 13 minutes behind an aarch64
batch), and the publish job waited about 3 minutes for a builder droplet
even when every package had a PR artifact and nothing needed building.

Build x86_64 trees that have no artifact in the rebuild job, one droplet per
entry, as aarch64 already builds there on arm64 runners: in parallel, with
no secrets, and outside any lock. The publish job now only collects
artifacts, signs and uploads, on ubuntu-latest with the GHCR builder image
(#850), and only it holds the publish group.
2026-10-08 15:03:28 -04:00
Ryan Hughes 93b1655ca8 Auto-merge package PRs that bring their own test (#868)
#867 auto-merged only PRs changing nothing outside pkgbuilds/, so it would
have left #854 open too: like voxtype-bin and the IPU7 camera before it,
Superwhisper added tests/superwhisper-bin-install.sh and one test.yml line
running it.

Count those as package changes: a new file under tests/, and a test.yml
change whose every line adds a ./tests/*.sh call. test.yml runs on PRs only.
Editing an existing test still needs a maintainer, since builder-images.yml
runs tests/build-isolation.sh on master with packages: write.
2026-10-08 14:59:25 -04:00
Emir BeganovićandRyan Hughes 5d9783b85e Publish pulls the tested builder image instead of building it on every run (#850)
A builder droplet starts with no images, so publish.yml built
omarchy-pkg-builder from the Dockerfile each time: about 100 s of
pacstrap, keyring setup and toolchain install, to run gpg, repo-add,
bsdtar and rclone for about 14 s.

builder-images.yml already publishes the tested image for the current
build inputs to ghcr.io/omacom/omarchy-pkg-builder under bin/builder-image
key. Pull that, check its org.omarchy.builder.key label, and tag it as the
local name the rest of the step uses.

Build as before when no image carries the key, which is what a merge
that changes build/ sees until the refresh it triggered has finished.

Co-authored-by: Ryan Hughes <ryan@heyoodle.com>
2026-10-08 14:57:21 -04:00
Ryan Hughes 48d6217ff7 Auto-merge package PRs that are trusted to build (#867)
A package PR approved to build, by its author being trusted or by the
build-approved label, sat open after going green until someone merged it by
hand, so nothing it built was published. Enable GitHub's auto-merge on it
with PKGS_BOT_TOKEN, so the merge lands once the required checks pass and
starts publish.yml.

The trust rule is build-pr.yml's. Only PRs changing nothing outside
pkgbuilds/ qualify: a PR's own tooling never runs in its build, and after
merge it runs with the publish secrets. The upstream sync, which labels its
own PRs, stays on the reviewed lane. Removing build-approved withdraws the
auto-merge.
2026-10-08 14:33:54 -04:00
David Heinemeier Hansson 7d2c7c50af Package Superwhisper with upstream beta tracking (#854)
* Package Superwhisper with upstream beta tracking

* Seed fresh Superwhisper shortcuts before daemon startup

* Refresh checksum for Superwhisper user setup

* Fix Superwhisper panel setup and packaging review findings

* Read shell replies when retrying Superwhisper panel setup

* Exclude Superwhisper portable menu integration
2026-10-08 20:29:07 +02:00
Ryan Hughes e285432795 omatrack: fetch the pinned source from a copy, upstream is gone (#865)
tobi/omatrack no longer exists on GitHub, so the pinned commit's archive is
404 and 1.8.6 cannot be rebuilt; the old repository host's sync deleted the
published 1.8.6-1 from R2, leaving edge at 1.2.0. A public copy serves the
same commit with an archive matching the pinned sha256 byte for byte.

pkgrel 2 gives the rebuild a new filename, so no cache can serve the
deleted 1.8.6-1 bytes for it.
2026-10-08 13:38:28 -04:00
Ryan Hughes 5961a3ff5d Replace builder droplets stuck provisioning (#864)
A droplet DigitalOcean still reports as "new" never registers a runner, but
the controller counted it as one booting and created no replacement until
MAX_AGE_MINUTES. A publish job sat queued for minutes behind one in mkc1.

Delete droplets still provisioning after MAX_BOOT_MINUTES (10) and leave them
out of the live count, so the same tick creates a replacement.
2026-10-08 11:59:48 -04:00
Ryan Hughes 259a3fa8b8 quickshell-git: build v0.3.2, which compiles against Qt 6.12 (#863)
The pinned 0.3.0.r20 commit fails Qt 6.12's "Meta Types must be fully
defined" assertion in the PipeWire service, which kept the rebuild PR red.
2026-10-08 11:40:40 -04:00
37288aada4 Auto-merge rebuild PRs once their builds pass (#862)
sync-rebuilds now runs on the unattended lane like track-branches: it
opens the pkgrel bump PR with PKGS_BOT_TOKEN and enables auto-merge, so a
Qt (or any rebuild_on) update reaches users without a maintainer merge.
Branch protection still requires result, self-tests and build-isolation
to pass; a failed rebuild stays an open red PR.

The PAT is required because a GITHUB_TOKEN merge does not start
publish.yml. PAT pushes are not held for approval, so the approve job,
the build-approved label and the review request go away.

Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:08:41 -04:00
Ryan Hughes 128c5647ba Keep builders coming when DigitalOcean sells out a size or region (#861)
* Keep builders coming when DigitalOcean sells out a droplet size

ric1 sold out of g5-32vcpu-64gb-50gb, and every create came back 422. curl -f
dropped the reason and set -e ended the tick, so builders only appeared when
capacity happened to free up, and the journal showed nothing but "curl: (22)".

Try each of SIZES in turn, logging DigitalOcean's refusal message, and fail
the tick only when every size is refused. Builders now power off however
start.sh exits, so a failed registration is reaped instead of counting as a
booting runner until MAX_AGE_MINUTES. The controller unit pulls the checkout
before each tick, so merged controller fixes reach the box.

* Create builders in any region that has the size in stock

ric1 sold out of g5-32vcpu-128gb-50gb within minutes of the box switching to
it. Builders need nothing from a particular region, so read DigitalOcean's
size catalog once per tick and try each of SIZES in every region it lists in
stock, REGIONS first if set. A refused pair is dropped for the rest of the
tick.
2026-10-08 10:50:06 -04:00
David Heinemeier Hansson 024943141d Count the full builder queue across workflow states (#859) 2026-10-08 15:38:31 +02:00
David Heinemeier Hansson a1ad25bbae Bump releases for packages with mismatched cached archives (#858) 2026-10-08 15:01:06 +02:00
David Heinemeier HanssonandClaude Opus 5.5 77d62dd156 Add quickshell 0.3.2 built from upstream releases (#855)
Tracks tagged releases from the quickshell-mirror GitHub repository
through an upstream watch, so new versions arrive via sync-upstream.
The recipe follows Arch's extra/quickshell, builds for x86_64 and
aarch64, ships the Qt compatibility check hook, and rebuilds on Qt
updates like quickshell-git. It conflicts with quickshell-git.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:51:47 +02:00
David Heinemeier Hansson 7d70768c3f Retire redundant edge package overrides (#853)
* Prepare OPR overrides and rebuild Quickshell for Qt 6.12

* Retire redundant edge package overrides

* Drop Quickshell rebuild from retirement scope

* Remove retirement notes from upstream source documentation
2026-10-08 10:45:07 +02:00
Ryan Hughes efc09808c6 Merge pull request #852 from omacom/omarchy-hyprland-titlebars
Add omarchy-hyprland-titlebars
2026-10-08 02:35:38 -04:00
Ryan Hughes f004f5fa20 Merge pull request #788 from omacom/auto/track-branches
Track upstream branches: omarchy-dev 4.0.0.r6807.g902fd8a, omarchy-settings-dev 4.0.0.r6807.g902fd8a
2026-10-08 02:33:16 -04:00
ryanrhughes 963cbf1230 Track upstream branches: omarchy-dev 4.0.0.r6807.g902fd8a, omarchy-settings-dev 4.0.0.r6807.g902fd8a 2026-10-08 06:31:32 +00:00
Ryan HughesandClaude Opus 5.5 a57d0fdb7f Add omarchy-hyprland-titlebars
The native Hyprland plugin behind Omarchy's floating workspaces: themed
titlebars and edge snapping, built from a hyprbars fork. It is rebuilt
with every Hyprland change, since a plugin only loads into the exact
build it was compiled against.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 02:23:16 -04:00
Emir Beganovic 00a98d2aa7 T3 Code: accept the AppImage's compatibility libraries under their new names
The 2026-10-07 nightly ships the same six compatibility libraries with
their full versioned file names beside the short ones (libXss.so.1.0.0),
and two under their GTK 3 names (libappindicator3, libindicator3). The
guard in package() listed the short names only, so it stopped the build
on both architectures and with it the bundled upstream sync (#837).

Accept an optional 3 and trailing version numbers. Anything else in
usr/ still stops the build. t3code-bin carries the same guard and gets
the same pattern before the change reaches a stable release.
2026-10-08 03:06:40 +02:00
Emir Beganović d37fcd09d1 Merge pull request #849 from omacom/omasnap-git/smoke-output-dir
omasnap-git: give the smoke suite its output directory as --output-dir
2026-10-08 02:45:49 +02:00
Emir Beganovic c19b48c445 omasnap-git: give the smoke suite its output directory as --output-dir
Upstream's 6771b19 ("keep smoke artifacts in the build directory") made
omasnap-smoke reject positional paths; the directory is now passed with
--output-dir. check() still passed it positionally, so every build of a
pin at or past that commit failed with "Unexpected positional argument;
use --output-dir <directory>."

Pass it as --output-dir and move the pin to 6771b19, the tip the branch
tracker has been trying to merge since October 4. The two have to land
together: the old pin does not know --output-dir.
2026-10-08 00:49:37 +02:00
Krzysztof Wilczyński 0e90a7652b Merge pull request #846 from kwilczynski/feature/add-muqss-version
Add MuQSS kernel based on v7.2.8-5 with latest MuQSS from CK tree
2026-10-07 23:52:36 +02:00
Krzysztof Wilczyński 4b6cc8ba0f Add MuQSS kernel based on v7.2.8-5 with latest MuQSS from CK tree
Signed-off-by: Krzysztof Wilczyński <kwilczynski@omarchy.org>
2026-10-08 05:43:59 +09:00
David Heinemeier Hansson 2d56129a55 Keep OWE lock feed in its separate package (#844) 2026-10-07 21:34:00 +02:00
David Heinemeier Hansson fe4b80b0a6 Update OWE to 0.2.10 and package its lock feed (#843)
* Update OWE to 0.2.10 and package its lock feed

* Print OWE regression failures during package checks

* Make OWE package regression independent of timestamp precision
2026-10-07 21:11:46 +02:00
ZacharyZhang-NY a84ad64c9e Write fcitx5 config as key=value so fcitx5 reads the Ctrl+Space trigger 2026-10-06 01:49:27 -04:00
ZacharyZhang-NY 5e0ff0df95 Add rime-ice-installer with offline assets and no sudo when its packages are present 2026-10-05 23:32:21 -04:00
479 changed files with 145625 additions and 1397 deletions

No files matched your search

+84
View File
@@ -0,0 +1,84 @@
// Whether a PR rides to master on its own once the required checks pass.
//
// The rule is the build gate's, from build-pr.yml: a PR trusted to build is
// trusted to ship. Collaborators, vouched authors and bots are trusted; an
// unknown author is trusted while the PR carries build-approved; a
// denouncement is absolute. Two limits on top of it:
//
// - Only package changes. A PR's workflows, scripts and build tooling never
// run in its own build (build-pr.yml overlays only its package directories
// onto base tooling), so green checks say nothing about them, and after
// merge they run with the publish secrets. Allowed: anything under
// pkgbuilds/, plus the test a package PR brings with it, which is a new
// file under tests/ and lines in test.yml that only run new tests/*.sh.
// test.yml runs on PRs only; an existing test may also run on master
// (builder-images.yml runs tests/build-isolation.sh with packages: write),
// so editing one still needs a maintainer.
// - Not the upstream sync. It labels its own PR build-approved to release
// GitHub's hold on its pushes, which is no one's approval; it stays on the
// reviewed lane.
const PACKAGES = 'pkgbuilds/';
const TESTS = 'tests/';
const TEST_WORKFLOW = '.github/workflows/test.yml';
const TEST_LINE = /^\+\s*\.\/tests\/[A-Za-z0-9._-]+\.sh\s*$/;
// Every changed line adds a ./tests/<name>.sh call; nothing removed. A diff
// too large for the API has no patch and does not qualify.
function onlyRunsTests(patch) {
if (!patch) return false;
const changed = patch.split('\n').filter(line =>
/^[+-]/.test(line) && !line.startsWith('+++') && !line.startsWith('---'));
return changed.length > 0 && changed.every(line => TEST_LINE.test(line));
}
function packageChange(file) {
if (file.previous_filename && !file.previous_filename.startsWith(PACKAGES)) return false;
if (file.filename.startsWith(PACKAGES)) return true;
if (file.filename.startsWith(TESTS)) return file.status === 'added';
if (file.filename === TEST_WORKFLOW) return file.status === 'modified' && onlyRunsTests(file.patch);
return false;
}
const REVIEWED_BRANCHES = /^auto\/sync-upstream(\/|$)/;
function decide({ pr, files, vouchStatus, repository }) {
if (pr.state !== 'open') return { enable: false, reason: 'PR is not open' };
if (pr.draft) return { enable: false, reason: 'PR is a draft' };
const labelled = pr.labels.some(label => label.name === 'build-approved');
let trusted;
switch (vouchStatus) {
case 'bot': case 'collaborator': case 'vouched': trusted = true; break;
case 'unknown': trusted = labelled; break;
default: trusted = false; // denounced, or a failed lookup
}
if (!trusted) {
return { enable: false, reason: `author not trusted to build (${vouchStatus || 'missing'}${labelled ? ', labelled' : ''})` };
}
if (pr.head.repo?.full_name === repository && REVIEWED_BRANCHES.test(pr.head.ref)) {
return { enable: false, reason: `${pr.head.ref} stays on the reviewed lane` };
}
if (!files.length) return { enable: false, reason: 'PR changes no files' };
const outside = files.filter(file => !packageChange(file));
if (outside.length) {
const names = outside.slice(0, 3).map(file => file.filename).join(', ');
return { enable: false, reason: `changes more than packages and their new tests: ${names}${outside.length > 3 ? ', ...' : ''}` };
}
return { enable: true, reason: `${vouchStatus === 'unknown' ? 'build-approved' : vouchStatus} author, package changes only` };
}
module.exports = async function autoMerge({ github, context, core, number, vouchStatus }) {
const { data: pr } = await github.rest.pulls.get({ ...context.repo, pull_number: number });
const files = await github.paginate(github.rest.pulls.listFiles, {
...context.repo, pull_number: number, per_page: 100,
});
const decision = decide({
pr, files, vouchStatus, repository: `${context.repo.owner}/${context.repo.repo}`,
});
core.info(`#${number}: ${decision.enable ? 'auto-merge' : 'leave for a maintainer'} (${decision.reason})`);
core.setOutput('enable', String(decision.enable));
core.setOutput('head_sha', pr.head.sha);
return decision;
};
module.exports.decide = decide;
+108
View File
@@ -0,0 +1,108 @@
name: Auto-merge approved package PRs
# A package PR trusted to build is trusted to ship: once its builds are
# green it should merge and publish without a maintainer pressing the
# button. This enables GitHub's auto-merge on such PRs; branch protection
# still holds the merge until `result`, `self-tests` and `build-isolation`
# pass, and a red build stays an open PR. .github/scripts/auto-merge-pr.cjs
# has the rule.
#
# Auto-merge is enabled with the PAT in PKGS_BOT_TOKEN: a merge made with the
# built-in GITHUB_TOKEN does not start publish.yml.
#
# pull_request_target runs this default-branch code with secrets; the PR's
# code is never checked out here.
on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review, labeled, unlabeled]
workflow_dispatch:
inputs:
pr:
description: 'PR number to evaluate'
required: true
permissions:
contents: read
pull-requests: read
concurrency:
group: auto-merge-pr-${{ github.event.pull_request.number || github.event.inputs.pr }}
cancel-in-progress: true
jobs:
auto-merge:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
- name: Find the PR's author
id: pr
uses: actions/github-script@v7
env:
NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr }}
with:
script: |
const { data: pr } = await github.rest.pulls.get({
...context.repo, pull_number: Number(process.env.NUMBER),
});
core.setOutput('number', String(pr.number));
core.setOutput('author', pr.user.login);
- id: vouch
uses: mitchellh/vouch/action/check-user@f23dbb5e745334f97414ec70463ce7301071a661 # v1
with:
user: ${{ steps.pr.outputs.author }}
allow-fail: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Decide
id: decide
uses: actions/github-script@v7
env:
NUMBER: ${{ steps.pr.outputs.number }}
VOUCH_STATUS: ${{ steps.vouch.outputs.status }}
with:
script: |
const autoMerge = require('./.github/scripts/auto-merge-pr.cjs');
await autoMerge({ github, context, core,
number: Number(process.env.NUMBER), vouchStatus: process.env.VOUCH_STATUS });
- name: Enable auto-merge
if: steps.decide.outputs.enable == 'true'
env:
GH_TOKEN: ${{ secrets.PKGS_BOT_TOKEN }}
PR: ${{ steps.pr.outputs.number }}
HEAD_SHA: ${{ steps.decide.outputs.head_sha }}
run: |
if [[ -z "$GH_TOKEN" ]]; then
echo "::error::Set PKGS_BOT_TOKEN; a GITHUB_TOKEN merge would not publish."
exit 1
fi
# Idempotent: enabling twice errors. Bot lanes enable their own.
if [[ "$(gh pr view "$PR" -R "$GITHUB_REPOSITORY" --json autoMergeRequest --jq '.autoMergeRequest != null')" == true ]]; then
echo "auto-merge already enabled on #$PR"
exit 0
fi
# --match-head-commit: never arm a merge for a commit newer than
# the one just judged.
gh pr merge --auto --squash --match-head-commit "$HEAD_SHA" "$PR" -R "$GITHUB_REPOSITORY"
# Removing build-approved withdraws the approval, so withdraw the
# auto-merge it armed too. Only on that event: auto-merge a maintainer
# enabled by hand on any other PR is theirs to keep.
- name: Withdraw auto-merge
if: >-
steps.decide.outputs.enable == 'false' &&
github.event.action == 'unlabeled' && github.event.label.name == 'build-approved'
env:
GH_TOKEN: ${{ secrets.PKGS_BOT_TOKEN }}
PR: ${{ steps.pr.outputs.number }}
run: |
if [[ "$(gh pr view "$PR" -R "$GITHUB_REPOSITORY" --json autoMergeRequest --jq '.autoMergeRequest != null')" == true ]]; then
gh pr merge --disable-auto "$PR" -R "$GITHUB_REPOSITORY"
fi
+71 -48
View File
@@ -24,11 +24,10 @@ on:
description: "Space-separated package directories to publish from master" description: "Space-separated package directories to publish from master"
required: true required: true
# Merges serialize. Two publishes into one channel at once would race on # Only the publish job serializes (see its concurrency group): two publishes
# the database; queued is fine, cancelled is not. # into one channel at once would race on the database. Builds run outside the
concurrency: # lock, so a merge waits behind another merge's signing and upload, seconds,
group: publish # never behind its kernel build.
cancel-in-progress: false
jobs: jobs:
changes: changes:
@@ -58,11 +57,10 @@ jobs:
echo "matrix=$matrix" >> "$GITHUB_OUTPUT" echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
echo "count=$(jq '.include | length' <<<"$matrix")" >> "$GITHUB_OUTPUT" echo "count=$(jq '.include | length' <<<"$matrix")" >> "$GITHUB_OUTPUT"
jq -r '.include[] | "\(.package) \(.arch) -> \(.channels)"' <<<"$matrix" jq -r '.include[] | "\(.package) \(.arch) -> \(.channels)"' <<<"$matrix"
# Reuse or rebuild, decided per entry and said out loud. An aarch64 # Reuse or rebuild, decided per entry and said out loud. A tree with
# tree with no build artifact (PR artifacts last 7 days; a dispatch # no build artifact (PR artifacts last 7 days; a dispatch may name
# may name any package) goes to the rebuild job, which builds it # any package) goes to the rebuild job: aarch64 natively on GitHub's
# natively on GitHub's arm64 runner. x86_64 builds inside the # arm64 runner, x86_64 on a builder droplet, one runner per entry.
# publish job on the droplet, as before.
rebuild=() rebuild=()
echo "| package | arch | tree | decision |" >> "$GITHUB_STEP_SUMMARY" echo "| package | arch | tree | decision |" >> "$GITHUB_STEP_SUMMARY"
echo "| --- | --- | --- | --- |" >> "$GITHUB_STEP_SUMMARY" echo "| --- | --- | --- | --- |" >> "$GITHUB_STEP_SUMMARY"
@@ -73,13 +71,23 @@ jobs:
found=$(curl -fsS -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \ found=$(curl -fsS -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/actions/artifacts?name=$label&per_page=5" \ "https://api.github.com/repos/${{ github.repository }}/actions/artifacts?name=$label&per_page=5" \
| jq -r '[.artifacts[] | select(.expired|not)] | sort_by(.created_at) | last | select(. != null) | "run \(.workflow_run.id), expires \(.expires_at)"') | jq -r '[.artifacts[] | select(.expired|not)] | sort_by(.created_at) | last | select(. != null) | "run \(.workflow_run.id), expires \(.expires_at)"')
# The plan the publish job makes, made here before a runner is
# asked for: a tree the channel already holds at master's version
# (a re-run, or a dispatch naming a package that is fine) needs
# no build, and an x86 rebuild would wait minutes for a droplet
# to find that out in seconds.
plan=""
[[ -n "$found" ]] || plan=$(bin/build --dry-run --mirror edge --arch "$arch" --package "$package" 2>&1 | grep -E '^==> Plan complete' || true)
if [[ -n "$found" ]]; then if [[ -n "$found" ]]; then
decision="reuse the build artifact ($found)" decision="reuse the build artifact ($found)"
elif [[ -n "$plan" && -z "$(sed -E 's/.*would build: *//' <<<"$plan" | tr -d '[:space:]')" ]]; then
decision="already published at master's version, nothing to build"
elif [[ $arch == aarch64 ]]; then elif [[ $arch == aarch64 ]]; then
decision="no build artifact: rebuild natively on ubuntu-24.04-arm" decision="no build artifact: rebuild natively on ubuntu-24.04-arm"
rebuild+=("$entry") rebuild+=("$(jq -c '. + {runner: "[\"ubuntu-24.04-arm\"]"}' <<<"$entry")")
else else
decision="no build artifact: build in the publish job on the self-hosted builder" decision="no build artifact: rebuild on a builder droplet"
rebuild+=("$(jq -c '. + {runner: "[\"self-hosted\",\"omarchy-builder\"]"}' <<<"$entry")")
fi fi
echo "==> $label: $decision" echo "==> $label: $decision"
echo "| $package | $arch | ${hash:0:12} | $decision |" >> "$GITHUB_STEP_SUMMARY" echo "| $package | $arch | ${hash:0:12} | $decision |" >> "$GITHUB_STEP_SUMMARY"
@@ -87,16 +95,19 @@ jobs:
echo "rebuild=$(printf '%s\n' "${rebuild[@]}" | jq -sc '{include: .}')" >> "$GITHUB_OUTPUT" echo "rebuild=$(printf '%s\n' "${rebuild[@]}" | jq -sc '{include: .}')" >> "$GITHUB_OUTPUT"
echo "rebuild_count=${#rebuild[@]}" >> "$GITHUB_OUTPUT" echo "rebuild_count=${#rebuild[@]}" >> "$GITHUB_OUTPUT"
# The aarch64 half of "build it now when there is none". It builds exactly # "Build it now when there is none". Each entry builds exactly as
# as build-pr.yml's aarch64 path does (same runner, same builder image, # build-pr.yml builds it (same runner kind, same builder image, same
# same bin/build call) and uploads under the same label, so the publish # bin/build call) and uploads under the same label, so the publish job
# job collects this run's artifact the way it collects a PR's. No secret # collects this run's artifact the way it collects a PR's. No secret
# reaches this runner; signing and upload stay on the self-hosted builder. # reaches these runners, and they hold no lock: entries build in parallel,
# and other merges publish while they do.
rebuild: rebuild:
needs: changes needs: changes
if: needs.changes.outputs.rebuild_count != '0' if: needs.changes.outputs.rebuild_count != '0'
runs-on: ubuntu-24.04-arm runs-on: ${{ fromJSON(matrix.runner) }}
timeout-minutes: 180 # The droplets are x86, so aarch64 never builds there. omarchy-mac-boot
# under QEMU took 2h47m; native arm64 and x86 kernels fit easily.
timeout-minutes: 240
permissions: permissions:
contents: read contents: read
strategy: strategy:
@@ -109,7 +120,7 @@ jobs:
# The same check the publish job makes before building: a re-run for a # The same check the publish job makes before building: a re-run for a
# package the channel already holds at master's version builds # package the channel already holds at master's version builds
# nothing, and uploads nothing that could shadow the published file. # nothing, and uploads nothing that could shadow the published file.
- name: Build ${{ matrix.package }} (${{ matrix.arch }}, native) - name: Build ${{ matrix.package }} (${{ matrix.arch }})
id: build id: build
env: env:
CONTAINER_ENGINE: docker CONTAINER_ENGINE: docker
@@ -140,23 +151,26 @@ jobs:
if-no-files-found: error if-no-files-found: error
retention-days: 7 retention-days: 7
# One job for the whole merge. It collects every PR artifact for the # One job for the whole merge. It collects every artifact for the merged
# merged tree (building only what has none; aarch64 comes from the # tree (PR builds, or the rebuild job above), then walks each channel and
# rebuild job above), then walks each channel and
# architecture slot exactly once: pull that database, add every package # architecture slot exactly once: pull that database, add every package
# that belongs in it, upload. Six slots, six round trips, however many # that belongs in it, upload. Six slots, six round trips, however many
# packages the merge carried. One process is the only writer, so there # packages the merge carried. One process is the only writer, so there
# is no race between packages; the run-level concurrency group above # is no race between packages; the concurrency group keeps one merge's
# keeps one merge from overlapping the next. # publish from overlapping the next. It builds nothing, so it runs on a
# hosted runner in about a minute instead of waiting for a droplet.
# It waits for the rebuild job and runs whatever that job's result: a # It waits for the rebuild job and runs whatever that job's result: a
# failed rebuild leaves its package without an artifact, and the collect # failed rebuild leaves its package without an artifact, and the collect
# step below records that and stops before any publish. # step below records that and stops before any publish.
publish: publish:
needs: [changes, rebuild] needs: [changes, rebuild]
if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.count != '0' }} if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.count != '0' }}
runs-on: [self-hosted, omarchy-builder] runs-on: ubuntu-latest
environment: publish environment: publish
timeout-minutes: 240 timeout-minutes: 30
concurrency:
group: publish
cancel-in-progress: false
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -172,8 +186,8 @@ jobs:
EOF_MATRIX EOF_MATRIX
cat plan.txt cat plan.txt
# Fetch each package's PR artifact into build-output/edge/<arch>/, or # Fetch each package's artifact into build-output/edge/<arch>/: the PR's,
# build it when no artifact exists for exactly this tree. An artifact # or the rebuild job's when the PR's had expired. An artifact
# carries its package files inside packages.tar (see build-pr.yml and # carries its package files inside packages.tar (see build-pr.yml and
# helpers/artifact-helpers.sh: the upload action rejects the colon in # helpers/artifact-helpers.sh: the upload action rejects the colon in
# an epoch filename). # an epoch filename).
@@ -199,8 +213,8 @@ jobs:
mkdir -p "build-output/edge/$arch" mkdir -p "build-output/edge/$arch"
if [[ -n "$found" ]]; then if [[ -n "$found" ]]; then
if [[ $from_run == "${{ github.run_id }}" ]]; then if [[ $from_run == "${{ github.run_id }}" ]]; then
kind=native-rebuild kind=rebuild
echo "==> $label: artifact from this run's native $arch rebuild" echo "==> $label: artifact from this run's $arch rebuild"
else else
kind=pr-artifact kind=pr-artifact
echo "==> $label: reusing the build artifact from run $from_run" echo "==> $label: reusing the build artifact from run $from_run"
@@ -225,20 +239,11 @@ jobs:
jq -nc --arg p "$package" --arg a "$arch" '{package:$p, arch:$a, source:"already-published"}' >> sources.jsonl jq -nc --arg p "$package" --arg a "$arch" '{package:$p, arch:$a, source:"already-published"}' >> sources.jsonl
continue continue
fi fi
# aarch64 never builds here: this droplet is x86 and would # Nothing builds here. No artifact means the rebuild failed (see
# emulate it. No artifact means the native rebuild failed (see # the rebuild job), or an artifact expired between planning and
# the rebuild job), or an artifact expired between planning # now (re-run all jobs).
# and now (re-run all jobs). echo "::error::$label: no artifact from the rebuild job"
if [[ $arch == aarch64 ]]; then jq -nc --arg p "$package" --arg a "$arch" '{package:$p, arch:$a, source:"build-failed"}' >> sources.jsonl; failed=1; break
echo "::error::$label: no artifact from the native rebuild; not building aarch64 under emulation"
jq -nc --arg p "$package" --arg a "$arch" '{package:$p, arch:$a, source:"native-build-failed"}' >> sources.jsonl; failed=1; break
fi
echo "==> $label: no artifact for this tree, building"
if OMARCHY_KEEP_BUILD_WORKSPACE=1 bin/build --mirror edge --arch "$arch" --package "$package"; then
jq -nc --arg p "$package" --arg a "$arch" '{package:$p, arch:$a, source:"built"}' >> sources.jsonl
else
jq -nc --arg p "$package" --arg a "$arch" '{package:$p, arch:$a, source:"build-failed"}' >> sources.jsonl; failed=1; break
fi
fi fi
done < plan.txt done < plan.txt
ls -1 build-output/edge/*/*.pkg.tar.zst 2>/dev/null || true ls -1 build-output/edge/*/*.pkg.tar.zst 2>/dev/null || true
@@ -280,8 +285,26 @@ jobs:
cat publish-record.json cat publish-record.json
exit 0 exit 0
fi fi
docker image inspect omarchy-pkg-builder:latest-x86_64-edge >/dev/null 2>&1 \ # A fresh runner has no images, and building this one here cost
|| docker buildx build --load -t omarchy-pkg-builder:latest-x86_64-edge --build-arg MIRROR=edge build # every publish about 100 s (and 20 s more to start a container
# from it) for the 14 s of signing and upload it is needed for.
# builder-images.yml already publishes the tested image for exactly
# these build inputs under their key; pull that. Build only when no
# image carries the key: a merge that changed build/ publishes
# before the refresh it triggered has finished.
builder=omarchy-pkg-builder:latest-x86_64-edge
if ! docker image inspect "$builder" >/dev/null 2>&1; then
key=$(bin/builder-image key --arch x86_64 --mirror edge)
published="ghcr.io/omacom/omarchy-pkg-builder:$key"
if docker pull --quiet "$published" &&
[[ $(docker image inspect "$published" --format '{{index .Config.Labels "org.omarchy.builder.key"}}') == "$key" ]]; then
docker tag "$published" "$builder"
echo "==> Builder image: pulled $published"
else
echo "==> Builder image: none published for $key, building it"
docker buildx build --load -t "$builder" --build-arg MIRROR=edge build
fi
fi
# Group the merge's files by the (channel, architecture) slot each # Group the merge's files by the (channel, architecture) slot each
# belongs to. A package's files live under build-output/edge/<built # belongs to. A package's files live under build-output/edge/<built
@@ -374,7 +397,7 @@ jobs:
run: | run: |
jq -r --arg outcome "${{ needs.publish.result }}" ' jq -r --arg outcome "${{ needs.publish.result }}" '
def pkgs: [.packages[] | select(test("-debug-")|not)] | join(", "); def pkgs: [.packages[] | select(test("-debug-")|not)] | join(", ");
def src: if .source=="pr-artifact" then "PR artifact" elif .source=="native-rebuild" then "rebuilt natively on arm64" elif .source=="built" then "built here" elif .source=="already-published" then "already published, skipped" else "**" + .source + "**" end; def src: if .source=="pr-artifact" then "PR artifact" elif .source=="rebuild" or .source=="native-rebuild" then "rebuilt at merge" elif .source=="built" then "built here" elif .source=="already-published" then "already published, skipped" else "**" + .source + "**" end;
"### Publish " + (if $outcome=="success" then "succeeded" else "FAILED" end) + "### Publish " + (if $outcome=="success" then "succeeded" else "FAILED" end) +
" → **" + .target + "**" + (if .target!="live" then " (proof prefix, not live)" else "" end), " → **" + .target + "**" + (if .target!="live" then " (proof prefix, not live)" else "" end),
"", "",
+38 -53
View File
@@ -1,5 +1,14 @@
name: Sync Rebuild Triggers name: Sync Rebuild Triggers
# Rebuilds ride the unattended lane, like track-branches.yml: the pkgrel bump
# PR builds on the droplets, auto-merge lands it once `result`, `self-tests`
# and `build-isolation` are green, and the merge publishes. A rebuild that
# fails stays an unmerged red PR for a maintainer.
#
# The PR and auto-merge use the PAT in PKGS_BOT_TOKEN, because a merge made
# with the built-in GITHUB_TOKEN does not start publish.yml, and its pushes
# are held for approval instead of building.
on: on:
schedule: schedule:
# Every 6 hours, off the hour to dodge the scheduling backlog at :00 # Every 6 hours, off the hour to dodge the scheduling backlog at :00
@@ -17,14 +26,17 @@ jobs:
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
outputs:
branch: ${{ steps.branch.outputs.branch }}
pushed_at: ${{ steps.pushed.outputs.at }}
number: ${{ steps.cpr.outputs.pull-request-number }}
operation: ${{ steps.cpr.outputs.pull-request-operation }}
head_sha: ${{ steps.cpr.outputs.pull-request-head-sha }}
steps: steps:
- name: Require the bot token
env:
PKGS_BOT_TOKEN: ${{ secrets.PKGS_BOT_TOKEN }}
run: |
if [[ -z "$PKGS_BOT_TOKEN" ]]; then
echo "::error::Set PKGS_BOT_TOKEN to a PAT with Contents: write and Pull requests: write on this repository, owned by an account trusted to trigger builds."
exit 1
fi
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
@@ -85,19 +97,12 @@ jobs:
echo "has_changes=true" >> "$GITHUB_OUTPUT" echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi fi
# Runs created by this push are newer than this; the approve job
# waits for them. A minute's slack absorbs runner clock skew.
- name: Record push time
if: steps.changes.outputs.has_changes == 'true'
id: pushed
run: echo "at=$(date -u -d '-1 minute' +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
- name: Create Pull Request - name: Create Pull Request
if: steps.changes.outputs.has_changes == 'true' if: steps.changes.outputs.has_changes == 'true'
id: cpr id: cpr
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v7
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.PKGS_BOT_TOKEN }}
commit-message: 'chore: rebuild against updated dependencies' commit-message: 'chore: rebuild against updated dependencies'
title: "chore: rebuild against updated dependencies${{ steps.branch.outputs.scope && format(' ({0})', steps.branch.outputs.scope) || '' }}" title: "chore: rebuild against updated dependencies${{ steps.branch.outputs.scope && format(' ({0})', steps.branch.outputs.scope) || '' }}"
body: | body: |
@@ -109,14 +114,27 @@ jobs:
bump is what makes the rebuilt package an upgrade pacman will offer; bump is what makes the rebuilt package an upgrade pacman will offer;
without it the build produces the version already published and no without it the build produces the version already published and no
one receives it. one receives it.
This PR auto-merges once the build checks pass. A failing rebuild
leaves it open for a maintainer.
branch: ${{ steps.branch.outputs.branch }} branch: ${{ steps.branch.outputs.branch }}
delete-branch: true delete-branch: true
# The bot is trusted; build-approved lets the approve job below labels: automated
# release GitHub's hold on its pushes without a maintainer.
labels: | # Auto-merge, not a direct merge: branch protection still has to see
automated # the build checks green before the rebuild lands.
build-approved - name: Enable auto-merge
reviewers: ryanrhughes if: steps.cpr.outputs.pull-request-number != ''
env:
GH_TOKEN: ${{ secrets.PKGS_BOT_TOKEN }}
PR: ${{ steps.cpr.outputs.pull-request-number }}
run: |
# Idempotent across re-runs of an updated PR: enabling twice errors.
if [[ "$(gh pr view "$PR" -R "${{ github.repository }}" --json autoMergeRequest --jq '.autoMergeRequest != null')" == true ]]; then
echo "auto-merge already enabled on #$PR"
exit 0
fi
gh pr merge --auto --merge "$PR" -R "${{ github.repository }}"
- name: Notify Basecamp on failure - name: Notify Basecamp on failure
if: failure() && env.BASECAMP_CHATBOT_URL != '' if: failure() && env.BASECAMP_CHATBOT_URL != ''
@@ -129,36 +147,3 @@ jobs:
"🔴 <strong>Rebuild trigger sync failed</strong><br><a href=\"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\">View run</a>" \ "🔴 <strong>Rebuild trigger sync failed</strong><br><a href=\"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\">View run</a>" \
'{content: $content}')" \ '{content: $content}')" \
"$BASECAMP_CHATBOT_URL" "$BASECAMP_CHATBOT_URL"
# GitHub holds pull_request runs from a GITHUB_TOKEN push for approval and
# creates no pull_request_target run for it, so approve-pr.yml never sees
# the sync's own pushes. The sync labels its PR build-approved, so release
# the held runs for the commit just pushed, whether it opened the PR or
# updated it. A separate job, so the sync container's token never holds
# actions: write.
approve:
needs: sync
if: ${{ !cancelled() && (needs.sync.outputs.operation == 'created' || needs.sync.outputs.operation == 'updated') }}
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
actions: write
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Release held build and test runs
uses: actions/github-script@v7
env:
NUMBER: ${{ needs.sync.outputs.number }}
BRANCH: ${{ needs.sync.outputs.branch }}
HEAD_SHA: ${{ needs.sync.outputs.head_sha }}
SINCE: ${{ needs.sync.outputs.pushed_at }}
with:
script: |
const approve = require('./.github/scripts/approve-sync-push.cjs');
const { NUMBER, BRANCH, HEAD_SHA, SINCE } = process.env;
await approve({ github, context, core, number: Number(NUMBER),
branch: BRANCH, headSha: HEAD_SHA, since: SINCE });
+1
View File
@@ -67,6 +67,7 @@ jobs:
./tests/artifact-helpers.sh ./tests/artifact-helpers.sh
./tests/limine-mkinitcpio-hook.sh ./tests/limine-mkinitcpio-hook.sh
./tests/voxtype-bin-install.sh ./tests/voxtype-bin-install.sh
./tests/superwhisper-bin-install.sh
pacman -S --noconfirm --quiet rclone >/dev/null pacman -S --noconfirm --quiet rclone >/dev/null
./tests/publish-artifact.sh ./tests/publish-artifact.sh
' '
+79
View File
@@ -0,0 +1,79 @@
name: Unpublish retired packages
# Takes packages out of the channel databases after their recipes are gone
# from master. Deleting a recipe stops it building; this stops pacman
# offering it. Files stay in the bucket (see bin/unpublish-packages).
#
# Only packages with no recipe on master: one that still has a recipe would
# come back on its next publish, and refusing it keeps a typo from pulling a
# live package out of every channel.
on:
workflow_dispatch:
inputs:
packages:
description: "Space-separated pkgbases whose recipes were removed from master"
required: true
channels:
description: "Channels to remove them from"
required: true
default: "edge rc stable"
jobs:
unpublish:
runs-on: ubuntu-latest
environment: publish
timeout-minutes: 15
# The publish job's group: one writer per channel database at a time.
concurrency:
group: publish
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Refuse packages that still have a recipe
env:
PACKAGES: ${{ github.event.inputs.packages }}
CHANNELS: ${{ github.event.inputs.channels }}
run: |
set -euo pipefail
for c in $CHANNELS; do
[[ $c == edge || $c == rc || $c == stable ]] || { echo "::error::Unknown channel: $c"; exit 1; }
done
for p in $PACKAGES; do
[[ $p =~ ^[a-z0-9@._+-]+$ ]] || { echo "::error::Not a package name: $p"; exit 1; }
if [[ -e pkgbuilds/$p ]]; then
echo "::error::pkgbuilds/$p still exists on master; remove the recipe first"
exit 1
fi
done
- name: Unpublish
env:
PACKAGES: ${{ github.event.inputs.packages }}
CHANNELS: ${{ github.event.inputs.channels }}
RCLONE_CONFIG_R2_TYPE: s3
RCLONE_CONFIG_R2_PROVIDER: Cloudflare
RCLONE_CONFIG_R2_NO_CHECK_BUCKET: "true"
RCLONE_CONFIG_R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
RCLONE_CONFIG_R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
RCLONE_CONFIG_R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
OMARCHY_PUBLISH_PREFIX: ${{ vars.OMARCHY_PUBLISH_PREFIX }}
run: |
set -euo pipefail
# repo-remove and bsdtar are Arch tools: run in the tested builder
# image, as the publish job does.
builder=ghcr.io/omacom/omarchy-pkg-builder:$(bin/builder-image key --arch x86_64 --mirror edge)
docker pull --quiet "$builder"
for mirror in $CHANNELS; do
for arch in x86_64 aarch64; do
docker run --rm \
-e OMARCHY_PUBLISH_PREFIX \
-e RCLONE_CONFIG_R2_TYPE -e RCLONE_CONFIG_R2_PROVIDER -e RCLONE_CONFIG_R2_ENDPOINT -e RCLONE_CONFIG_R2_NO_CHECK_BUCKET \
-e RCLONE_CONFIG_R2_ACCESS_KEY_ID -e RCLONE_CONFIG_R2_SECRET_ACCESS_KEY \
-v "$PWD:/w:ro" -w /w "$builder" \
bin/unpublish-packages --remote R2:omarchy-pkgs --mirror "$mirror" --arch "$arch" $PACKAGES
done
done
+35 -8
View File
@@ -565,12 +565,26 @@ bin/repo deploy # Build locally, then publish from the host
bin/repo push # Upload local builds to the host and publish bin/repo push # Upload local builds to the host and publish
bin/add-package <package> # Add an Omarchy-owned package with metadata bin/add-package <package> # Add an Omarchy-owned package with metadata
bin/package-worktree <package> # Inspect historical AUR provenance in a scratch workspace bin/package-worktree <package> # Inspect historical AUR provenance in a scratch workspace
bin/repo remove <package> # Remove package bin/repo remove <package> # Remove package (host workflow; CI uses unpublish.yml)
bin/sync-upstream # Update packages that track a vendor release feed bin/sync-upstream # Update packages that track a vendor release feed
bin/sync-rebuilds # Bump pkgrel for packages whose dependencies moved bin/sync-rebuilds # Bump pkgrel for packages whose dependencies moved
bin/clean-docker # Clear Docker images/cache (forces fresh rebuild) bin/clean-docker # Clear Docker images/cache (forces fresh rebuild)
``` ```
### Retiring a package
Delete its recipe directory in a PR. Once that merges, take it out of the
channel databases with the **Unpublish retired packages** workflow:
```
gh workflow run unpublish.yml -f packages="<pkgbase> ..." -f channels="edge rc stable"
```
It removes every entry built from those pkgbases (split outputs and `-debug`
included) from both architectures' databases, and refuses any package that
still has a recipe on master. Package files stay in the bucket: published
filenames are immutable, and nothing references them once the entries are gone.
### Package Metadata Tools ### Package Metadata Tools
```bash ```bash
@@ -893,15 +907,15 @@ The repository includes GitHub workflows and systemd services for automated rele
#### GitHub Workflows #### GitHub Workflows
1. **sync-upstream.yml** (Every 6 hours): Watches direct upstream feeds and updates owned recipes on the reviewed lane. Successful package updates reach a PR even if another feed fails; failed recipes stay untouched and the workflow remains red. 1. **sync-upstream.yml** (Every 6 hours): Watches direct upstream feeds and updates owned recipes on the reviewed lane. Successful package updates reach a PR even if another feed fails; failed recipes stay untouched and the workflow remains red.
2. **sync-rebuilds.yml** (Every 6 hours): Bumps pkgrel for packages whose `rebuild_on` dependencies have moved in the official repositories and opens a PR. 2. **sync-rebuilds.yml** (Every 6 hours): Bumps pkgrel for packages whose `rebuild_on` dependencies have moved in the official repositories, opens a PR, and enables auto-merge. The PR lands once its build checks pass; a rebuild that fails stays an open red PR for a maintainer.
3. **track-branches.yml** (Every 2 hours): The unattended lane. Pins every `"auto_merge": true` package to the tip of its watched branch once its commit timestamp clears `min_release_age`, opens one PR for all of them, and enables auto-merge. Packages pinned from the same branch move together or not at all, including targeted syncs. The PR builds like any other; a tip that fails to build stays an open red PR until the next tick supersedes it. 3. **track-branches.yml** (Every 2 hours): The unattended lane. Pins every `"auto_merge": true` package to the tip of its watched branch once its commit timestamp clears `min_release_age`, opens one PR for all of them, and enables auto-merge. Packages pinned from the same branch move together or not at all, including targeted syncs. The PR builds like any other; a tip that fails to build stays an open red PR until the next tick supersedes it.
The tracking PR and auto-merge use the PAT stored in `PKGS_BOT_TOKEN`, with The tracking and rebuild PRs and their auto-merge use the PAT stored in `PKGS_BOT_TOKEN`, with
Contents and Pull requests write access to this repository and an owner trusted Contents and Pull requests write access to this repository and an owner trusted
to trigger builds. The existing controller PAT can be reused. No GitHub App is to trigger builds. The existing controller PAT can be reused. No GitHub App is
required. The built-in Actions `GITHUB_TOKEN` cannot drive the unattended required. The built-in Actions `GITHUB_TOKEN` cannot drive the unattended
build-and-publish chain, so the tracker requires this secret before it runs. build-and-publish chain, so both workflows require this secret before they run.
The reviewed sync workflows continue to use `GITHUB_TOKEN` and require The reviewed upstream sync continues to use `GITHUB_TOKEN` and requires
maintainer approval as before. See [setup instructions](docs/upstream-sources.md#enable-unattended-branch-updates). maintainer approval as before. See [setup instructions](docs/upstream-sources.md#enable-unattended-branch-updates).
Scheduled runs regenerate one shared PR (`auto/sync-upstream`, `auto/sync-rebuilds`) Scheduled runs regenerate one shared PR (`auto/sync-upstream`, `auto/sync-rebuilds`)
@@ -912,14 +926,27 @@ pending updates. The next scheduled run still picks the same update up in the
shared PR if it has not merged by then; identical package trees reuse the same shared PR if it has not merged by then; identical package trees reuse the same
build artifacts. build artifacts.
Sync PRs are pushed with `GITHUB_TOKEN`, so GitHub holds their build and test Upstream sync PRs are pushed with `GITHUB_TOKEN`, so GitHub holds their build and test
runs for approval on every push and starts no `pull_request_target` workflow runs for approval on every push and starts no `pull_request_target` workflow
for them. The sync workflows label their own PRs **`build-approved`**, and for them. The upstream sync labels its own PRs **`build-approved`**, and
their `approve` job releases the held runs for each commit they push, including its `approve` job releases the held runs for each commit they push, including
the push that opens the PR. A push to an `auto/sync-*` branch does not cancel the push that opens the PR. A push to an `auto/sync-*` branch does not cancel
the PR's in-flight build: the new build waits for it and then reuses its the PR's in-flight build: the new build waits for it and then reuses its
artifacts, so a long aarch64 build is not restarted by every sync. artifacts, so a long aarch64 build is not restarted by every sync.
Package PRs that are trusted to build also merge themselves.
`auto-merge-pr.yml` enables auto-merge (with `PKGS_BOT_TOKEN`, so the merge
publishes) on any open, non-draft PR whose author is a collaborator, vouched,
or a bot, or that carries **`build-approved`**, and that changes only
packages: anything under `pkgbuilds/`, plus the test a package PR brings with
it (a new file under `tests/`, and `test.yml` lines that only run new
`./tests/*.sh`). The PR lands once `result`, `self-tests` and
`build-isolation` pass; a red build stays open. PRs that also touch
workflows, scripts, build tooling or existing tests still need a maintainer, as does
the upstream sync (`auto/sync-upstream`), which labels itself. Removing
`build-approved` withdraws the auto-merge it armed. For a PR opened before
the workflow existed, run it by hand: `gh workflow run auto-merge-pr.yml -f pr=<number>`.
To approve builds for an unvouched contributor's PR, apply **`build-approved`**. To approve builds for an unvouched contributor's PR, apply **`build-approved`**.
Until approval, the PR shows **Awaiting build approval** and its required Until approval, the PR shows **Awaiting build approval** and its required
`result` check stays pending, keeping the PR blocked from merging without `result` check stays pending, keeping the PR blocked from merging without
+1 -1
View File
@@ -86,7 +86,7 @@ while [[ $# -gt 0 ]]; do
echo " $0 --arch aarch64" echo " $0 --arch aarch64"
echo " $0 --mirror stable" echo " $0 --mirror stable"
echo " $0 --package yay" echo " $0 --package yay"
echo " $0 --package yay elephant cursor-bin" echo " $0 --package yay walker cursor-bin"
echo "" echo ""
echo "Environment (for CI and resumed builds; defaults keep today's behaviour):" 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_KEEP_BUILD_WORKSPACE=1 keep build-output and reuse packages already there"
+80
View File
@@ -0,0 +1,80 @@
#!/bin/bash
# Retire packages from one channel of the remote repository.
#
# unpublish-packages --mirror <edge|rc|stable> --arch <arch> <pkgbase...>
#
# The counterpart of publish-artifact, with the same steps:
# 1. pull the channel's current database from the remote
# 2. find every entry built from the named pkgbases (so a package's split
# outputs and -debug go with it)
# 3. repo-remove them
# 4. upload the database
#
# Package files stay in the bucket. Published filenames are immutable and the
# R2 cache cannot recover from a rewrite; an unreferenced file costs nothing
# and pacman never sees it. Naming a package the channel does not hold is not
# an error, so a re-run is harmless.
#
# The remote is an rclone remote (REMOTE, default the production one);
# OMARCHY_PUBLISH_PREFIX can point a proof run at a scratch prefix.
set -euo pipefail
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
source "$BUILD_ROOT/helpers/paths.sh"
REMOTE=${REMOTE:-pkgs.omarchy.org:omarchy-pkgs}
PREFIX=${OMARCHY_PUBLISH_PREFIX:-}
BASES=()
while [[ $# -gt 0 ]]; do
case $1 in
--mirror) MIRROR=$2; require_valid_mirror "$MIRROR"; shift 2 ;;
--arch) ARCH=$2; require_valid_arch "$ARCH"; shift 2 ;;
--remote) REMOTE=$2; shift 2 ;;
-h|--help) sed -n '2,19p' "$0"; exit 0 ;;
-*) print_error "Unknown option: $1"; exit 1 ;;
*) BASES+=("$1"); shift ;;
esac
done
(( ${#BASES[@]} )) || { print_error "No packages given"; exit 1; }
DEST="$REMOTE/${PREFIX:+$PREFIX/}$MIRROR/$ARCH"
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT
print_header "Unpublish from $DEST"
# --- 1. pull the current database -----------------------------------------
mkdir -p "$WORK/repo"
listing=$(rclone lsf "$DEST/" --s3-no-head 2>/dev/null || true)
if ! grep -q '^omarchy.db.tar.zst$' <<<"$listing"; then
print_info "No database at $DEST; nothing to remove"
exit 0
fi
rclone copy "$DEST/omarchy.db.tar.zst" "$WORK/repo" --s3-no-head
rclone copy "$DEST/omarchy.files.tar.zst" "$WORK/repo" --s3-no-head 2>/dev/null || true
before=$(tar -tf "$WORK/repo/omarchy.db.tar.zst" | grep -c '/$')
print_info "Pulled current database ($before entries)"
# --- 2. entries built from the named pkgbases -----------------------------
names=$(bsdtar -xOf "$WORK/repo/omarchy.db.tar.zst" --include '*/desc' |
awk -v bases=" ${BASES[*]} " '
/^%NAME%$/ { getline name }
/^%BASE%$/ { getline base; if (index(bases, " " base " ")) print name }')
if [[ -z "$names" ]]; then
print_info "None of ${BASES[*]} is in $MIRROR/$ARCH; nothing to remove"
exit 0
fi
mapfile -t NAMES <<<"$names"
for n in "${NAMES[@]}"; do print_step "removing $n"; done
# --- 3. repo-remove ---------------------------------------------------------
( cd "$WORK/repo" && repo-remove --quiet omarchy.db.tar.zst "${NAMES[@]}" )
ln -sf omarchy.db.tar.zst "$WORK/repo/omarchy.db"
ln -sf omarchy.files.tar.zst "$WORK/repo/omarchy.files"
after=$(tar -tf "$WORK/repo/omarchy.db.tar.zst" | grep -c '/$')
(( before - after == ${#NAMES[@]} )) || {
print_error "Expected to remove ${#NAMES[@]} entries, removed $((before - after))"; exit 1; }
print_info "Database now has $after entries"
# --- 4. upload the database -------------------------------------------------
rclone copy "$WORK/repo" "$DEST" --s3-no-head --checksum --copy-links --filter '+ omarchy.db*' --filter '+ omarchy.files*' --filter '- *'
print_success "Removed ${#NAMES[@]} package(s) from $DEST"
+17 -4
View File
@@ -12,9 +12,12 @@ signing on merge exactly as before.
- `runner-cloud-init.yaml` — Ubuntu 24.04 user-data: docker + buildx, the - `runner-cloud-init.yaml` — Ubuntu 24.04 user-data: docker + buildx, the
GitHub runner registered `--ephemeral`, runs one job, powers off. GitHub runner registered `--ephemeral`, runs one job, powers off.
- `controller.sh` — systemd timer every minute on a small always-on droplet. - `controller.sh` — systemd timer every minute on a small always-on droplet.
Polls for queued jobs with our label, creates one g5-32vcpu-64gb-50gb droplet (ric1) per job up Polls for queued jobs with our label, creates one g5-32vcpu-64gb-50gb droplet per job up
to `MAX_DROPLETS`, deletes droplets that are powered off or older than to `MAX_DROPLETS`, deletes droplets that are powered off or older than
`MAX_AGE_MINUTES`. No inbound endpoint. Plain curl against both APIs, no `MAX_AGE_MINUTES`, or still provisioning after `MAX_BOOT_MINUTES`. Builders go in any region DigitalOcean lists the size in
stock in (`REGIONS` only sets which to try first); a refused create, logged
with DigitalOcean's message, falls back to the next region, then the next
of `SIZES`. No inbound endpoint. Plain curl against both APIs, no
doctl and no gh: a token in the environment cannot pick the wrong account doctl and no gh: a token in the environment cannot pick the wrong account
the way a saved doctl context can. Needs curl and jq. the way a saved doctl context can. Needs curl and jq.
`tests/controller.sh` exercises every decision against canned responses. `tests/controller.sh` exercises every decision against canned responses.
@@ -31,6 +34,13 @@ Administration read+write (registration tokens). The DO token is baked into
the box's env file, so it is the account that pays for builder droplets. the box's env file, so it is the account that pays for builder droplets.
Watch it with `journalctl -u omarchy-controller -f` on the box. Watch it with `journalctl -u omarchy-controller -f` on the box.
Each tick pulls the box's checkout first, so a merged `controller.sh` is live
within a minute. The unit and timer are copies made at creation; after
changing them, on the box:
cp /opt/omarchy-pkgs/ci/controller-box/omarchy-controller.{service,timer} /etc/systemd/system/
systemctl daemon-reload
## What the spike proved (2026-09-17, fork ryanrhughes/omarchy-pkgs) ## What the spike proved (2026-09-17, fork ryanrhughes/omarchy-pkgs)
- `bin/build` works from a bare clone: with no local published tree it - `bin/build` works from a bare clone: with no local published tree it
@@ -70,8 +80,11 @@ Watch it with `journalctl -u omarchy-controller -f` on the box.
packages then signatures then the db. packages then signatures then the db.
- aarch64 under QEMU with credential-preserving binfmt. PR builds now run - aarch64 under QEMU with credential-preserving binfmt. PR builds now run
aarch64 natively on `ubuntu-24.04-arm` (QEMU was up to ~15x slower). When a aarch64 natively on `ubuntu-24.04-arm` (QEMU was up to ~15x slower). When a
merged aarch64 tree has no artifact, publish.yml rebuilds it there too, in its merged tree has no artifact, publish.yml rebuilds it in its own job, aarch64
own job, and signs and uploads it on the droplet like a PR artifact. there and x86_64 on a droplet, outside the publish lock.
- Publish itself builds nothing: it signs and uploads on `ubuntu-latest` in the
tested builder image pulled from GHCR, and only that job holds the `publish`
concurrency group, so a merge waits for seconds of signing, not for builds.
- Vouch gate: collaborators, `.github/VOUCHED.td`, or the `build-approved` - Vouch gate: collaborators, `.github/VOUCHED.td`, or the `build-approved`
label; denounced authors cannot be overridden by the label. label; denounced authors cannot be overridden by the label.
- Tests run on PRs only; `result`, `self-tests`, `build-isolation` are the - Tests run on PRs only; `result`, `self-tests`, `build-isolation` are the
+6 -2
View File
@@ -5,10 +5,14 @@ GITHUB_TOKEN=github_pat_...
REPO=omacom/omarchy-pkgs REPO=omacom/omarchy-pkgs
LABEL=omarchy-builder LABEL=omarchy-builder
TAG=omarchy-builder TAG=omarchy-builder
REGION=ric1 # Builder sizes, tried in order in any region that has them in stock.
SIZE=g5-32vcpu-64gb-50gb SIZES="g5-32vcpu-64gb-50gb g5-32vcpu-128gb-50gb"
# Optional: regions to try first, e.g. "ric1". Empty means any.
REGIONS=
MAX_DROPLETS=6 MAX_DROPLETS=6
MAX_AGE_MINUTES=200 MAX_AGE_MINUTES=200
# Delete a droplet DigitalOcean still reports as provisioning after this long.
MAX_BOOT_MINUTES=10
LOCK=/run/omarchy-controller/lock LOCK=/run/omarchy-controller/lock
# Operator public keys for root on every builder droplet (JSON array). # Operator public keys for root on every builder droplet (JSON array).
# create.sh fills this from the operators' GitHub keys. # create.sh fills this from the operators' GitHub keys.
@@ -7,6 +7,9 @@ Wants=network-online.target
Type=oneshot Type=oneshot
User=controller User=controller
EnvironmentFile=/etc/omarchy-controller.env EnvironmentFile=/etc/omarchy-controller.env
# Run the branch's current controller, not the one cloned when the box was
# built. As root (the checkout's owner); a failed pull keeps the last one.
ExecStartPre=-+/usr/bin/git -C /opt/omarchy-pkgs pull --ff-only --quiet
ExecStart=/opt/omarchy-pkgs/ci/controller.sh ExecStart=/opt/omarchy-pkgs/ci/controller.sh
# The reaper's safety net is time, not state; a hung tick must not hold the lock. # The reaper's safety net is time, not state; a hung tick must not hold the lock.
TimeoutStartSec=240 TimeoutStartSec=240
+88 -18
View File
@@ -4,7 +4,8 @@
# Run from a systemd timer every minute on a small always-on droplet. No # Run from a systemd timer every minute on a small always-on droplet. No
# inbound endpoint: it polls GitHub for queued jobs wanting our label, creates # inbound endpoint: it polls GitHub for queued jobs wanting our label, creates
# one ephemeral droplet per job (up to MAX_DROPLETS), and deletes droplets # one ephemeral droplet per job (up to MAX_DROPLETS), and deletes droplets
# that have powered off or exceeded MAX_AGE_MINUTES. The reaper does not # that have powered off, exceeded MAX_AGE_MINUTES, or are still provisioning
# after MAX_BOOT_MINUTES. The reaper does not
# trust its own bookkeeping: it lists by tag and acts on what DigitalOcean # trust its own bookkeeping: it lists by tag and acts on what DigitalOcean
# reports. # reports.
# #
@@ -21,11 +22,19 @@ REPO=${REPO:?owner/name}
: "${DIGITALOCEAN_TOKEN:?}" "${GITHUB_TOKEN:?}" : "${DIGITALOCEAN_TOKEN:?}" "${GITHUB_TOKEN:?}"
LABEL=${LABEL:-omarchy-builder} LABEL=${LABEL:-omarchy-builder}
TAG=${TAG:-omarchy-builder} TAG=${TAG:-omarchy-builder}
REGION=${REGION:-ric1} # Sizes to try, in order, in any region DigitalOcean lists them in stock. A
SIZE=${SIZE:-g5-32vcpu-64gb-50gb} # size can sell out in a region for hours; the create is then refused with
# 422 and the next region, then the next size, is tried. REGIONS only orders
# the regions tried first. SIZE and REGION, if set, are one-item lists.
SIZES=${SIZES:-${SIZE:-g5-32vcpu-64gb-50gb g5-32vcpu-128gb-50gb}}
REGIONS=${REGIONS:-${REGION:-}}
IMAGE=${IMAGE:-ubuntu-24-04-x64} IMAGE=${IMAGE:-ubuntu-24-04-x64}
MAX_DROPLETS=${MAX_DROPLETS:-4} MAX_DROPLETS=${MAX_DROPLETS:-4}
MAX_AGE_MINUTES=${MAX_AGE_MINUTES:-200} MAX_AGE_MINUTES=${MAX_AGE_MINUTES:-200}
# A droplet DigitalOcean still reports as "new" this long after creation is
# stuck provisioning. Left alone it counts as a runner booting, and holds a
# queued job until MAX_AGE_MINUTES.
MAX_BOOT_MINUTES=${MAX_BOOT_MINUTES:-10}
RUNNER_VERSION=${RUNNER_VERSION:-2.337.0} RUNNER_VERSION=${RUNNER_VERSION:-2.337.0}
CLOUD_INIT=${CLOUD_INIT:-$(dirname "$0")/runner-cloud-init.yaml} CLOUD_INIT=${CLOUD_INIT:-$(dirname "$0")/runner-cloud-init.yaml}
# Operator public keys authorized on every builder (JSON array of strings). # Operator public keys authorized on every builder (JSON array of strings).
@@ -39,7 +48,8 @@ log() { echo "$(date '+%F %T') $*"; }
# both, so every decision below is exercised against canned responses. # both, so every decision below is exercised against canned responses.
do_api() { # do_api <path> [curl args...] do_api() { # do_api <path> [curl args...]
local path=$1; shift local path=$1; shift
curl -fsS -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \ # --fail-with-body: a refused create still prints why.
curl -sS --fail-with-body -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "Content-Type: application/json" "https://api.digitalocean.com/v2/$path" "$@" -H "Content-Type: application/json" "https://api.digitalocean.com/v2/$path" "$@"
} }
gh_api() { # gh_api <path> [curl args...] gh_api() { # gh_api <path> [curl args...]
@@ -55,7 +65,8 @@ reap() {
while read -r id status created; do while read -r id status created; do
[[ -n "$id" ]] || continue [[ -n "$id" ]] || continue
age=$(( (now - $(date -d "$created" +%s)) / 60 )) age=$(( (now - $(date -d "$created" +%s)) / 60 ))
if [[ $status == off ]] || (( age > MAX_AGE_MINUTES )); then if [[ $status == off ]] || (( age > MAX_AGE_MINUTES )) ||
{ [[ $status == new ]] && (( age > MAX_BOOT_MINUTES )); }; then
log "deleting droplet $id (status=$status age=${age}m)" log "deleting droplet $id (status=$status age=${age}m)"
do_api "droplets/$id" -X DELETE do_api "droplets/$id" -X DELETE
fi fi
@@ -64,18 +75,40 @@ reap() {
} }
# --- demand ---------------------------------------------------------------- # --- demand ----------------------------------------------------------------
# Emit every item, including later pages of large build matrices. Keep API
# failures fatal so a failed query cannot look like an empty queue.
gh_items() {
local path=$1 key=$2 page=1 response count separator="?"
[[ $path != *"?"* ]] || separator="&"
while :; do
response=$(gh_api "${path}${separator}per_page=100&page=$page") || return 1
count=$(jq -er --arg key "$key" '.[$key] | arrays | length' <<< "$response") || return 1
jq -c --arg key "$key" '.[$key][]' <<< "$response" || return 1
(( count == 100 )) || break
((page += 1))
done
}
queued_jobs() { queued_jobs() {
local run local status runs run
gh_api "repos/$REPO/actions/runs?status=queued&per_page=50" --get \ # A workflow can be in progress while most of its matrix is still queued.
| jq -r '.workflow_runs[].id' | runs=$(
for status in queued in_progress; do
gh_items "repos/$REPO/actions/runs?status=$status" workflow_runs || exit 1
done
) || return 1
jq -r '.id' <<< "$runs" | sort -u |
while read -r run; do while read -r run; do
gh_api "repos/$REPO/actions/runs/$run/jobs" \ gh_items "repos/$REPO/actions/runs/$run/jobs" jobs |
| jq -r --arg l "$LABEL" '.jobs[] | select(.status=="queued") | select(.labels | index($l)) | .id' jq -r --arg l "$LABEL" 'select(.status=="queued") | select(.labels | index($l)) | .id' || return 1
done | wc -l done | sort -u | wc -l
} }
live_droplets() { live_droplets() {
do_api "droplets?tag_name=$TAG&per_page=200" | jq '[.droplets[] | select(.status != "off")] | length' # Not the ones reap() just deleted: DigitalOcean can list them for a while.
do_api "droplets?tag_name=$TAG&per_page=200" | jq --argjson boot "$MAX_BOOT_MINUTES" '
[.droplets[] | select(.status != "off")
| select(.status != "new" or (now - (.created_at | fromdateiso8601)) / 60 <= $boot)] | length'
} }
busy_runners() { busy_runners() {
@@ -83,22 +116,59 @@ busy_runners() {
| jq --arg l "$LABEL" '[.runners[] | select(.busy) | select(any(.labels[]; .name == $l))] | length' | jq --arg l "$LABEL" '[.runners[] | select(.busy) | select(any(.labels[]; .name == $l))] | length'
} }
# --- capacity --------------------------------------------------------------
# "size region" lines to try, best first: SIZES order, then REGIONS order,
# then every other region where DigitalOcean lists the size in stock.
candidates() {
local page=1 response count catalog=""
while :; do
response=$(do_api "sizes?per_page=200&page=$page") || return 1
count=$(jq -er '.sizes | arrays | length' <<< "$response") || return 1
catalog+=$(jq -c '.sizes[]' <<< "$response")$'\n'
(( count == 200 )) || break
((page += 1))
done
jq -rs --arg sizes "$SIZES" --arg regions "$REGIONS" '
($regions | split(" ") | map(select(length > 0))) as $pref
| INDEX(.slug) as $by
| $sizes | split(" ") | map(select(length > 0)) | .[]
| . as $size | $by[$size] // {} | select(.available == true)
| .regions as $in
| (($pref | map(select(. as $r | $in | index($r)))) + ($in - $pref))[]
| "\($size) \(.)"' <<< "$catalog"
}
# --- create ---------------------------------------------------------------- # --- create ----------------------------------------------------------------
# Built once per tick by the first create; a refused pair is dropped from it.
CANDIDATES=""
create_droplet() { create_droplet() {
local token userdata name body local token userdata name size region body response
[[ -n $CANDIDATES ]] || CANDIDATES=$(candidates) || return 1
token=$(gh_api "repos/$REPO/actions/runners/registration-token" -X POST | jq -r .token) token=$(gh_api "repos/$REPO/actions/runners/registration-token" -X POST | jq -r .token)
userdata=$(sed -e "s|__REPO__|$REPO|g" -e "s|__RUNNER_TOKEN__|$token|g" \ userdata=$(sed -e "s|__REPO__|$REPO|g" -e "s|__RUNNER_TOKEN__|$token|g" \
-e "s|__RUNNER_LABELS__|$LABEL|g" -e "s|__RUNNER_VERSION__|$RUNNER_VERSION|g" \ -e "s|__RUNNER_LABELS__|$LABEL|g" -e "s|__RUNNER_VERSION__|$RUNNER_VERSION|g" \
-e "s|__SSH_KEYS_JSON__|$SSH_KEYS_JSON|" "$CLOUD_INIT") -e "s|__SSH_KEYS_JSON__|$SSH_KEYS_JSON|" "$CLOUD_INIT")
name="$TAG-$(date +%s)-$RANDOM" name="$TAG-$(date +%s)-$RANDOM"
body=$(jq -n --arg name "$name" --arg region "$REGION" --arg size "$SIZE" --arg image "$IMAGE" \ while read -r size region; do
--arg tag "$TAG" --arg ud "$userdata" \ [[ -n $size ]] || continue
'{name:$name, region:$region, size:$size, image:$image, tags:[$tag], user_data:$ud, monitoring:false}') body=$(jq -n --arg name "$name" --arg region "$region" --arg size "$size" --arg image "$IMAGE" \
log "creating $name ($SIZE)" --arg tag "$TAG" --arg ud "$userdata" \
do_api droplets -X POST -d "$body" | jq -r '"created droplet \(.droplet.id)"' '{name:$name, region:$region, size:$size, image:$image, tags:[$tag], user_data:$ud, monitoring:false}')
log "creating $name ($size in $region)"
if response=$(do_api droplets -X POST -d "$body"); then
jq -r '"created droplet \(.droplet.id)"' <<< "$response"
return 0
fi
log "$size in $region refused: $(jq -r .message <<< "$response" 2>/dev/null || echo "$response")"
CANDIDATES=$(grep -Fvx "$size $region" <<< "$CANDIDATES" || true)
done <<< "$CANDIDATES"
# Every size refused everywhere: the rest of this tick's creates would be too.
log "no size in '$SIZES' can be created in any region"
return 1
} }
controller_tick() { controller_tick() {
CANDIDATES=""
reap reap
local queued live busy available need room local queued live busy available need room
queued=$(queued_jobs) queued=$(queued_jobs)
+4 -2
View File
@@ -45,6 +45,10 @@ write_files:
content: | content: |
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
# Power off after the one job, and also when the download or the
# registration fails: the controller deletes powered-off droplets, but
# counts a running one as a runner still booting until MAX_AGE_MINUTES.
trap 'sudo poweroff' EXIT
cd /home/runner cd /home/runner
mkdir -p actions-runner && cd actions-runner mkdir -p actions-runner && cd actions-runner
arch=$(uname -m); [[ $arch == x86_64 ]] && arch=x64 arch=$(uname -m); [[ $arch == x86_64 ]] && arch=x64
@@ -58,8 +62,6 @@ write_files:
--labels "__RUNNER_LABELS__" \ --labels "__RUNNER_LABELS__" \
--replace --replace
./run.sh ./run.sh
# One job done. Power off; the controller deletes powered-off droplets.
sudo poweroff
runcmd: runcmd:
# With no account ssh key attached, DO expires root's password, and sshd # With no account ssh key attached, DO expires root's password, and sshd
+1 -20
View File
@@ -151,7 +151,6 @@ in `origin` and has no effect on release selection.
| `1password-beta` | debian | [https://downloads.1password.com/linux/debian/amd64/dists/beta/main/binary-amd64/Packages](https://downloads.1password.com/linux/debian/amd64/dists/beta/main/binary-amd64/Packages) | | `1password-beta` | debian | [https://downloads.1password.com/linux/debian/amd64/dists/beta/main/binary-amd64/Packages](https://downloads.1password.com/linux/debian/amd64/dists/beta/main/binary-amd64/Packages) |
| `1password-cli` | json | [https://app-updates.agilebits.com/check/1/0/CLI2/en/0](https://app-updates.agilebits.com/check/1/0/CLI2/en/0) | | `1password-cli` | json | [https://app-updates.agilebits.com/check/1/0/CLI2/en/0](https://app-updates.agilebits.com/check/1/0/CLI2/en/0) |
| `aether` | github | [omacom/aether](https://github.com/omacom/aether) | | `aether` | github | [omacom/aether](https://github.com/omacom/aether) |
| `asusctl` | git_tags | [https://github.com/OpenGamingCollective/asusctl.git](https://github.com/OpenGamingCollective/asusctl.git) |
| `basecamp-cli` | github | [basecamp/basecamp-cli](https://github.com/basecamp/basecamp-cli) | | `basecamp-cli` | github | [basecamp/basecamp-cli](https://github.com/basecamp/basecamp-cli) |
| `bun-bin` | github | [oven-sh/bun](https://github.com/oven-sh/bun) | | `bun-bin` | github | [oven-sh/bun](https://github.com/oven-sh/bun) |
| `claude-code` | regex | [https://downloads.claude.ai/claude-code-releases/latest](https://downloads.claude.ai/claude-code-releases/latest) | | `claude-code` | regex | [https://downloads.claude.ai/claude-code-releases/latest](https://downloads.claude.ai/claude-code-releases/latest) |
@@ -162,21 +161,6 @@ in `origin` and has no effect on release selection.
| `dbxcli-bin` | github | [dropbox/dbxcli](https://github.com/dropbox/dbxcli) | | `dbxcli-bin` | github | [dropbox/dbxcli](https://github.com/dropbox/dbxcli) |
| `dropbox` | redirect | [https://www.dropbox.com/download?plat=lnx.x86_64](https://www.dropbox.com/download?plat=lnx.x86_64) | | `dropbox` | redirect | [https://www.dropbox.com/download?plat=lnx.x86_64](https://www.dropbox.com/download?plat=lnx.x86_64) |
| `dropbox-cli` | regex | [https://linux.dropbox.com/packages/](https://linux.dropbox.com/packages/) | | `dropbox-cli` | regex | [https://linux.dropbox.com/packages/](https://linux.dropbox.com/packages/) |
| `elephant` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-all` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-archlinuxpkgs` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-bluetooth` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-calc` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-clipboard` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-desktopapplications` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-files` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-menus` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-providerlist` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-runner` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-symbols` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-todo` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-unicode` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `elephant-websearch` | github | [abenz1267/elephant](https://github.com/abenz1267/elephant) |
| `heroic-games-launcher-bin` | github | [Heroic-Games-Launcher/HeroicGamesLauncher](https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher) | | `heroic-games-launcher-bin` | github | [Heroic-Games-Launcher/HeroicGamesLauncher](https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher) |
| `hyprshade` | pypi | [hyprshade](https://pypi.org/project/hyprshade/) | | `hyprshade` | pypi | [hyprshade](https://pypi.org/project/hyprshade/) |
| `lib32-nvidia-580xx-utils` | regex | [https://download.nvidia.com/XFree86/Linux-x86_64/](https://download.nvidia.com/XFree86/Linux-x86_64/) | | `lib32-nvidia-580xx-utils` | regex | [https://download.nvidia.com/XFree86/Linux-x86_64/](https://download.nvidia.com/XFree86/Linux-x86_64/) |
@@ -213,7 +197,6 @@ in `origin` and has no effect on release selection.
| `vi` | regex | [https://sources.archlinux.org/other/vi/](https://sources.archlinux.org/other/vi/) | | `vi` | regex | [https://sources.archlinux.org/other/vi/](https://sources.archlinux.org/other/vi/) |
| `visual-studio-code-bin` | json | [https://update.code.visualstudio.com/api/update/linux-deb-x64/stable/latest](https://update.code.visualstudio.com/api/update/linux-deb-x64/stable/latest) | | `visual-studio-code-bin` | json | [https://update.code.visualstudio.com/api/update/linux-deb-x64/stable/latest](https://update.code.visualstudio.com/api/update/linux-deb-x64/stable/latest) |
| `walker` | github | [abenz1267/walker](https://github.com/abenz1267/walker) | | `walker` | github | [abenz1267/walker](https://github.com/abenz1267/walker) |
| `xdg-terminal-exec` | git_tags | [https://gitlab.freedesktop.org/Vladimir-csp/xdg-terminal-exec.git](https://gitlab.freedesktop.org/Vladimir-csp/xdg-terminal-exec.git) |
| `xpadneo-dkms` | github | [atar-axis/xpadneo](https://github.com/atar-axis/xpadneo) | | `xpadneo-dkms` | github | [atar-axis/xpadneo](https://github.com/atar-axis/xpadneo) |
| `yaru-icon-theme` | git_tags | [https://github.com/ubuntu/yaru.git](https://github.com/ubuntu/yaru.git) | | `yaru-icon-theme` | git_tags | [https://github.com/ubuntu/yaru.git](https://github.com/ubuntu/yaru.git) |
| `yay` | github | [Jguer/yay](https://github.com/Jguer/yay) | | `yay` | github | [Jguer/yay](https://github.com/Jguer/yay) |
@@ -221,12 +204,10 @@ in `origin` and has no effect on release selection.
## Existing manual holds ## Existing manual holds
`grok-bot`, `libfprint-git`, `libretro-cap32-git`, `libretro-database-git`, `libretro-fbneo-git`, `libretro-uae-git`, `libretro-vice-git`, `quickshell-git`, `supergfxctl`. `libfprint-git`, `libretro-cap32-git`, `libretro-database-git`, `libretro-fbneo-git`, `libretro-uae-git`, `libretro-vice-git`, `quickshell-git`, `supergfxctl`.
These packages were already excluded from automatic AUR updates. The migration preserves that policy. These packages were already excluded from automatic AUR updates. The migration preserves that policy.
`linux-firmware-cirrus` is a deliberate hold: a self-retiring shim that ships Arch's linux-firmware-cirrus 20260910-2 payload to stable while stable's Arch snapshot is on 20260810-2 (Dell XPS 13 DX13260 / 1028:0e54 speaker firmware). It is versioned 20260810-3 so the genuine Arch package supersedes it as soon as the snapshot advances; bumping it to the Arch version would defeat that. Delete the recipe once stable's snapshot carries linux-firmware >= 20260910.
`m1n1-aurora` and `uboot-asahi` are deliberate holds: Apple Silicon boot code, pinned by hand like `linux-aurora`, and bumped only after a cold boot on the qualification Macs. `m1n1-aurora` pins an aurora-silicon/m1n1 commit plus a local patch. `uboot-asahi` follows asahi-alarm's recipe and patch set (asahi-alarm/PKGBUILDs), which a tag watch on AsahiLinux/u-boot cannot carry. `m1n1-aurora` and `uboot-asahi` are deliberate holds: Apple Silicon boot code, pinned by hand like `linux-aurora`, and bumped only after a cold boot on the qualification Macs. `m1n1-aurora` pins an aurora-silicon/m1n1 commit plus a local patch. `uboot-asahi` follows asahi-alarm's recipe and patch set (asahi-alarm/PKGBUILDs), which a tag watch on AsahiLinux/u-boot cannot carry.
`cua-driver-bin` is a deliberate hold: Omarchy bumps it by hand, so a Cua release ships only when a maintainer has verified it. It keeps its `.omarchy/upstream.sh` hook and `min_release_age`, so lifting the hold means removing `"sync": false`. `cua-hyprland-plugin` declares no upstream source, so no automation updates it either. `cua-driver-bin` is a deliberate hold: Omarchy bumps it by hand, so a Cua release ships only when a maintainer has verified it. It keeps its `.omarchy/upstream.sh` hook and `min_release_age`, so lifting the hold means removing `"sync": false`. `cua-hyprland-plugin` declares no upstream source, so no automation updates it either.
+1 -1
View File
@@ -10,7 +10,7 @@ case "${CARCH}" in
;; ;;
esac esac
pkgver=8.12.40_27.BETA pkgver=8.12.40_27.BETA
pkgrel=1 pkgrel=2
conflicts=('1password' '1password-beta-bin') conflicts=('1password' '1password-beta-bin')
pkgdesc="Password manager and secure wallet" pkgdesc="Password manager and secure wallet"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
+1 -1
View File
@@ -3,7 +3,7 @@
pkgname=1password-cli pkgname=1password-cli
pkgver=2.40.0 pkgver=2.40.0
pkgrel=1 pkgrel=2
pkgdesc="1Password command line tool" pkgdesc="1Password command line tool"
arch=('x86_64' 'i686' 'arm' 'armv6h' 'aarch64') arch=('x86_64' 'i686' 'arm' 'armv6h' 'aarch64')
url="https://app-updates.agilebits.com/product_history/CLI2" url="https://app-updates.agilebits.com/product_history/CLI2"
+1 -1
View File
@@ -1,6 +1,6 @@
pkgname=1password pkgname=1password
pkgver=8.12.40 pkgver=8.12.40
pkgrel=1 pkgrel=2
conflicts=('1password-beta' '1password-beta-bin') conflicts=('1password-beta' '1password-beta-bin')
pkgdesc="Password manager and secure wallet" pkgdesc="Password manager and secure wallet"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
+1 -1
View File
@@ -1,7 +1,7 @@
# Maintainer: Bjarne Øverli <bjarne@oever.li> # Maintainer: Bjarne Øverli <bjarne@oever.li>
pkgname=aether pkgname=aether
pkgver=4.32.0 pkgver=4.32.0
pkgrel=1 pkgrel=2
pkgdesc='Desktop theming application - extract colors from wallpapers and apply cohesive themes' pkgdesc='Desktop theming application - extract colors from wallpapers and apply cohesive themes'
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url='https://github.com/omacom/aether' url='https://github.com/omacom/aether'
-3
View File
@@ -1,3 +0,0 @@
[asusctl]
source = "git"
git = "https://github.com/OpenGamingCollective/asusctl.git"
-13
View File
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"git_tags": "https://github.com/OpenGamingCollective/asusctl.git",
"pattern": "(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "asusctl",
"commit": "b0ec6ca495eb331a684db91b0fe12085a868b632"
}
}
-12
View File
@@ -1,12 +0,0 @@
Copyright Arch Linux Contributors
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-1
View File
@@ -1 +0,0 @@
../LICENSE
-59
View File
@@ -1,59 +0,0 @@
# Maintainer: Mahdi Sarikhani <mahdisarikhani@outlook.com>
# Contributor: Fabian Bornschein <fabiscafe@archlinux.org>
# Contributor: Static_Rocket
pkgbase=asusctl
pkgname=(asusctl rog-control-center)
pkgver=6.5.0
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=('cargo' 'fontconfig')
source=("${pkgbase}-${pkgver}.tar.gz::https://github.com/OpenGamingCollective/asusctl/archive/${pkgver}.tar.gz")
b2sums=('4179e08a60f9480b62e41d84faade1f46407140a213ca4d60c8699837a2486bda8e66b4ca43fa06149667d02e3d060c3efd792348f9a93a675f762d6ea2d05f8')
prepare() {
cd "${pkgbase}-${pkgver}"
export RUSTUP_TOOLCHAIN=stable
cargo fetch --locked --target host-tuple
}
build() {
cd "${pkgbase}-${pkgver}"
export RUSTUP_TOOLCHAIN=stable
export CARGO_TARGET_DIR=target
make build
}
package_asusctl() {
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}-${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() {
pkgdesc="Graphical user interface for asusctl"
depends=('asusctl' 'fontconfig' 'glibc' 'hicolor-icon-theme' 'libgcc' 'systemd-libs')
cd "${pkgbase}-${pkgver}"
make DESTDIR="${pkgdir}" \
install-rog_gui \
install-data-rog_gui
}
-22
View File
@@ -1,22 +0,0 @@
version = 1
[[annotations]]
path = [
"PKGBUILD",
"README.md",
"keys/**",
".SRCINFO",
".nvchecker.toml",
"*.install",
"*.sysusers",
"*.tmpfiles",
"*.logrotate",
"*.pam",
"*.service",
"*.socket",
"*.timer",
"*.desktop",
"*.hook",
]
SPDX-FileCopyrightText = "Arch Linux contributors"
SPDX-License-Identifier = "0BSD"
-18
View File
@@ -1,18 +0,0 @@
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://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://github.com/OpenGamingCollective/asusctl#kernel-requirements\n"
printf ":: for latest required kernel patches/versions\n"
}
+1 -1
View File
@@ -11,7 +11,7 @@
pkgname=brave-bin pkgname=brave-bin
pkgver=1.96.61 pkgver=1.96.61
pkgrel=1 pkgrel=2
epoch=1 epoch=1
pkgdesc='Web browser that blocks ads and trackers by default (binary release)' pkgdesc='Web browser that blocks ads and trackers by default (binary release)'
arch=(x86_64 aarch64) arch=(x86_64 aarch64)
+1 -1
View File
@@ -2,7 +2,7 @@
pkgname=brave-origin-bin pkgname=brave-origin-bin
pkgver=1.96.61 pkgver=1.96.61
pkgrel=1 pkgrel=2
epoch=1 epoch=1
pkgdesc='The minimalist browser from the makers of Brave (binary release).' pkgdesc='The minimalist browser from the makers of Brave (binary release).'
arch=(x86_64 aarch64) arch=(x86_64 aarch64)
+1 -1
View File
@@ -5,7 +5,7 @@
pkgname=claude-code pkgname=claude-code
pkgver=2.1.291 pkgver=2.1.291
pkgrel=1 pkgrel=2
pkgdesc="An agentic coding tool that lives in your terminal" pkgdesc="An agentic coding tool that lives in your terminal"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://github.com/anthropics/claude-code" url="https://github.com/anthropics/claude-code"
+1 -1
View File
@@ -7,7 +7,7 @@
pkgname=claude-desktop pkgname=claude-desktop
pkgver=2.19675.1 pkgver=2.19675.1
pkgrel=1 pkgrel=2
pkgdesc="Official Claude desktop app with Claude Code" pkgdesc="Official Claude desktop app with Claude Code"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://claude.ai" url="https://claude.ai"
+1 -1
View File
@@ -1,7 +1,7 @@
# Maintainer: bjarneo <https://github.com/bjarneo> # Maintainer: bjarneo <https://github.com/bjarneo>
pkgname=cliamp pkgname=cliamp
pkgver=2.3.0 pkgver=2.3.0
pkgrel=1 pkgrel=2
pkgdesc='A retro terminal music player inspired by Winamp 2.x' pkgdesc='A retro terminal music player inspired by Winamp 2.x'
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url='https://github.com/bjarneo/cliamp' url='https://github.com/bjarneo/cliamp'
+1 -1
View File
@@ -4,7 +4,7 @@
pkgname='crush-bin' pkgname='crush-bin'
pkgver=0.97.1 pkgver=0.97.1
pkgrel=1 pkgrel=2
pkgdesc='A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal.' pkgdesc='A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal.'
url='https://charm.sh/crush' url='https://charm.sh/crush'
arch=('aarch64' 'armv7h' 'i686' 'x86_64') arch=('aarch64' 'armv7h' 'i686' 'x86_64')
+7 -8
View File
@@ -19,10 +19,8 @@
# binary to point at pm.sh, a stand-in that declines and names pacman instead. # binary to point at pm.sh, a stand-in that declines and names pacman instead.
pkgname=cua-driver-bin pkgname=cua-driver-bin
# Held at 0.28.2: 0.28.3 and newer break screenshots. Bump by hand once a pkgver=0.33.4
# fixed release is verified. pkgrel=1
pkgver=0.28.2
pkgrel=3
pkgdesc="Computer-use driver for native GUI apps: accessibility-tree snapshots and input injection" pkgdesc="Computer-use driver for native GUI apps: accessibility-tree snapshots and input injection"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://github.com/trycua/cua" url="https://github.com/trycua/cua"
@@ -49,8 +47,8 @@ source_x86_64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v$
source_aarch64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v${pkgver}/cua-driver-rs-${pkgver}-linux-arm64.tar.gz") source_aarch64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v${pkgver}/cua-driver-rs-${pkgver}-linux-arm64.tar.gz")
sha256sums=('c0779290c1d4783169aa3dbfb55feb505e563ef8a004bbf55298ceffcfbda8d9' sha256sums=('c0779290c1d4783169aa3dbfb55feb505e563ef8a004bbf55298ceffcfbda8d9'
'c76e251c3ed424200eac52bec35ba534336307fabd83a175ab0b47e2084ab0d8') 'c76e251c3ed424200eac52bec35ba534336307fabd83a175ab0b47e2084ab0d8')
sha256sums_x86_64=('8f3e5b669e2bcd98d0eecc64f40640aac77f358b6332a06abc6ee79991620f7d') sha256sums_x86_64=('a4759cc41c00691a345f08abfc28ece79aef41447d27a463ddd8662939fa3378')
sha256sums_aarch64=('cadd7e6b757c3ce50f2b5f6e273c154ea48450fb5fcaff744209b382915eddf5') sha256sums_aarch64=('63a1e858a1a407c44ceb407ad133909b8cddedd713aea3b56d7ccb6db784eb48')
case "${CARCH}" in case "${CARCH}" in
x86_64) _platform="linux-x86_64" ;; x86_64) _platform="linux-x86_64" ;;
@@ -72,8 +70,8 @@ prepare() {
return 1 return 1
fi fi
# In 0.28.1 the URL appears in the updater, the printed reinstall command, # Through 0.33.4 the URL appears in the updater, the printed reinstall
# and two embedded copies of Skills/cua-driver/README.md. Rewrite all four # command, and two embedded copies of Skills/cua-driver/README.md. Rewrite all four
# so the embedded instructions also defer to pacman. Any other count means # so the embedded instructions also defer to pacman. Any other count means
# the release layout changed and needs review before packaging. # the release layout changed and needs review before packaging.
local expected=4 found local expected=4 found
@@ -113,4 +111,5 @@ package() {
ln -s ../lib/cua-driver/cua-driver "${pkgdir}/usr/bin/cua-driver" ln -s ../lib/cua-driver/cua-driver "${pkgdir}/usr/bin/cua-driver"
install -Dm644 "${srcdir}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" install -Dm644 "${srcdir}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
install -Dm644 THIRD_PARTY_NOTICES.md "${pkgdir}/usr/share/licenses/${pkgname}/THIRD_PARTY_NOTICES.md"
} }
+3 -3
View File
@@ -1,6 +1,6 @@
# Optional Cua Hyprland plugin # Optional Cua Hyprland plugin
This package targets **Omarchy x86_64**, with Inkscape `1.4.4-6` and two independent background-input lanes. Release `0.32.0-3` is an edge candidate built from the plugin source published with Driver `0.32.0`, paired with `cua-driver-bin` `0.28.2`. That source carries the independent agent keymaps and compatible Num Lock handling that releases `0.26.1-5` through `0.28.2-2` applied as an Omarchy patch; this release applies a smaller one, `downstream.patch`, so foreground typing keeps working with modifier and Compose remaps (see *Keyboard behavior*) and so that, with its guard active, restarting fcitx5 does not crash Hyprland (see *Input-method popups*). The upstream native qualification below covers older, unpatched source. Cua's native qualification is recorded in [the kit's qualification record](https://github.com/trycua/cua/releases/download/cua-hyprland-kit-v1.1.0-omarchy-stable-20260910/QUALIFICATION.md) and [Cua #3698](https://github.com/trycua/cua/pull/3698). Omabot replay and Omarchy's merge decision are recorded in [omarchy-pkgs #346](https://github.com/omacom/omarchy-pkgs/pull/346). Scheduling the recipe does not expand the qualified stable target. This package targets **Omarchy x86_64**, with Inkscape `1.4.4-6` and two independent background-input lanes. Release `0.32.0-3` is an edge candidate built from the plugin source published with Driver `0.32.0`, paired with `cua-driver-bin` `0.33.4`; the plugin sources are unchanged from 0.32.0 through 0.33.4. That source carries the independent agent keymaps and compatible Num Lock handling that releases `0.26.1-5` through `0.28.2-2` applied as an Omarchy patch; this release applies a smaller one, `downstream.patch`, so foreground typing keeps working with modifier and Compose remaps (see *Keyboard behavior*) and so that, with its guard active, restarting fcitx5 does not crash Hyprland (see *Input-method popups*). The upstream native qualification below covers older, unpatched source. Cua's native qualification is recorded in [the kit's qualification record](https://github.com/trycua/cua/releases/download/cua-hyprland-kit-v1.1.0-omarchy-stable-20260910/QUALIFICATION.md) and [Cua #3698](https://github.com/trycua/cua/pull/3698). Omabot replay and Omarchy's merge decision are recorded in [omarchy-pkgs #346](https://github.com/omacom/omarchy-pkgs/pull/346). Scheduling the recipe does not expand the qualified stable target.
The plugin is optional. Cua Driver works independently, and installation does not load the plugin or enable input. The package follows the normal edge-to-RC-to-stable promotion path instead of the fast release ring. Its PKGBUILD limits builds to x86_64. The upstream qualification covers the original stable profile; the updated Aquamarine profile needs its own Omabot validation before promotion. The plugin is optional. Cua Driver works independently, and installation does not load the plugin or enable input. The package follows the normal edge-to-RC-to-stable promotion path instead of the fast release ring. Its PKGBUILD limits builds to x86_64. The upstream qualification covers the original stable profile; the updated Aquamarine profile needs its own Omabot validation before promotion.
@@ -8,7 +8,7 @@ The plugin is optional. Cua Driver works independently, and installation does no
The package uses the [Driver 0.32.0 plugin source](https://github.com/trycua/cua/releases/tag/cua-driver-rs-v0.32.0). Against the Driver 0.26.1 source the profile kit was qualified with, it adds the keyboard behaviour below ([Cua #3970](https://github.com/trycua/cua/pull/3970), adapted from [#473](https://github.com/omacom/omarchy-pkgs/pull/473)) and gives agent keyboards the user seat's key repeat rate instead of zero ([Cua #4358](https://github.com/trycua/cua/pull/4358)), which crashed single-seat clients such as imv that bound an agent seat ([Cua #4257](https://github.com/trycua/cua/issues/4257)). The input protocol header is unchanged. The package uses the [Driver 0.32.0 plugin source](https://github.com/trycua/cua/releases/tag/cua-driver-rs-v0.32.0). Against the Driver 0.26.1 source the profile kit was qualified with, it adds the keyboard behaviour below ([Cua #3970](https://github.com/trycua/cua/pull/3970), adapted from [#473](https://github.com/omacom/omarchy-pkgs/pull/473)) and gives agent keyboards the user seat's key repeat rate instead of zero ([Cua #4358](https://github.com/trycua/cua/pull/4358)), which crashed single-seat clients such as imv that bound an agent seat ([Cua #4257](https://github.com/trycua/cua/issues/4257)). The input protocol header is unchanged.
The qualified upstream Driver pairing is `cua-driver-bin 0.27.0-1`, with input protocol v3. Driver 0.27.0 contains the bounded stale-geometry retry validated with the upstream module. This package pairs with `cua-driver-bin 0.28.2`, which speaks the same input protocol v3 to this source; Driver finds the plugin only through its versioned input socket, not through the plugin's provenance. Discovery protocol v2 is separate. `cua-driver-bin` stays at 0.28.2 because Driver 0.28.3 through 0.32.0 refuse desktop capture on Hyprland with more than one output or with one output away from the origin ([Cua #4161](https://github.com/trycua/cua/issues/4161)), where 0.28.2 captures. This pairing is a changed pairing and requires affected replay before promotion. The qualified upstream Driver pairing is `cua-driver-bin 0.27.0-1`, with input protocol v3. Driver 0.27.0 contains the bounded stale-geometry retry validated with the upstream module. This package pairs with `cua-driver-bin 0.33.4`, which speaks the same input protocol v3 to this source; Driver finds the plugin only through its versioned input socket, not through the plugin's provenance. Discovery protocol v2 is separate. Driver 0.28.3 through 0.33.3 refuse desktop capture on Hyprland with more than one output or with one output away from the origin ([Cua #4161](https://github.com/trycua/cua/issues/4161)); 0.33.4 captures there again ([Cua #4305](https://github.com/trycua/cua/pull/4305)). This pairing is a changed pairing and requires affected replay before promotion.
Profile `omarchy-hyprland-0562r4-remaps`, kit tooling `1.1.0`, and package release `3` pin: Profile `omarchy-hyprland-0562r4-remaps`, kit tooling `1.1.0`, and package release `3` pin:
@@ -19,7 +19,7 @@ Profile `omarchy-hyprland-0562r4-remaps`, kit tooling `1.1.0`, and package relea
This profile derives from Cua's `omarchy-stable-20260910` profile. Arch's Hyprland `0.56.2-4` is a rebuild of the same 0.56.2 release against vulkan-sdk 1.4.363 and glslang, built with the same GCC `16.2.1 20260810` and linked to the same `libstdc++`. Its executable (SHA-256 `55da553be71222566ee73b973d2f56dbb9939044d8f22f81aa54b66c83f2f6d1`) and two of its 497 headers differ from `-3`: `src/version.h` now names the Aquamarine `0.15.1` and hyprutils `0.14.2` it was built against, and `protocols/hyprland-input-capture-v1.hpp` gains a destroy handler. The header inventory is re-measured the way `profile_verify.py` measures it, giving `1fdefe6ac027a159d04a5dfee4928ec7ebd15544a9a25b5f66d2f5a46fcf364a`; that method reproduces the kit's `-2`/`-3` values exactly. This profile derives from Cua's `omarchy-stable-20260910` profile. Arch's Hyprland `0.56.2-4` is a rebuild of the same 0.56.2 release against vulkan-sdk 1.4.363 and glslang, built with the same GCC `16.2.1 20260810` and linked to the same `libstdc++`. Its executable (SHA-256 `55da553be71222566ee73b973d2f56dbb9939044d8f22f81aa54b66c83f2f6d1`) and two of its 497 headers differ from `-3`: `src/version.h` now names the Aquamarine `0.15.1` and hyprutils `0.14.2` it was built against, and `protocols/hyprland-input-capture-v1.hpp` gains a destroy handler. The header inventory is re-measured the way `profile_verify.py` measures it, giving `1fdefe6ac027a159d04a5dfee4928ec7ebd15544a9a25b5f66d2f5a46fcf364a`; that method reproduces the kit's `-2`/`-3` values exactly.
The checked-in `PROFILE.json` changes only the profile name, package release, source release, exact Hyprland, Aquamarine and glibc package versions, and the re-measured compositor executable and header hashes. Compiler and libstdc++ runtime identities remain Cua's; the separately recorded patch changes the build source. Cua publishes the profile tooling only in the 0.26.1 kit, and the Driver 0.32.0 source manifest has exactly the fields that kit's `profile_verify.py` checks. The download wrapper verifies the original kit and the Driver 0.32.0 source archive before substituting that archive and its manifest into the kit, deriving the updated profile and provenance, and rendering the recipe from the kit's own `PROFILE-PKGBUILD.in`. It then verifies every derived member against its recorded digest, so the result is the kit Cua's `profile_verify.py` accepts as complete for this profile. The checked-in `PROFILE.json` changes only the profile name, package release, source release, exact Hyprland, Aquamarine and glibc package versions, and the re-measured compositor executable and header hashes. Compiler and libstdc++ runtime identities remain Cua's; the separately recorded patch changes the build source. Cua publishes the profile tooling only in the 0.26.1 kit, and the Driver 0.32.0 source manifest has exactly the fields that kit's `profile_verify.py` checks. The download wrapper verifies the original kit and the Driver 0.32.0 source archive before substituting that archive and its manifest into the kit, deriving the updated profile and provenance, and rendering the recipe from the kit's own `PROFILE-PKGBUILD.in`. It then verifies every derived member against its recorded digest, so the result is the kit Cua's `profile_verify.py` accepts as complete for this profile.
The native qualification below was recorded with package `0.26.1-2` and Hyprland `-2`. The 0.32.0 source and its Omarchy patch, the Aquamarine and glibc updates, and the Driver 0.28.2 pairing need their own application and Driver replay before promotion. Hyprland `0.56.2-4`, Aquamarine `0.15.1-1` and glibc `2.44+r50+g1848099f063e-1` must all reach a destination channel before this artifact can be installed there; publication still follows edge → RC → stable. The native qualification below was recorded with package `0.26.1-2` and Hyprland `-2`. The 0.32.0 source and its Omarchy patch, the Aquamarine and glibc updates, and the Driver 0.33.4 pairing need their own application and Driver replay before promotion. Hyprland `0.56.2-4`, Aquamarine `0.15.1-1` and glibc `2.44+r50+g1848099f063e-1` must all reach a destination channel before this artifact can be installed there; publication still follows edge → RC → stable.
The generated `PKGBUILD` identifies the immutable kit download, outer checksum, The generated `PKGBUILD` identifies the immutable kit download, outer checksum,
and member checksums. The kit records the full source and tooling revisions, and member checksums. The kit records the full source and tooling revisions,
+1 -1
View File
@@ -2,7 +2,7 @@
pkgname=cursor-bin pkgname=cursor-bin
pkgver=3.23.23 pkgver=3.23.23
pkgrel=1 pkgrel=2
pkgdesc='AI-first coding environment' pkgdesc='AI-first coding environment'
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://www.cursor.com" url="https://www.cursor.com"
+1 -1
View File
@@ -8,7 +8,7 @@ pkgver=2026.10.01.1.e373342
# Derive the upstream version (YYYY.MM.DD-<hash>) from that pkgver. # Derive the upstream version (YYYY.MM.DD-<hash>) from that pkgver.
_upstream_ver="${pkgver%.*}" _upstream_ver="${pkgver%.*}"
_upstream_ver="${_upstream_ver%.*}-${pkgver##*.}" _upstream_ver="${_upstream_ver%.*}-${pkgver##*.}"
pkgrel=1 pkgrel=2
# epoch=1: bumped when switching from the original `20250808.0.<sha>` scheme # epoch=1: bumped when switching from the original `20250808.0.<sha>` scheme
# to the current `YYYY.MM.DD.<n>.<hash>` scheme (2025-08-09). Never decrease. # to the current `YYYY.MM.DD.<n>.<hash>` scheme (2025-08-09). Never decrease.
epoch=1 epoch=1
+1 -1
View File
@@ -3,7 +3,7 @@
pkgname=disktree-bin pkgname=disktree-bin
_name=disktree _name=disktree
pkgver=0.11.0 pkgver=0.11.0
pkgrel=1 pkgrel=2
pkgdesc="Disk space treemap for Omarchy: see what fills a disk by kind, mark what should go, and remove it" pkgdesc="Disk space treemap for Omarchy: see what fills a disk by kind, mark what should go, and remove it"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://github.com/tobi/disktree" url="https://github.com/tobi/disktree"
+1 -1
View File
@@ -7,7 +7,7 @@
pkgname=dropbox-cli pkgname=dropbox-cli
pkgver=2026.09.28 pkgver=2026.09.28
pkgrel=2 pkgrel=3
pkgdesc="Command line interface for Dropbox" pkgdesc="Command line interface for Dropbox"
arch=("any") arch=("any")
url="https://www.dropbox.com" url="https://www.dropbox.com"
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-all",
"commit": "5614a0a61616643e448fb7c68d58237715ce2739"
}
}
-47
View File
@@ -1,47 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-all
pkgver=2.22.1
pkgrel=1
pkgdesc='elephant + all official elephant providers'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
depends=('libqalculate' 'wl-clipboard' 'imagemagick' 'fd' 'wtype' 'jq' 'sqlite3')
makedepends=('go')
conflicts=('elephant' 'elephant-playerctl' 'elephant-wireplumber' 'elephant-bitwarden' 'elephant-dnfpackages' 'elephant-1password' 'elephant-bookmarks' 'elephant-nirisessions' 'elephant-niriactions' 'elephant-archlinuxpkgs' 'elephant-bluetooth' 'elephant-calc' 'elephant-clipboard' 'elephant-desktopapplications' 'elephant-files' 'elephant-menus' 'elephant-providerlist' 'elephant-runner' 'elephant-snippets' 'elephant-symbols' 'elephant-todo' 'elephant-unicode' 'elephant-websearch' 'elephant-windows')
provides=('elephant' 'elephant-playerctl' 'elephant-wireplumber' 'elephant-nirisessions' 'elephant-niriactions' 'elephant-archlinuxpkgs' 'elephant-bluetooth' 'elephant-calc' 'elephant-clipboard' 'elephant-desktopapplications' 'elephant-files' 'elephant-menus' 'elephant-providerlist' 'elephant-runner' 'elephant-snippets' 'elephant-symbols' 'elephant-todo' 'elephant-unicode' 'elephant-websearch' 'elephant-windows')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
# Build main elephant binary
cd elephant-${pkgver}/cmd/elephant
go build -ldflags="-s -w" -buildvcs=false -x -o elephant -trimpath
# Build all provider plugins
cd ../../internal/providers
# Build each provider
for provider in playerctl wireplumber archlinuxpkgs bitwarden dnfpackages 1password bookmarks bluetooth nirisessions niriactions calc clipboard desktopapplications files menus providerlist runner snippets symbols todo unicode websearch windows; do
cd $provider
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
cd ..
done
}
package() {
# Install main elephant binary
cd elephant-${pkgver}/cmd/elephant
install -Dm 755 elephant -t "${pkgdir}/usr/bin"
# Install all provider plugins
cd ../../internal/providers
for provider in playerctl wireplumber archlinuxpkgs bitwarden dnfpackages bookmarks 1password nirisessions niriactions bluetooth calc clipboard desktopapplications files menus providerlist runner snippets symbols todo unicode websearch windows; do
install -Dm 755 $provider/$provider.so -t "${pkgdir}/usr/lib/elephant"
done
# Install license
cd ../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-archlinuxpkgs",
"commit": "659b81f1aa74a13fd2ebec222e19da2046d8e977"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-archlinuxpkgs
pkgver=2.22.1
pkgrel=1
pkgdesc='archlinuxpkgs provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-archlinuxpkgs')
provides=('elephant-archlinuxpkgs')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/archlinuxpkgs
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/archlinuxpkgs
install -Dm 755 archlinuxpkgs.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-bluetooth",
"commit": "42d9dd5424884c51b8fe6bf7692caf0a31007f05"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-bluetooth
pkgver=2.22.1
pkgrel=1
pkgdesc='bluetooth provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-bluetooth')
provides=('elephant-bluetooth')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/bluetooth
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/bluetooth
install -Dm 755 bluetooth.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-calc",
"commit": "84aba9e90bbd65af45f83168cd6c7bce6ec4322e"
}
}
-28
View File
@@ -1,28 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-calc
pkgver=2.22.1
pkgrel=1
pkgdesc='calc provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
depends=('libqalculate')
makedepends=('go')
conflicts=('elephant-calc')
provides=('elephant-calc')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/calc
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/calc
install -Dm 755 calc.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-clipboard",
"commit": "3176f9de1445e7115009383f9cdac116729fc7be"
}
}
-28
View File
@@ -1,28 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-clipboard
pkgver=2.22.1
pkgrel=1
pkgdesc='clipboard provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
depends=('wl-clipboard' 'imagemagick')
makedepends=('go')
conflicts=('elephant-clipboard')
provides=('elephant-clipboard')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/clipboard
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/clipboard
install -Dm 755 clipboard.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-desktopapplications",
"commit": "c30e33db5fef912dec9aa157773b10ffab1e0307"
}
}
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-desktopapplications
pkgver=2.22.1
pkgrel=1
pkgdesc='desktopapplications provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-desktopapplications')
provides=('elephant-desktopapplications')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/desktopapplications
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/desktopapplications
install -Dm 755 desktopapplications.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-files",
"commit": "2d16502b7a905e7d7a03e0026c5519c3b3c4abf2"
}
}
-28
View File
@@ -1,28 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-files
pkgver=2.22.1
pkgrel=1
pkgdesc='files provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
depends=('fd')
makedepends=('go')
conflicts=('elephant-files')
provides=('elephant-files')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/files
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/files
install -Dm 755 files.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-menus",
"commit": "5ab583fee6ba3e387d49ffe4e409bb84bc60ea24"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-menus
pkgver=2.22.1
pkgrel=1
pkgdesc='menus provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-menus')
provides=('elephant-menus')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/menus
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/menus
install -Dm 755 menus.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-providerlist",
"commit": "1d756a138e926a81b9d33265f0197b8661168845"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-providerlist
pkgver=2.22.1
pkgrel=1
pkgdesc='providerlist provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-providerlist')
provides=('elephant-providerlist')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/providerlist
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/providerlist
install -Dm 755 providerlist.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-runner",
"commit": "e47641530d912199372204cf8780ef37f99f0b37"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-runner
pkgver=2.22.1
pkgrel=1
pkgdesc='runner provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-runner')
provides=('elephant-runner')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/runner
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/runner
install -Dm 755 runner.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-symbols",
"commit": "32263e8b71390ab38b8aa1fd82fc2595b41a5157"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-symbols
pkgver=2.22.1
pkgrel=1
pkgdesc='symbols provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-symbols')
provides=('elephant-symbols')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/symbols
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/symbols
install -Dm 755 symbols.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-todo",
"commit": "447978df5ea3afd1e10959d7973c0b35367724c3"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-todo
pkgver=2.22.1
pkgrel=1
pkgdesc='todo provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-todo')
provides=('elephant-todo')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/todo
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/todo
install -Dm 755 todo.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-unicode",
"commit": "23222b0d304a234c74f630c5b9176d58c6c6e0b3"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-unicode
pkgver=2.22.1
pkgrel=1
pkgdesc='unicode provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-unicode')
provides=('elephant-unicode')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/unicode
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/unicode
install -Dm 755 unicode.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant-websearch",
"commit": "6b5da831da33e3533593823826a8ffb1a008a299"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant-websearch
pkgver=2.22.1
pkgrel=1
pkgdesc='websearch provider for elephant'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant-websearch')
provides=('elephant-websearch')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd elephant-${pkgver}/internal/providers/websearch
go build -ldflags="-s -w" -buildvcs=false -buildmode=plugin -trimpath
}
package() {
cd elephant-${pkgver}/internal/providers/websearch
install -Dm 755 websearch.so -t "${pkgdir}/usr/lib/elephant"
cd ../../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
-13
View File
@@ -1,13 +0,0 @@
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/elephant",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
},
"origin": {
"aur": "elephant",
"commit": "6dd02e6987a7a91be6a33e9600147523efa7fa5a"
}
}
-27
View File
@@ -1,27 +0,0 @@
# Maintainer: Andrej Benz <hello[at]benz[dot]dev>
pkgname=elephant
pkgver=2.22.1
pkgrel=1
pkgdesc='general purpose datasource and executor'
url='https://github.com/abenz1267/elephant'
arch=('x86_64' 'aarch64')
license=('GPL')
makedepends=('go')
conflicts=('elephant')
provides=('elephant')
source=("${url}/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('3d1d0d4c55ae531fa3f06406b96504b5165a0d7b53523d1f8351d9d93e457f44')
build() {
cd ${pkgname}-${pkgver}/cmd/elephant
go build -ldflags="-s -w" -buildvcs=false -x -o elephant -trimpath
}
package() {
cd ${pkgname}-${pkgver}/cmd/elephant
install -Dm 755 elephant -t "${pkgdir}/usr/bin"
cd ../../
install -Dm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
}
+1 -1
View File
@@ -2,7 +2,7 @@
pkgname=flea pkgname=flea
pkgver=0.3.7 pkgver=0.3.7
pkgrel=1 pkgrel=2
pkgdesc='Fast, keyboard-first file manager for Omarchy' pkgdesc='Fast, keyboard-first file manager for Omarchy'
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url='https://github.com/thisisgm/flea' url='https://github.com/thisisgm/flea'
+1 -1
View File
@@ -7,7 +7,7 @@ pkgname=github-copilot-cli
_pkgexec=copilot _pkgexec=copilot
pkgver=1.0.92 pkgver=1.0.92
pkgrel=1 pkgrel=2
pkgdesc="GitHub Copilot CLI brings the power of Copilot coding agent directly to your terminal." pkgdesc="GitHub Copilot CLI brings the power of Copilot coding agent directly to your terminal."
+1 -1
View File
@@ -8,7 +8,7 @@
pkgname=google-chrome pkgname=google-chrome
pkgver=155.0.8059.39 pkgver=155.0.8059.39
pkgrel=1 pkgrel=2
pkgdesc="The popular web browser by Google (Stable Channel)" pkgdesc="The popular web browser by Google (Stable Channel)"
arch=( arch=(
'x86_64' 'x86_64'
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"source": "local", "source": "local",
"sync": false, "release_ring": "fast",
"origin": { "origin": {
"aur": "grok-bot", "aur": "grok-bot",
"commit": "05eb78fca06b482affda28b26223cbf249d4bbcd" "commit": "05eb78fca06b482affda28b26223cbf249d4bbcd"
+84
View File
@@ -0,0 +1,84 @@
#!/bin/bash
# Cursor publishes Grok Bot from its own Debian repository, one index per
# architecture. Each index carries the version and the SHA256, so an update
# is two small HTTP requests instead of downloading the debs, and the pool
# URL is keyed by version. bin/sync-upstream can rewrite pkgver and the
# checksums; it cannot rewrite a commit id embedded in the old
# downloads.cursor.com/grokbot/stable/<commit>/ URL.
set -euo pipefail
BASE_URL="https://downloads.cursor.com/aptrepo"
declare -A DEB_ARCHES=([x86_64]=amd64 [aarch64]=arm64)
# Print "<version> <sha256>" for the newest grok-bot stanza. 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. The winner's Filename
# must be the versioned pool path the PKGBUILD downloads from.
newest_release() {
local index="$1" debarch="$2"
local version sha256 filename best_version="" best_sha256="" best_filename=""
while read -r version sha256 filename; do
[[ -n "$version" && -n "$sha256" ]] || continue
if [[ -z "$best_version" ]] || [[ "$(vercmp "$version" "$best_version")" -gt 0 ]]; then
best_version="$version"
best_sha256="$sha256"
best_filename="$filename"
fi
done < <(awk '
{ sub(/\r$/, "") }
/^Package:/ { package = $2 }
/^Version:/ { version = $2 }
/^SHA256:/ { sha256 = $2 }
/^Filename:/ { filename = $2 }
/^$/ {
if (package == "grok-bot" && version && sha256) print version, sha256, filename
package = version = sha256 = filename = ""
}
END {
if (package == "grok-bot" && version && sha256) print version, sha256, filename
}
' <<<"$index")
[[ -n "$best_version" ]] || return 1
local expected="pool/grok-bot/g/gr/grok-bot_${best_version}_${debarch}.deb"
if [[ "$best_filename" != "$expected" ]]; then
echo "Unexpected Grok Bot $best_version $debarch Filename: '${best_filename}' (expected $expected)" >&2
return 1
fi
echo "$best_version $best_sha256"
}
versions=()
declare -A checksums=()
for arch in "${!DEB_ARCHES[@]}"; do
index=$(curl -fsSL "$BASE_URL/dists/grok-bot/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 Grok Bot release found for $arch" >&2
exit 1
fi
versions+=("$version")
checksums[$arch]="$sha256"
done
# A release can land one architecture at a time. Wait until both agree so one
# pkgver always describes both artifacts.
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]}}'
+8 -6
View File
@@ -2,9 +2,8 @@
# Contributor: Omarchy # Contributor: Omarchy
pkgname=grok-bot pkgname=grok-bot
pkgver=0.47.0 pkgver=0.68.1
pkgrel=1 pkgrel=1
_commit=c1e7d7a46549956d25f53e9c0b9f59666e03aa3a
pkgdesc='Grok Bot desktop agent' pkgdesc='Grok Bot desktop agent'
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url='https://x.ai/bot' url='https://x.ai/bot'
@@ -30,20 +29,23 @@ install=grok-bot.install
_deb_x86_64="grok-bot_${pkgver}_amd64.deb" _deb_x86_64="grok-bot_${pkgver}_amd64.deb"
_deb_aarch64="grok-bot_${pkgver}_arm64.deb" _deb_aarch64="grok-bot_${pkgver}_arm64.deb"
# Versioned pool paths — Packages indexes carry SHA256 so upstream.sh
# can bump pkgver without embedding a Cursor commit id.
_pool="https://downloads.cursor.com/aptrepo/pool/grok-bot/g/gr"
source=( source=(
'grok-bot.sh' 'grok-bot.sh'
'grok-bot.desktop' 'grok-bot.desktop'
) )
source_x86_64=( source_x86_64=(
"${_deb_x86_64}::https://downloads.cursor.com/grokbot/stable/${_commit}/linux/x64/${_deb_x86_64}" "${_deb_x86_64}::${_pool}/${_deb_x86_64}"
) )
source_aarch64=( source_aarch64=(
"${_deb_aarch64}::https://downloads.cursor.com/grokbot/stable/${_commit}/linux/arm64/${_deb_aarch64}" "${_deb_aarch64}::${_pool}/${_deb_aarch64}"
) )
sha256sums=('6dfa6c305941afa6cbaefbeaae06d05ab5a88f31630005d25a819a160c20c7a3' sha256sums=('6dfa6c305941afa6cbaefbeaae06d05ab5a88f31630005d25a819a160c20c7a3'
'3e2a2461ea58d17ac1777616be9ba660f7cb9ceefa9292016e36c55758bf78dd') '3e2a2461ea58d17ac1777616be9ba660f7cb9ceefa9292016e36c55758bf78dd')
sha256sums_x86_64=('11ca0f51a535b97af51a352adf9c0f9ecd2e1b0430a69ae9451b688a7a065808') sha256sums_x86_64=('b2be8106d2b3eae07d983d5f1ca77b657accde666dc440db2a409421ecff3359')
sha256sums_aarch64=('836f8d19d3826c6573c31ac45c7a9b797abc73381ae0d2b1e7a8dae5410e7e46') sha256sums_aarch64=('3f85fbe2ba3c1d122aa16f8be672076bc19146e07e9d431f37a93b85fa75a93f')
noextract=("${_deb_x86_64}" "${_deb_aarch64}") noextract=("${_deb_x86_64}" "${_deb_aarch64}")
package() { package() {
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bash
# Resolve current Grok Bot stable from Cursor's update feed and pin PKGBUILD.
# Linux has no latest alias (linux-x64 feed returns 204). The darwin-arm64
# sand feed publishes version + commit; the Linux .deb lives at the same commit.
# Darwin can ship first — HEAD-check the Linux URL and fail loudly if 404.
set -euo pipefail
PKGBUILD_PATH="${1:-PKGBUILD}"
[[ -f "${PKGBUILD_PATH}" ]] || { echo "Error: PKGBUILD not found at '${PKGBUILD_PATH}'" >&2; exit 1; }
FEED='https://api2.cursor.sh/updates/api/update/darwin-arm64/sand/0.0.0/00000000-0000-0000-0000-000000000000/stable'
json="$(curl -fsSL -H 'cache-control: no-cache' "${FEED}")"
ver="$(jq -er '.name // .version' <<<"${json}")"
feed_url="$(jq -er '.url' <<<"${json}")"
commit="$(sed -nE 's@.*/(grokbot|sand)/stable/([0-9a-f]{40})/.*@\2@p' <<<"${feed_url}")"
[[ -n "${ver}" && -n "${commit}" ]] || {
echo "Error: could not parse version/commit from feed: ${json}" >&2
exit 1
}
deb_url="https://downloads.cursor.com/grokbot/stable/${commit}/linux/x64/Grok_Bot_${ver}.deb"
code="$(curl -fsSIL -o /dev/null -w '%{http_code}' "${deb_url}")"
[[ "${code}" == "200" ]] || {
echo "Error: Linux deb not fetchable (${code}): ${deb_url}" >&2
exit 1
}
tmp="$(mktemp)"
trap 'rm -f "${tmp}"' EXIT
curl -fL --retry 3 -o "${tmp}" "${deb_url}"
sum="$(sha256sum "${tmp}" | awk '{print $1}')"
current_ver="$(sed -nE 's/^pkgver=([^[:space:]#]+).*/\1/p' "${PKGBUILD_PATH}" | head -n1)"
sed -i -E \
-e "s/^_commit=.*/_commit=${commit}/" \
-e "s/^pkgver=.*/pkgver=${ver}/" \
-e "0,/^[[:space:]]*'[0-9a-f]{64}'/s// '${sum}'/" \
"${PKGBUILD_PATH}"
if [[ "${ver}" != "${current_ver}" ]]; then
sed -i -E 's/^pkgrel=.*/pkgrel=1/' "${PKGBUILD_PATH}"
fi
echo "${ver} ${commit}"
echo "${deb_url}"
echo "${sum}"
+1 -1
View File
@@ -5,7 +5,7 @@
pkgname=hermes-desktop pkgname=hermes-desktop
pkgver=2026.9.7 pkgver=2026.9.7
pkgrel=3 pkgrel=4
pkgdesc='Native desktop shell for Hermes Agent' pkgdesc='Native desktop shell for Hermes Agent'
arch=('x86_64') arch=('x86_64')
url='https://github.com/NousResearch/hermes-agent' url='https://github.com/NousResearch/hermes-agent'
@@ -1,21 +0,0 @@
{
"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"
}
}
}
-40
View File
@@ -1,40 +0,0 @@
# 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
}
@@ -2,7 +2,7 @@
pkgname="hyprland-preview-share-picker" pkgname="hyprland-preview-share-picker"
pkgver=0.2.1 pkgver=0.2.1
pkgrel=2 pkgrel=3
pkgdesc="An alternative share picker for hyprland with window and monitor previews" pkgdesc="An alternative share picker for hyprland with window and monitor previews"
arch=(x86_64 aarch64) arch=(x86_64 aarch64)
url="https://github.com/WhySoBad/hyprland-preview-share-picker" url="https://github.com/WhySoBad/hyprland-preview-share-picker"
+1 -1
View File
@@ -16,7 +16,7 @@
], ],
"rebuilt_against": { "rebuilt_against": {
"aarch64": { "aarch64": {
"aquamarine": "0.15.0-2" "aquamarine": "0.15.1-1.1"
} }
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@
pkgname=(hyprland hyprpm) pkgname=(hyprland hyprpm)
pkgver=0.56.2 pkgver=0.56.2
pkgrel=4 pkgrel=5
pkgdesc='a highly customizable dynamic tiling Wayland compositor' pkgdesc='a highly customizable dynamic tiling Wayland compositor'
arch=(aarch64) arch=(aarch64)
url="https://github.com/hyprwm/${pkgname^}" url="https://github.com/hyprwm/${pkgname^}"
@@ -1,21 +0,0 @@
{
"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"
}
}
}
-50
View File
@@ -1,50 +0,0 @@
# Maintainer: Caleb Maclennan <caleb@alerque.com>
pkgname=hyprtoolkit
pkgver=0.6.0
pkgrel=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=('53c41be72af97d9ede274a63c9c1034c58726d862905763ed6e5a564ae42ba6b')
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 -1
View File
@@ -2,7 +2,7 @@
pkgname=learn-omarchy pkgname=learn-omarchy
pkgver=0.2.5 pkgver=0.2.5
pkgrel=1 pkgrel=2
pkgdesc="Interactive, theme-aware courses for learning Omarchy" pkgdesc="Interactive, theme-aware courses for learning Omarchy"
arch=('any') arch=('any')
url="https://github.com/DanWahlin/learn-omarchy" url="https://github.com/DanWahlin/learn-omarchy"
+1 -1
View File
@@ -16,7 +16,7 @@
pkgname=libfprint-git pkgname=libfprint-git
pkgver=1.94.100.r10.g6f9479c pkgver=1.94.100.r10.g6f9479c
pkgrel=2 pkgrel=3
# Retain the epoch used to supersede the previously published untested build. # Retain the epoch used to supersede the previously published untested build.
epoch=1 epoch=1
pkgdesc="Library for fingerprint readers (pinned upstream snapshot with FocalTech and Synaptics 06cb:010b support, and Apple Touch ID on aarch64)" pkgdesc="Library for fingerprint readers (pinned upstream snapshot with FocalTech and Synaptics 06cb:010b support, and Apple Touch ID on aarch64)"
@@ -8,5 +8,10 @@
}, },
"rebuild_on": [ "rebuild_on": [
"libva" "libva"
] ],
"rebuilt_against": {
"aarch64": {
"libva": "2.24.1-1"
}
}
} }
+1 -1
View File
@@ -4,7 +4,7 @@
_fork=sofus13 _fork=sofus13
pkgname=libva-v4l2_request-avd pkgname=libva-v4l2_request-avd
pkgver=1.3 pkgver=1.3
pkgrel=1 pkgrel=2
pkgdesc='VA-API driver for V4L2 stateless decoders, with Apple Video Decoder (AVD) support' pkgdesc='VA-API driver for V4L2 stateless decoders, with Apple Video Decoder (AVD) support'
arch=('aarch64') arch=('aarch64')
url="https://github.com/$_fork/libva-v4l2_request" url="https://github.com/$_fork/libva-v4l2_request"
+1 -1
View File
@@ -3,7 +3,7 @@ _pkgname="limine-entry-tool"
pkgname="limine-mkinitcpio-hook" pkgname="limine-mkinitcpio-hook"
_gradle_version=9.7.1 _gradle_version=9.7.1
pkgver=1.40.0 pkgver=1.40.0
pkgrel=1 pkgrel=2
pkgdesc="Install kernels for the Limine bootloader." pkgdesc="Install kernels for the Limine bootloader."
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://gitlab.com/Zesko/limine-entry-tool" url="https://gitlab.com/Zesko/limine-entry-tool"
+1 -1
View File
@@ -1,7 +1,7 @@
# Maintainer: Zesko # Maintainer: Zesko
pkgname="limine-snapper-sync" pkgname="limine-snapper-sync"
pkgver=1.32.1 pkgver=1.32.1
pkgrel=1 pkgrel=2
_gradle_version=9.7.1 _gradle_version=9.7.1
pkgdesc="Integrates Limine boot entries with Snapper snapshots." pkgdesc="Integrates Limine boot entries with Snapper snapshots."
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
@@ -2,7 +2,7 @@
pkgname=linux-firmware-cirrus-dx13260 pkgname=linux-firmware-cirrus-dx13260
pkgver=20260810 pkgver=20260810
pkgrel=1 pkgrel=2
pkgdesc="Cirrus speaker firmware aliases for Dell XPS 13 DX13260 Panther Lake" pkgdesc="Cirrus speaker firmware aliases for Dell XPS 13 DX13260 Panther Lake"
arch=('x86_64') arch=('x86_64')
url="https://gitlab.com/kernel-firmware/linux-firmware" url="https://gitlab.com/kernel-firmware/linux-firmware"
@@ -1,5 +0,0 @@
{
"source": "local",
"release_ring": "fast",
"sync": false
}
-63
View File
@@ -1,63 +0,0 @@
# Maintainer: Spencer Bull <spencerbull2554@gmail.com>
#
# Self-retiring shim: ships Arch's linux-firmware-cirrus 20260910-2 payload to
# the stable channel while stable's pinned Arch snapshot is still on
# linux-firmware 20260810-2 (which lacks the Dell XPS 13 DX13260 / 1028:0e54
# CS35L56 amplifier firmware aliases, leaving that machine's speakers silent).
#
# Nothing is rebuilt. The signed Arch package is verified against the Arch
# packager key and its payload reinstalled as-is, minus the files that Arch
# moved out of linux-firmware-other in 20260910 (the cs42l45 SDCA tree): on
# the stable snapshot those are still owned by linux-firmware-other 20260810-2
# and would conflict, so they are left to that package.
#
# Versioning is deliberate: 20260810-3 orders above the snapshot's 20260810-2
# and BELOW Arch's real 20260910-2, so as soon as the stable snapshot advances
# pacman replaces this shim with the genuine package in the same transaction
# that upgrades linux-firmware-other, and nothing is lost. Delete this recipe
# once stable's snapshot is at linux-firmware >= 20260910.
pkgname=linux-firmware-cirrus
pkgver=20260810
pkgrel=3
_fwver=20260910
_fwrel=2
_basever=20260810
_baserel=2
pkgdesc="Firmware files for Linux - Firmware for Cirrus Logic audio devices (Arch - payload, stable-snapshot shim)"
arch=('any')
url="https://gitlab.com/kernel-firmware/linux-firmware"
license=('LicenseRef-WHENCE' 'LicenseRef-cirrus')
depends=('linux-firmware-whence')
options=('!strip' '!debug')
_cirrus="linux-firmware-cirrus-${_fwver}-${_fwrel}-any.pkg.tar.zst"
_other="linux-firmware-other-${_basever}-${_baserel}-any.pkg.tar.zst"
source=(
"https://archive.archlinux.org/packages/l/linux-firmware-cirrus/${_cirrus}"
"https://archive.archlinux.org/packages/l/linux-firmware-cirrus/${_cirrus}.sig"
"https://archive.archlinux.org/packages/l/linux-firmware-other/${_other}"
"https://archive.archlinux.org/packages/l/linux-firmware-other/${_other}.sig"
)
noextract=("${_cirrus}" "${_other}")
sha256sums=('70100c551b079bd8abec3d9c96a16defd04766b2a4afc6d7be9128d37e9840f7'
'SKIP'
'b0f016ee0d0532b977211b0cbb630bca75184f68a9ace82675eb3cf9acce4f6c'
'SKIP')
# Jan Alexander Steffens (heftig) <heftig@archlinux.org>, Arch Linux packager
validpgpkeys=('83BC8889351B5DEBBB68416EB8AC08600F108CDF')
package() {
# Payload only; makepkg regenerates .PKGINFO/.MTREE/.BUILDINFO.
bsdtar -xf "${srcdir}/${_cirrus}" -C "${pkgdir}" \
--exclude='.PKGINFO' --exclude='.MTREE' --exclude='.BUILDINFO' \
--exclude='.INSTALL' --exclude='.CHANGELOG'
# Drop every file the snapshot's linux-firmware-other still owns.
local f
while IFS= read -r f; do
[[ -e "${pkgdir}/${f}" || -L "${pkgdir}/${f}" ]] && rm -f "${pkgdir}/${f}"
done < <(bsdtar -tf "${srcdir}/${_other}" | grep -v '^\.' | grep -v '/$')
# Remove directories emptied by the step above.
find "${pkgdir}/usr/lib/firmware" -depth -type d -empty -delete
}
@@ -1,60 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEZXeS9hYJKwYBBAHaRw8BAQdAT04Na8ee0UltkhyNi2RGHYdjZDgg+X/K8Jix
dSSQ+Ni0NkphbiBBbGV4YW5kZXIgU3RlZmZlbnMgKGhlZnRpZykgPGhlZnRpZ0Bh
cmNobGludXgub3JnPoiQBBMWCgA4AhsDAheAFiEEg7yIiTUbXeu7aEFuuKwIYA8Q
jN8FAmWq/kcFCwkIBwMFFQoJCAsFFgIDAQACHgUACgkQuKwIYA8QjN+2qAEAh/RL
Zq7Hmqv/z09yq0m6IEb0kbXaW50POi/V+2VcJ9wBAN5Ik/fFgnGMlvZF7Rugu37o
2fk7jnUVsWJca9QmytgGiHUEEBYKAB0WIQSZtmGEcqOzuBQYW67X09gjuIvbmwUC
aYWy0QAKCRDX09gjuIvbm7vJAP9xqmmI8jNGEUQNidh9yZCmVOr3vT5/sUcHGo0J
08o/TgD/Wix2/4DHfnk6fu+onERrK5uF9BAacERnCsG5lMWQ2wSJAjMEEAEKAB0W
IQSR/+BwDoBhnOtzI1yojiPjd1FOAAUCZa0cywAKCRCojiPjd1FOAIKbEACipPSS
sA2G7ntHRGEHSWKgqEKseGGr7kflVdsmJn1tjKI8/VGKa77NkCRgqIJRwmE9m9+F
Cx+a3ILmMOxsjj5RCVFce9NJuscVGHaphZcp7Z0MVoR9hhtnsyjWk/CYOAv+JLKq
NTYhdmat+ixY4fwPzjdV6sxCDL/s6Fci0zPLUam7QVr9LIS4U3UH7smkKj6jM+G/
sEn0QM02EKy2iJLlbPNN3pppYWqZ5p9xXeB6EJ89JvZMI3k92xy456JjkCgLN860
NPmdmnLLtlrGWJRgNK6+iaFjLt/BL9gU8aGe+K3ONXES2k7iZnh+oLAEV8Z07dgv
Gd0o+OFEPrC8kETbQK45r1yAjZVO+tp4dSxvV/BD+7KhUXAZnOKWLaOMomfsG17E
KKa894cBLJG7LWN/d/Uk9fjfjd4ZYbSpIALJiEoKrm1ytj2KgnxKveTtY69i63/N
0BpNVrkYIJffWR6zSosC8geAWfqm7pR6JARUAZrw0YtJbluDrRgOO0XFn8hDqRUm
FPWgXuvqNdR2JyD4aB87LKGhzVFzQvbHa+S4sG7+w5nWQB0Eca+hiVpJDpMYjoU+
f+L3yUb6POwvUJe7VT/2PYOwidnV3guTevnn9a4erKoW/6wKAr13cW+KTKTR0bdC
S0UTOWbJnbi2Hfhyr7NZgs4T4OcpH3kj+R4WPIkCMwQQAQoAHRYhBNiv3aB6W27f
p9jM2tbQVfknhD8cBQJlg4C5AAoJENbQVfknhD8cpPQP/19uAVMaG1lQNaAK9XWT
Z1/lAr6sxYT6B2+MqnRtbkr4Gh3ts7Ey5BI39HxNWRIUGUt7pq4FjCQxWeJC9mfp
/hqj9rl1s32lbBzevbkjESro+cHPfrv0vsVlwJA2W3rURQlQzbEq3fvDzc/wz4sN
vgQDiUlxH5JYXZ5OexsDATLyfHNpJh+4NxqB24axjDe/1ZK8hoYl+eX46dP9JKWB
F8GA3Ebwst3de/81oNngBjDgNPju6cvgykoT2jCBn4asp1xKekZh5ZbRG40jAeoQ
QAvEgTxIbwNf4HBVhvGjQ6G5lCNO6gQonq1X4UbHgH8tRGSSgnz2yDAdcxtaj1eC
e5BMhjuoHuxS4DCtR97Dtn7YjrYoVus5eMkhEZGuWKK4hkggsLbyUx5llxZxLXPD
mBAYLkqgZsHgiqLeHAdrEmAFaRfskVg0MzfCcEE9StWnWf0ixk3thuwQAaPI4GCB
nNLnmqCcOyCN1Qa3iXjdOzp5bU0qwFi/qFQagq0nu8sJim7q0g0Bk7J+iGRht3no
L5iT9d+8CQaN1it+L+elSYfrr/LamghRvh9epOtGUVH3GQYS4Bgo2rgktGXKtcX+
P/jR/aM034g8VPlbV+Kas/c6mIk9JzKOvJJ4+Lpvr0ZzRG32ez9dAlDogE3xASi6
sMWbY+t4unGs+nY3SqIOyHLTiHUEEBYKAB0WIQRp5kceOuBlKXUpgy5roPWiA39P
QQUCZX7ZYAAKCRBroPWiA39PQadvAQD7F/N3xuyWogrJV7TMZk2PFteviEW2Dv9d
dSUGasK3dQEAxf3HxRDvrv3yJLhgNKa+ksr4bBBmruvilpWS+X4InwKIdQQQFgoA
HRYhBDVy+iobBn8ixYrxVfi4IbQqb9zXBQJlfKbrAAoJEPi4IbQqb9zXe7MBAIzF
QqdV8CJXYIcZJtUUIQ7a/AN2enHBpoa/qXEre5bAAP4uNEUMKiDZRpHAh/KmqarM
vF+c1BOpEJbQsPqv0L5hDIh1BBAWCgAdFiEEKsCkLvsLXLx6BALtTclbbXvpiS4F
AmV8nsgACgkQTclbbXvpiS6bpwD/W0sMOH4lmR4t9Sc8hJB+uBLGYxzoNIgaNa5x
vbdm5hwBAIPYr1SVl0+yghsxg5k75jStRL2S5MZW2iSV3ynNLTkFiHkEEBYKACEW
IQSi/zo2qqVmVBCQZKsZgC+LDXD8MAUCZXe6yAMFAngACgkQGYAviw1w/DCmCAD8
Cfvn8O+N/AJTOKY8lZzk+OSX3tSTQTOUiLHKRl+RX6IA/1Bku44c1YJVZ+RhWkGQ
n0C8ZN/DYzHh9JInl3blLcIMtDhKYW4gQWxleGFuZGVyIFN0ZWZmZW5zIChoZWZ0
aWcpIDxqYW4uc3RlZmZlbnNAZ21haWwuY29tPoiTBBMWCgA7AhsDAheAAhkBFiEE
g7yIiTUbXeu7aEFuuKwIYA8QjN8FAmWq/kIFCwkIBwMFFQoJCAsFFgIDAQACHgUA
CgkQuKwIYA8QjN+ySAD+PI99JJsFWz2CaS3enxjUMCWJZJvSV9G1FqmeTKtH95oA
/ismVRjBbwbCrDDEsZVIK3NeRyRyhiWIVFXWix/KnH4CiHkEEBYKACEWIQSi/zo2
qqVmVBCQZKsZgC+LDXD8MAUCZXe6xQMFAngACgkQGYAviw1w/DDnzAD6AwROKYI8
7DZ6a1onZeR5wOV50bt2LCB4XxNiupHcpLMA/i4dmwa4Bkzyh/h+v0kN2PSssueX
7kFPNcnyhe3KbUUDuDMEZXeUSxYJKwYBBAHaRw8BAQdAkvIbYwde3OFqoAy6QOO9
BPwFNCll8tgQ6iAmQMkOjtWIeAQYFgoAIBYhBIO8iIk1G13ru2hBbrisCGAPEIzf
BQJld5RLAhsgAAoJELisCGAPEIzfhU8A/3NZzIEk3dmCAL0XLtylcFp/HExnN+5Q
RGmT0+SzzuGaAP9ozoMlSjtcGLAZMglLk8/mYzKveR89RJlB0cZtUU6UArg4BGV3
kvYSCisGAQQBl1UBBQEBB0Dh/7CubQh/MabODq3IcoqeGUzEGUPU8GXCVrDmPHih
WQMBCAeIeAQYFgoAIBYhBIO8iIk1G13ru2hBbrisCGAPEIzfBQJld5L2AhsMAAoJ
ELisCGAPEIzfao0A/AiJPB4igiyHjPgR8OpKh4Nz+pwmFrD/j5l2YC0Xi2dOAP4j
LDEa1VCNNhq7vWA8SqUjareBzHpwlG2ObUwYxORjBQ==
=OXp6
-----END PGP PUBLIC KEY BLOCK-----
@@ -0,0 +1,4 @@
{
"source": "local",
"skip_build": true
}
@@ -0,0 +1,55 @@
diff --git a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -127,6 +127,12 @@
#include <kunit/visibility.h>
+#ifdef CONFIG_USER_NS
+static int unprivileged_userns_clone = 1;
+#else
+#define unprivileged_userns_clone 1
+#endif
+
/*
* Minimum number of threads to boot the kernel
*/
@@ -2092,6 +2098,11 @@ __latent_entropy struct task_struct *copy_process(
return ERR_PTR(-EPERM);
}
+ if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) {
+ if (!capable(CAP_SYS_ADMIN))
+ return ERR_PTR(-EPERM);
+ }
+
/*
* Force any signals received before this point to be delivered
* before the fork happens. Collect up signals sent to multiple
@@ -3165,6 +3176,10 @@ static int check_unshare_flags(unsigned long unshare_flags)
if (!current_is_single_threaded())
return -EINVAL;
}
+ if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ }
return 0;
}
@@ -3400,6 +3415,15 @@ static const struct ctl_table fork_sysctl_table[] = {
.mode = 0644,
.proc_handler = sysctl_max_threads,
},
+#ifdef CONFIG_USER_NS
+ {
+ .procname = "unprivileged_userns_clone",
+ .data = &unprivileged_userns_clone,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+#endif
};
static int __init init_fork_sysctl(void)
@@ -0,0 +1,31 @@
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -935,6 +935,9 @@ KBUILD_RUSTFLAGS += -Copt-level=2
else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os
KBUILD_RUSTFLAGS += -Copt-level=s
+else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
+KBUILD_CFLAGS += -O3
+KBUILD_RUSTFLAGS += -Copt-level=3
endif
# Always set `debug-assertions` and `overflow-checks` because their default
diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1622,6 +1622,14 @@ config CC_OPTIMIZE_FOR_SIZE
Choosing this option will pass "-Os" to your compiler resulting
in a smaller kernel.
+config CC_OPTIMIZE_FOR_PERFORMANCE_O3
+ bool "Optimize harder for performance (-O3)"
+ help
+ Build with the "-O3" compiler flag: more inlining, loop
+ unrolling and vectorization than -O2, at the cost of a larger
+ kernel image and larger modules. Rust code is built at
+ opt-level 3.
+
endchoice
config HAVE_LD_DEAD_CODE_DATA_ELIMINATION
File diff suppressed because it is too large. Load diff
Loaded 100 of 479 files, more files were not shown because too many files have changed in this diff. Show more