Expand declarative upstream providers
This commit is contained in:
17 files changed
+372
-209
No files matched your search
@@ -322,9 +322,49 @@ recent releases are considered. The provider fails closed on anything it cannot
|
||||
read — an unusable tag, timestamp, or checksum stops the sync rather than being
|
||||
skipped.
|
||||
|
||||
A package may also declare `"min_release_age": "24h"` (`s`/`m`/`h`/`d` suffix or
|
||||
bare seconds) to quarantine fresh releases until maintainers have had time to
|
||||
pull a bad or compromised one. The newest release that has cleared the window
|
||||
Projects that publish version tags but no checksum manifest can declare the
|
||||
tag repository, the exact tag shape, and every source that should be hashed:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/owner/project.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://github.com/owner/project/archive/refs/tags/{tag}.tar.gz"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The newest matching tag is selected with pacman's `vercmp`; unrelated tags are
|
||||
ignored. `tag_pattern` must contain exactly one `{pkgver}`. Source templates may
|
||||
use `{tag}` and `{pkgver}`. Each expanded URL must be HTTPS and is downloaded
|
||||
only when the discovered version is newer. A checked-in patch or other local
|
||||
source can be included as `file:patch-name.patch`; it is hashed from the package
|
||||
directory. Keys such as `any`, `x86_64`, and `aarch64` select the corresponding
|
||||
`sha256sums` array.
|
||||
|
||||
npm packages use the same source mapping, with `{npm_tarball}` available for
|
||||
the tarball named by the selected dist-tag:
|
||||
|
||||
```json
|
||||
"upstream": {
|
||||
"npm": "@scope/package",
|
||||
"dist_tag": "latest",
|
||||
"sources": {
|
||||
"any": ["{npm_tarball}", "https://example.com/v{pkgver}/CHANGELOG.md"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`dist_tag` defaults to `latest`. The registry's publication timestamp is
|
||||
carried into the provider result, so `min_release_age` works for npm packages.
|
||||
Exactly one of `github`, `git_tags`, or `npm` may appear in a declaration.
|
||||
|
||||
A timestamped provider may also declare `"min_release_age": "24h"`
|
||||
(`s`/`m`/`h`/`d` suffix or bare seconds) to quarantine fresh releases until
|
||||
maintainers have had time to pull a bad or compromised one. GitHub Releases and
|
||||
npm provide publication times; raw git tags do not, so combining `git_tags`
|
||||
with this policy fails closed. The newest release that has cleared the window
|
||||
ships, so a fast release cadence cannot starve updates. The window is enforced
|
||||
centrally: whatever reports the release must prove its age via `published_at`,
|
||||
or the sync fails. A maintainer deliberately shipping inside the window runs
|
||||
|
||||
+90
-16
@@ -18,11 +18,11 @@ Usage: $0 [PACKAGE...]
|
||||
|
||||
Update packages that track an upstream vendor release feed instead of the AUR.
|
||||
|
||||
A package whose upstream ships tagged GitHub releases with a checksum manifest
|
||||
opts in declaratively, via "upstream" in .omarchy/package.json (see
|
||||
helpers/upstream-github.sh for the schema); no code needed. Anything with a
|
||||
bespoke feed provides pkgbuilds/<package>/.omarchy/upstream.sh instead, a hook
|
||||
that reports the newest upstream release as JSON on stdout:
|
||||
Packages opt in declaratively through "upstream" in .omarchy/package.json.
|
||||
Providers cover GitHub Releases with checksum manifests, semver-shaped git
|
||||
tags whose source URLs can be hashed, and npm dist-tags. See README.md for the
|
||||
schemas. Anything outside those conventions may provide
|
||||
pkgbuilds/<package>/.omarchy/upstream.sh, a hook that reports JSON on stdout:
|
||||
|
||||
{
|
||||
"pkgver": "1.2.3",
|
||||
@@ -332,27 +332,27 @@ sync_package() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
local github_repo has_upstream=false
|
||||
github_repo=$(package_upstream_github_repo "$package_dir")
|
||||
local provider has_upstream=false
|
||||
provider=$(package_upstream_provider "$package_dir")
|
||||
if package_has_upstream_provider "$package_dir"; then
|
||||
has_upstream=true
|
||||
fi
|
||||
|
||||
# A present-but-unusable declaration fails loudly; treating it like "no
|
||||
# upstream source" would silently drop the package from scheduled runs.
|
||||
if [[ "$has_upstream" == true && -z "$github_repo" ]]; then
|
||||
print_error "Package $package has an unusable upstream declaration (needs a github owner/repo)"
|
||||
if [[ "$has_upstream" == true && -z "$provider" ]]; then
|
||||
print_error "Package $package has an unusable or ambiguous upstream declaration"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "$github_repo" && -f "$hook" ]]; then
|
||||
print_error "Package $package declares both upstream.github and an upstream.sh hook; keep exactly one"
|
||||
if [[ -n "$provider" && -f "$hook" ]]; then
|
||||
print_error "Package $package declares both an upstream provider and an upstream.sh hook; keep exactly one"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -z "$github_repo" && ! -f "$hook" ]]; then
|
||||
if [[ -z "$provider" && ! -f "$hook" ]]; then
|
||||
if [[ "$SPECIFIC_MODE" == true ]]; then
|
||||
print_error "Package $package has neither an upstream declaration nor .omarchy/upstream.sh"
|
||||
((++FAILED))
|
||||
@@ -372,10 +372,15 @@ sync_package() {
|
||||
|
||||
print_info "Checking $package for upstream releases..."
|
||||
|
||||
local release
|
||||
if [[ -n "$github_repo" ]]; then
|
||||
if ! release=$(github_upstream_release "$package_dir" "$min_age"); then
|
||||
print_error "GitHub release provider failed for $package"
|
||||
local release release_status=0
|
||||
if [[ -n "$provider" ]]; then
|
||||
case "$provider" in
|
||||
github) release=$(github_upstream_release "$package_dir" "$min_age") || release_status=$? ;;
|
||||
git_tags) release=$(git_tags_upstream_release "$package_dir") || release_status=$? ;;
|
||||
npm) release=$(npm_upstream_release "$package_dir") || release_status=$? ;;
|
||||
esac
|
||||
if [[ ${release_status:-0} -ne 0 ]]; then
|
||||
print_error "$provider upstream provider failed for $package"
|
||||
((++FAILED))
|
||||
return 0
|
||||
fi
|
||||
@@ -614,10 +619,79 @@ EOF
|
||||
echo '{"source": "local", "upstream": {"github": "example/tool"}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "upstream without checksums/assets is rejected" "1" "$vst"
|
||||
echo '{"source":"local","upstream":{"github":"example/tool","git_tags":"https://example/tool.git","checksums":"sums","assets":{"any":"tool"}}}' > "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "multiple provider types are rejected" "1" "$vst"
|
||||
cp "$pkg/.omarchy/package.json" "$agepkg/.omarchy/package.json"
|
||||
vst=0; validate_package_metadata "$agepkg" >/dev/null || vst=$?
|
||||
check "the real declaration shape is accepted" "0" "$vst"
|
||||
|
||||
echo "Git-tag provider:"
|
||||
local tagpkg="$TEMP_DIR/selftest-tags" tag_sum remote_sum local_sum
|
||||
mkdir -p "$tagpkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=4\nsha256sums=("old" "old")\n' > "$tagpkg/PKGBUILD"
|
||||
printf 'local fixture\n' > "$tagpkg/local.patch"
|
||||
cat > "$tagpkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://example.test/tool.git",
|
||||
"tag_pattern": "release/{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://downloads.example.test/tool-{pkgver}.tar.gz", "file:local.patch"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
git_tags_fetch_refs() {
|
||||
printf '%s\n' \
|
||||
'aaaa refs/tags/release/1.9.0' \
|
||||
'bbbb refs/tags/release/1.10.0' \
|
||||
'cccc refs/tags/not-a-release'
|
||||
}
|
||||
upstream_fetch_source() { printf 'remote fixture for %s\n' "$1" > "$2"; }
|
||||
tag_sum=$(git_tags_upstream_release "$tagpkg")
|
||||
remote_sum=$(printf 'remote fixture for %s\n' 'https://downloads.example.test/tool-1.10.0.tar.gz' | sha256sum | cut -d' ' -f1)
|
||||
local_sum=$(sha256sum "$tagpkg/local.patch" | cut -d' ' -f1)
|
||||
check "pacman ordering selects 1.10.0 over 1.9.0" "1.10.0" "$(jq -r '.pkgver' <<<"$tag_sum")"
|
||||
check "remote source template is downloaded and hashed" "$remote_sum" "$(jq -r '.sha256sums.any[0]' <<<"$tag_sum")"
|
||||
check "local source entry is hashed" "$local_sum" "$(jq -r '.sha256sums.any[1]' <<<"$tag_sum")"
|
||||
vst=0; validate_package_metadata "$tagpkg" >/dev/null || vst=$?
|
||||
check "git-tags declaration validates" "0" "$vst"
|
||||
|
||||
echo "npm provider:"
|
||||
local npmpkg="$TEMP_DIR/selftest-npm" npm_sum npm_tar_sum npm_notes_sum
|
||||
mkdir -p "$npmpkg/.omarchy"
|
||||
printf 'pkgver=1.0.0\npkgrel=1\nsha256sums=("old" "old")\n' > "$npmpkg/PKGBUILD"
|
||||
cat > "$npmpkg/.omarchy/package.json" <<'EOF'
|
||||
{
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"npm": "@example/tool",
|
||||
"dist_tag": "latest",
|
||||
"sources": {
|
||||
"any": ["{npm_tarball}", "https://example.test/tool/{pkgver}/notes"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
npm_fetch_metadata() {
|
||||
jq -n '{
|
||||
"dist-tags": {latest: "2.0.0"},
|
||||
versions: {"2.0.0": {dist: {tarball: "https://registry.npmjs.org/@example/tool/-/tool-2.0.0.tgz"}}},
|
||||
time: {"2.0.0": "2024-01-02T03:04:05.000Z"}
|
||||
}'
|
||||
}
|
||||
npm_sum=$(npm_upstream_release "$npmpkg")
|
||||
npm_tar_sum=$(printf 'remote fixture for %s\n' 'https://registry.npmjs.org/@example/tool/-/tool-2.0.0.tgz' | sha256sum | cut -d' ' -f1)
|
||||
npm_notes_sum=$(printf 'remote fixture for %s\n' 'https://example.test/tool/2.0.0/notes' | sha256sum | cut -d' ' -f1)
|
||||
check "npm dist-tag selects its version" "2.0.0" "$(jq -r '.pkgver' <<<"$npm_sum")"
|
||||
check "npm tarball placeholder is hashed" "$npm_tar_sum" "$(jq -r '.sha256sums.any[0]' <<<"$npm_sum")"
|
||||
check "npm pkgver template is hashed" "$npm_notes_sum" "$(jq -r '.sha256sums.any[1]' <<<"$npm_sum")"
|
||||
check "npm publication time is preserved" "2024-01-02T03:04:05.000Z" "$(jq -r '.published_at' <<<"$npm_sum")"
|
||||
vst=0; validate_package_metadata "$npmpkg" >/dev/null || vst=$?
|
||||
check "npm declaration validates" "0" "$vst"
|
||||
|
||||
# End to end over the real mise-bin package: its checked-in metadata and
|
||||
# PKGBUILD, the full sync_package path (selection, validation, backstop,
|
||||
# rewrite, read-back verification), with only the two network fetches
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
# { "source": "local", "channels": ["edge", "rc", "stable"] }
|
||||
# { "source": "local", "min_release_age": "24h" }
|
||||
# { "source": "local", "upstream": { "github": "owner/repo", "checksums": "SHASUMS256.txt", "assets": { "x86_64": "name-{tag}-x64.tar.xz" } } }
|
||||
# { "source": "local", "upstream": { "git_tags": "https://example/repo.git", "tag_pattern": "v{pkgver}", "sources": { "any": ["https://example/archive/{tag}.tar.gz"] } } }
|
||||
# { "source": "local", "upstream": { "npm": "@scope/package", "sources": { "any": ["{npm_tarball}"] } } }
|
||||
#
|
||||
# bin/sync-aur also writes upstream_commit for AUR-backed packages, and
|
||||
# bin/sync-rebuilds writes rebuilt_against for packages declaring rebuild_on.
|
||||
@@ -446,17 +448,33 @@ validate_package_metadata() {
|
||||
# `has` rather than `// {}`: jq's // treats false as absent, which would
|
||||
# let "upstream": false slip through as an empty declaration.
|
||||
if ! jq -e '
|
||||
def valid_sources:
|
||||
type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z"))
|
||||
and (.value | type == "array" and length > 0 and all(type == "string" and length > 0))
|
||||
));
|
||||
if has("upstream") | not then true
|
||||
elif (.upstream | type) != "object" then false
|
||||
else .upstream |
|
||||
((.github // "") | type == "string" and test("\\A[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+\\z"))
|
||||
and ((.checksums // "") | type == "string" and length > 0)
|
||||
and ((.assets // {}) | type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z")) and (.value | type == "string" and length > 0)
|
||||
)))
|
||||
([has("github"), has("git_tags"), has("npm")] | map(select(.)) | length) == 1
|
||||
and if has("github") then
|
||||
(.github | type == "string" and test("\\A[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+\\z"))
|
||||
and (.checksums | type == "string" and length > 0)
|
||||
and (.assets | type == "object" and length > 0 and (to_entries | all(
|
||||
(.key | test("\\A[a-z0-9_]+\\z")) and (.value | type == "string" and length > 0)
|
||||
)))
|
||||
elif has("git_tags") then
|
||||
(.git_tags | type == "string" and test("\\Ahttps://[^[:space:]]+\\.git\\z"))
|
||||
and (.tag_pattern | type == "string" and (split("{pkgver}") | length) == 2)
|
||||
and (.sources | valid_sources)
|
||||
else
|
||||
(.npm | type == "string" and test("\\A(@[a-z0-9_.-]+/)?[a-z0-9_.-]+\\z"))
|
||||
and ((.dist_tag // "latest") | type == "string" and test("\\A[a-z0-9_.-]+\\z"))
|
||||
and (.sources | valid_sources)
|
||||
end
|
||||
end
|
||||
' "$metadata" >/dev/null; then
|
||||
echo "invalid upstream for $(basename "$pkgdir"): needs github owner/repo, checksums asset name, and an assets arch->name map"
|
||||
echo "invalid upstream for $(basename "$pkgdir"): configure exactly one valid github, git_tags, or npm provider"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
+159
-7
@@ -1,4 +1,4 @@
|
||||
# GitHub-releases upstream provider for bin/sync-upstream.
|
||||
# Declarative upstream providers for bin/sync-upstream.
|
||||
#
|
||||
# A package whose upstream ships tagged GitHub releases with a checksum
|
||||
# manifest asset needs no upstream.sh hook: the whole feed is data, declared
|
||||
@@ -17,13 +17,20 @@
|
||||
# "v", which is stripped for pkgver. Drafts and prereleases are ignored. The
|
||||
# provider emits the same JSON contract as an upstream.sh hook, so
|
||||
# bin/sync-upstream's validation and min_release_age backstop apply
|
||||
# unchanged; a feed that fits no convention keeps a bespoke upstream.sh.
|
||||
# unchanged. Git-tag and npm providers below cover projects without a release
|
||||
# checksum manifest; a feed that fits no convention keeps a bespoke hook.
|
||||
|
||||
package_upstream_github_repo() {
|
||||
local pkgdir="$1"
|
||||
# `objects` drops a non-object upstream value (validation rejects those
|
||||
# separately) instead of erroring the jq pipeline.
|
||||
package_metadata_value "$pkgdir" '(.upstream? | objects | .github)' ""
|
||||
# Return the single declarative provider selected by a package. An empty
|
||||
# result means either no provider or an invalid/ambiguous declaration; the
|
||||
# caller distinguishes those through package_has_upstream_provider().
|
||||
package_upstream_provider() {
|
||||
local pkgdir="$1" metadata
|
||||
metadata=$(metadata_file_for_dir "$pkgdir")
|
||||
jq -r '
|
||||
(.upstream? | objects) as $u
|
||||
| [$u | keys[] | select(. == "github" or . == "git_tags" or . == "npm")]
|
||||
| if length == 1 then .[0] else "" end
|
||||
' "$metadata"
|
||||
}
|
||||
|
||||
# Fetches sit behind functions so the self-test can replace them with fixture
|
||||
@@ -43,6 +50,151 @@ github_fetch_checksums() {
|
||||
curl -fsSL "https://github.com/$repo/releases/download/$tag/$asset"
|
||||
}
|
||||
|
||||
git_tags_fetch_refs() {
|
||||
local repo="$1"
|
||||
git ls-remote --tags "$repo"
|
||||
}
|
||||
|
||||
npm_fetch_metadata() {
|
||||
local package="$1" encoded
|
||||
encoded=$(jq -rn --arg package "$package" '$package | @uri')
|
||||
curl -fsSL "https://registry.npmjs.org/$encoded"
|
||||
}
|
||||
|
||||
upstream_fetch_source() {
|
||||
local url="$1" output="$2"
|
||||
curl --proto '=https' --proto-redir '=https' -fsSL -o "$output" "$url"
|
||||
}
|
||||
|
||||
# Hash every URL template in upstream.sources and emit hook-contract JSON.
|
||||
# Templates may use {pkgver}, {tag}, and (for npm) {npm_tarball}. Downloads
|
||||
# happen only after discovery reports a version newer than the PKGBUILD.
|
||||
upstream_hash_sources() {
|
||||
local package_dir="$1" pkgver="$2" tag="${3:-}" npm_tarball="${4:-}"
|
||||
local metadata sources work result arch template url file sum sums index=0
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
sources=$(jq -c '.upstream.sources' "$metadata")
|
||||
work=$(mktemp -d)
|
||||
result=$(jq -n --arg pkgver "$pkgver" '{pkgver: $pkgver, sha256sums: {}}')
|
||||
|
||||
while IFS= read -r arch; do
|
||||
sums='[]'
|
||||
while IFS= read -r template; do
|
||||
if [[ "$template" == file:* ]]; then
|
||||
file=${template#file:}
|
||||
if [[ ! "$file" =~ ^[A-Za-z0-9._+-]+$ || ! -f "$package_dir/$file" ]]; then
|
||||
echo "upstream source names an unsafe or missing local file: '$file'" >&2
|
||||
rm -rf "$work"
|
||||
return 1
|
||||
fi
|
||||
sum=$(sha256sum "$package_dir/$file" | cut -d' ' -f1)
|
||||
sums=$(jq -c --arg sum "$sum" '. + [$sum]' <<<"$sums")
|
||||
continue
|
||||
fi
|
||||
url=${template//\{pkgver\}/$pkgver}
|
||||
url=${url//\{tag\}/$tag}
|
||||
url=${url//\{npm_tarball\}/$npm_tarball}
|
||||
if [[ ! "$url" =~ ^https://[^[:space:]{}]+$ ]]; then
|
||||
echo "upstream source template produced an unsafe URL: '$url'" >&2
|
||||
rm -rf "$work"
|
||||
return 1
|
||||
fi
|
||||
file="$work/source-$((index += 1))"
|
||||
if ! upstream_fetch_source "$url" "$file"; then
|
||||
echo "could not fetch upstream source: $url" >&2
|
||||
rm -rf "$work"
|
||||
return 1
|
||||
fi
|
||||
sum=$(sha256sum "$file" | cut -d' ' -f1)
|
||||
sums=$(jq -c --arg sum "$sum" '. + [$sum]' <<<"$sums")
|
||||
done < <(jq -r --arg arch "$arch" '.[$arch][]' <<<"$sources")
|
||||
result=$(jq -c --arg arch "$arch" --argjson sums "$sums" '.sha256sums[$arch] = $sums' <<<"$result")
|
||||
done < <(jq -r 'keys[]' <<<"$sources")
|
||||
|
||||
rm -rf "$work"
|
||||
printf '%s\n' "$result"
|
||||
}
|
||||
|
||||
git_tags_upstream_release() {
|
||||
local package_dir="$1" metadata repo pattern prefix suffix refs
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
repo=$(jq -r '.upstream.git_tags // ""' "$metadata")
|
||||
pattern=$(jq -r '.upstream.tag_pattern // ""' "$metadata")
|
||||
prefix=${pattern%%\{pkgver\}*}
|
||||
suffix=${pattern#*\{pkgver\}}
|
||||
|
||||
if [[ ! "$repo" =~ ^https://[^[:space:]]+\.git$ || "$pattern" != *'{pkgver}'* || "$suffix" == *'{pkgver}'* ]]; then
|
||||
echo "invalid git_tags provider configuration" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! refs=$(git_tags_fetch_refs "$repo"); then
|
||||
echo "could not fetch tags from $repo" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local best_pkgver="" best_tag="" tag candidate
|
||||
declare -A version_tags=()
|
||||
while read -r tag; do
|
||||
tag=${tag%\^\{\}}
|
||||
[[ "$tag" == "$prefix"*"$suffix" ]] || continue
|
||||
candidate=${tag#"$prefix"}
|
||||
[[ -z "$suffix" ]] || candidate=${candidate%"$suffix"}
|
||||
[[ "$candidate" =~ ^[A-Za-z0-9][A-Za-z0-9._+]*$ ]] || continue
|
||||
if [[ -n "${version_tags[$candidate]:-}" && "${version_tags[$candidate]}" != "$tag" ]]; then
|
||||
echo "multiple tags map to pkgver $candidate: ${version_tags[$candidate]} and $tag" >&2
|
||||
return 1
|
||||
fi
|
||||
version_tags[$candidate]="$tag"
|
||||
if [[ -z "$best_pkgver" || $(vercmp "$candidate" "$best_pkgver") -gt 0 ]]; then
|
||||
best_pkgver="$candidate"
|
||||
best_tag="$tag"
|
||||
fi
|
||||
done < <(sed -n 's#^.*refs/tags/##p' <<<"$refs")
|
||||
|
||||
[[ -n "$best_pkgver" ]] || { echo "no usable tags found at $repo" >&2; return 1; }
|
||||
local current_pkgver
|
||||
current_pkgver=$(grep -m1 '^pkgver=' "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best_pkgver" "$current_pkgver") -le 0 ]]; then
|
||||
echo '{}'
|
||||
return 0
|
||||
fi
|
||||
upstream_hash_sources "$package_dir" "$best_pkgver" "$best_tag"
|
||||
}
|
||||
|
||||
npm_upstream_release() {
|
||||
local package_dir="$1" metadata package dist_tag npm_metadata pkgver tarball published_at release
|
||||
metadata=$(metadata_file_for_dir "$package_dir")
|
||||
package=$(jq -r '.upstream.npm // ""' "$metadata")
|
||||
dist_tag=$(jq -r '.upstream.dist_tag // "latest"' "$metadata")
|
||||
if [[ ! "$package" =~ ^(@[a-z0-9_.-]+/)?[a-z0-9_.-]+$ || ! "$dist_tag" =~ ^[a-z0-9_.-]+$ ]]; then
|
||||
echo "invalid npm provider configuration" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! npm_metadata=$(npm_fetch_metadata "$package"); then
|
||||
echo "could not fetch npm metadata for $package" >&2
|
||||
return 1
|
||||
fi
|
||||
pkgver=$(jq -r --arg tag "$dist_tag" '."dist-tags"[$tag] // ""' <<<"$npm_metadata")
|
||||
tarball=$(jq -r --arg version "$pkgver" '.versions[$version].dist.tarball // ""' <<<"$npm_metadata")
|
||||
published_at=$(jq -r --arg version "$pkgver" '.time[$version] // ""' <<<"$npm_metadata")
|
||||
if [[ ! "$pkgver" =~ ^[A-Za-z0-9][A-Za-z0-9._+]*$ || ! "$tarball" =~ ^https://registry\.npmjs\.org/ ]]; then
|
||||
echo "npm returned an unusable $package release" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local current_pkgver
|
||||
current_pkgver=$(grep -m1 '^pkgver=' "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$pkgver" "$current_pkgver") -le 0 ]]; then
|
||||
echo '{}'
|
||||
return 0
|
||||
fi
|
||||
release=$(upstream_hash_sources "$package_dir" "$pkgver" "$pkgver" "$tarball") || return 1
|
||||
if [[ -n "$published_at" ]]; then
|
||||
release=$(jq -c --arg published_at "$published_at" '.published_at = $published_at' <<<"$release")
|
||||
fi
|
||||
printf '%s\n' "$release"
|
||||
}
|
||||
|
||||
# Emits the newest qualifying release as hook-contract JSON. min_release_age
|
||||
# is honored during selection (newest release older than the window wins,
|
||||
# even when a younger one exists) and BYPASS_MIN_RELEASE_AGE=1 lifts it.
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast"
|
||||
"release_ring": "fast",
|
||||
"upstream": {
|
||||
"npm": "@github/copilot",
|
||||
"sources": {
|
||||
"any": [
|
||||
"{npm_tarball}",
|
||||
"https://raw.githubusercontent.com/github/copilot-cli/v{pkgver}/changelog.md"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
# GitHub Copilot CLI is published to npm. Track npm's stable `latest` tag,
|
||||
# then hash both inputs the PKGBUILD downloads. AUR is deliberately not part
|
||||
# of this update path: Omarchy owns the multi-architecture recipe.
|
||||
set -euo pipefail
|
||||
|
||||
REGISTRY_URL="https://registry.npmjs.org/@github%2Fcopilot"
|
||||
CHANGELOG_BASE="https://raw.githubusercontent.com/github/copilot-cli"
|
||||
|
||||
metadata=$(curl -fsSL "$REGISTRY_URL")
|
||||
version=$(jq -r '."dist-tags".latest // ""' <<<"$metadata")
|
||||
tarball=$(jq -r --arg version "$version" '.versions[$version].dist.tarball // ""' <<<"$metadata")
|
||||
|
||||
if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ || ! $tarball =~ ^https://registry\.npmjs\.org/ ]]; then
|
||||
echo "npm returned an unusable Copilot release: version='$version' tarball='$tarball'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$version" "$current") -le 0 ]]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
curl -fsSL -o "$work/copilot.tgz" "$tarball"
|
||||
curl -fsSL -o "$work/changelog.md" "$CHANGELOG_BASE/v${version}/changelog.md"
|
||||
|
||||
jq -n \
|
||||
--arg pkgver "$version" \
|
||||
--arg package_sum "$(sha256sum "$work/copilot.tgz" | cut -d' ' -f1)" \
|
||||
--arg changelog_sum "$(sha256sum "$work/changelog.md" | cut -d' ' -f1)" \
|
||||
'{pkgver: $pkgver, sha256sums: {any: [$package_sum, $changelog_sum]}}'
|
||||
@@ -1,3 +1,10 @@
|
||||
{
|
||||
"source": "local"
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/FrameworkComputer/qmk_hid.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://github.com/FrameworkComputer/qmk_hid/archive/refs/tags/{tag}.tar.gz"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
# qmk_hid marks every GitHub Release as a prerelease, including the versions
|
||||
# it considers current. Track its semver tags instead and hash the tagged
|
||||
# source archive only when a newer version appears.
|
||||
set -euo pipefail
|
||||
|
||||
REPO="https://github.com/FrameworkComputer/qmk_hid.git"
|
||||
best=""
|
||||
while read -r tag; do
|
||||
tag=${tag%\^\{\}}
|
||||
[[ $tag =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]] || continue
|
||||
version=${BASH_REMATCH[1]}
|
||||
if [[ -z $best || $(vercmp "$version" "$best") -gt 0 ]]; then
|
||||
best=$version
|
||||
fi
|
||||
done < <(git ls-remote --tags "$REPO" | sed 's#^.*refs/tags/##')
|
||||
|
||||
[[ -n $best ]] || { echo "No usable qmk_hid version tag found" >&2; exit 1; }
|
||||
current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best" "$current") -le 0 ]]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sum=$(curl -fsSL "https://github.com/FrameworkComputer/qmk_hid/archive/refs/tags/v${best}.tar.gz" | sha256sum | cut -d' ' -f1)
|
||||
jq -n --arg pkgver "$best" --arg sha256 "$sum" \
|
||||
'{pkgver: $pkgver, sha256sums: {any: [$sha256]}}'
|
||||
@@ -1,4 +1,11 @@
|
||||
{
|
||||
"source": "local",
|
||||
"release_ring": "fast"
|
||||
"release_ring": "fast",
|
||||
"upstream": {
|
||||
"github": "symfony-cli/symfony-cli",
|
||||
"checksums": "checksums.txt",
|
||||
"assets": {
|
||||
"any": "symfony-cli-{pkgver}.tar.gz"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Symfony publishes a checksum manifest with every stable GitHub release.
|
||||
# The `latest` URL is its vendor-maintained stable feed, so no GitHub API or
|
||||
# AUR state is involved in selecting and verifying the source tarball.
|
||||
set -euo pipefail
|
||||
|
||||
CHECKSUMS_URL="https://github.com/symfony-cli/symfony-cli/releases/latest/download/checksums.txt"
|
||||
checksums=$(curl -fsSL "$CHECKSUMS_URL")
|
||||
|
||||
best=""
|
||||
best_sum=""
|
||||
while read -r sum filename; do
|
||||
[[ $filename =~ ^symfony-cli-([0-9]+\.[0-9]+\.[0-9]+)\.tar\.gz$ ]] || continue
|
||||
version=${BASH_REMATCH[1]}
|
||||
[[ $sum =~ ^[0-9a-f]{64}$ ]] || continue
|
||||
if [[ -z $best || $(vercmp "$version" "$best") -gt 0 ]]; then
|
||||
best=$version
|
||||
best_sum=$sum
|
||||
fi
|
||||
done <<<"$checksums"
|
||||
|
||||
[[ -n $best ]] || { echo "Symfony's latest checksum manifest names no source tarball" >&2; exit 1; }
|
||||
current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best" "$current") -le 0 ]]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
jq -n --arg pkgver "$best" --arg sha256 "$best_sum" \
|
||||
'{pkgver: $pkgver, sha256sums: {any: [$sha256]}}'
|
||||
@@ -1,3 +1,10 @@
|
||||
{
|
||||
"source": "local"
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/jondkinney/tensaku.git",
|
||||
"tag_pattern": "v{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://github.com/jondkinney/tensaku/archive/refs/tags/{tag}.tar.gz"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Tensaku publishes semver tags but no source checksum manifest. Select the
|
||||
# newest tag using pacman's ordering and hash its source archive.
|
||||
set -euo pipefail
|
||||
|
||||
REPO="https://github.com/jondkinney/tensaku.git"
|
||||
version=""
|
||||
while read -r tag; do
|
||||
tag=${tag%\^\{\}}
|
||||
[[ $tag =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]] || continue
|
||||
candidate=${BASH_REMATCH[1]}
|
||||
if [[ -z $version || $(vercmp "$candidate" "$version") -gt 0 ]]; then
|
||||
version=$candidate
|
||||
fi
|
||||
done < <(git ls-remote --tags "$REPO" | sed 's#^.*refs/tags/##')
|
||||
|
||||
[[ -n $version ]] || { echo "No usable Tensaku version tag found" >&2; exit 1; }
|
||||
current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$version" "$current") -le 0 ]]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sum=$(curl -fsSL "https://github.com/jondkinney/tensaku/archive/refs/tags/v${version}.tar.gz" | sha256sum | cut -d' ' -f1)
|
||||
jq -n --arg pkgver "$version" --arg sha256 "$sum" \
|
||||
'{pkgver: $pkgver, sha256sums: {any: [$sha256]}}'
|
||||
@@ -1,3 +1,10 @@
|
||||
{
|
||||
"source": "local"
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://github.com/cdown/tzupdate.git",
|
||||
"tag_pattern": "{pkgver}",
|
||||
"sources": {
|
||||
"any": ["https://github.com/cdown/tzupdate/archive/refs/tags/{tag}.tar.gz"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
# tzupdate publishes version tags but no GitHub Releases. Track its semver
|
||||
# tags and hash the tagged source archive when a new version appears.
|
||||
set -euo pipefail
|
||||
|
||||
REPO="https://github.com/cdown/tzupdate.git"
|
||||
best=""
|
||||
while read -r tag; do
|
||||
tag=${tag%\^\{\}}
|
||||
[[ $tag =~ ^v?([0-9]+\.[0-9]+\.[0-9]+)$ ]] || continue
|
||||
version=${BASH_REMATCH[1]}
|
||||
if [[ -z $best || $(vercmp "$version" "$best") -gt 0 ]]; then
|
||||
best=$version
|
||||
fi
|
||||
done < <(git ls-remote --tags "$REPO" | sed 's#^.*refs/tags/##')
|
||||
|
||||
[[ -n $best ]] || { echo "No usable tzupdate version tag found" >&2; exit 1; }
|
||||
current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best" "$current") -le 0 ]]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sum=$(curl -fsSL "https://github.com/cdown/tzupdate/archive/refs/tags/${best}.tar.gz" | sha256sum | cut -d' ' -f1)
|
||||
jq -n --arg pkgver "$best" --arg sha256 "$sum" \
|
||||
'{pkgver: $pkgver, sha256sums: {any: [$sha256]}}'
|
||||
@@ -1,3 +1,14 @@
|
||||
{
|
||||
"source": "local"
|
||||
"source": "local",
|
||||
"upstream": {
|
||||
"git_tags": "https://gitlab.com/vicamo/v4l2-relayd.git",
|
||||
"tag_pattern": "upstream/{pkgver}",
|
||||
"sources": {
|
||||
"any": [
|
||||
"https://gitlab.com/vicamo/v4l2-relayd/-/archive/upstream/{pkgver}/v4l2-relayd-upstream-{pkgver}.tar.gz",
|
||||
"file:0001-reset-output-on-idle.patch",
|
||||
"file:0002-escape-optional-splashsrc-expansion.patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
# v4l2-relayd uses GitLab tags named upstream/<version>. Keep Omarchy's local
|
||||
# patches and follow that authoritative tag stream directly.
|
||||
set -euo pipefail
|
||||
|
||||
REPO="https://gitlab.com/vicamo/v4l2-relayd.git"
|
||||
best=""
|
||||
while read -r tag; do
|
||||
tag=${tag%\^\{\}}
|
||||
[[ $tag =~ ^upstream/([0-9]+\.[0-9]+\.[0-9]+)$ ]] || continue
|
||||
version=${BASH_REMATCH[1]}
|
||||
if [[ -z $best || $(vercmp "$version" "$best") -gt 0 ]]; then
|
||||
best=$version
|
||||
fi
|
||||
done < <(git ls-remote --tags "$REPO" | sed 's#^.*refs/tags/##')
|
||||
|
||||
[[ -n $best ]] || { echo "No usable v4l2-relayd upstream tag found" >&2; exit 1; }
|
||||
current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'")
|
||||
if [[ $(vercmp "$best" "$current") -le 0 ]]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sum=$(curl -fsSL "https://gitlab.com/vicamo/v4l2-relayd/-/archive/upstream/${best}/v4l2-relayd-upstream-${best}.tar.gz" | sha256sum | cut -d' ' -f1)
|
||||
jq -n --arg pkgver "$best" --arg sha256 "$sum" \
|
||||
'{pkgver: $pkgver, sha256sums: {any: [$sha256, "SKIP", "SKIP"]}}'
|
||||
@@ -19,8 +19,8 @@ source=("https://gitlab.com/vicamo/v4l2-relayd/-/archive/upstream/${pkgver}/v4l2
|
||||
"0001-reset-output-on-idle.patch"
|
||||
"0002-escape-optional-splashsrc-expansion.patch")
|
||||
sha256sums=('0c063edf18dcc6edcdef46e695128cfc2b2d60964ea8538c7e79a2454310c53d'
|
||||
'SKIP'
|
||||
'SKIP')
|
||||
'07722a8708ced48d2db9575f3eae5b1266868d259d260635e06e9a10baddec78'
|
||||
'3cb89056af276eed7a45dfc96435e8e48558e4e11c96560360d46d631b1c0b6c')
|
||||
|
||||
prepare() {
|
||||
cd "$srcdir/${pkgname}-upstream-${pkgver}"
|
||||
|
||||
Reference in new issue
Block a user