also looking at this
fix(ci): bot commits land through a checked pull request, not a bypass
#274
10 files
+621
-23
| @@ -0,0 +1,154 @@ | ||
| 1 | name: Merge via PR | |
| 2 | description: >- | |
| 3 | Land an already-committed change on the default branch through a pull request | |
| 4 | that actually runs the required checks. | |
| 5 | ||
| 6 | inputs: | |
| 7 | token: | |
| 8 | description: "GitHub token with contents, pull-requests and actions write." | |
| 9 | required: true | |
| 10 | branch-prefix: | |
| 11 | description: "Branch namespace for the pull request's head." | |
| 12 | required: false | |
| 13 | default: 'chore/automated' | |
| 14 | title: | |
| 15 | description: "Pull request title. Defaults to the commit subject." | |
| 16 | required: false | |
| 17 | default: '' | |
| 18 | body: | |
| 19 | description: "Pull request body." | |
| 20 | required: false | |
| 21 | default: '' | |
| 22 | checks: | |
| 23 | description: "Comma-separated required check names to wait for." | |
| 24 | required: false | |
| 25 | default: 'lint,typecheck,test,zig-tests' | |
| 26 | workflow: | |
| 27 | description: "Workflow dispatched to produce those checks." | |
| 28 | required: false | |
| 29 | default: 'ci.yml' | |
| 30 | timeout-minutes: | |
| 31 | description: "How long to wait for the checks before giving up." | |
| 32 | required: false | |
| 33 | default: '40' | |
| 34 | ||
| 35 | outputs: | |
| 36 | merged: | |
| 37 | description: "true when the pull request was merged." | |
| 38 | value: ${{ steps.land.outputs.merged }} | |
| 39 | pr-number: | |
| 40 | description: "Number of the pull request that was opened." | |
| 41 | value: ${{ steps.land.outputs.pr-number }} | |
| 42 | pr-url: | |
| 43 | description: "URL of the pull request that was opened." | |
| 44 | value: ${{ steps.land.outputs.pr-url }} | |
| 45 | ||
| 46 | runs: | |
| 47 | using: composite | |
| 48 | steps: | |
| 49 | # A bot cannot push to the default branch: the branch ruleset requires the | |
| 50 | # CI contexts, and `github-actions[bot]` holds no repository role, so its | |
| 51 | # push is refused with GH013. Going through a pull request is the honest | |
| 52 | # answer — the generated catalog gets checked like anything else — but it | |
| 53 | # needs one piece of care. GitHub suppresses events caused by GITHUB_TOKEN, | |
| 54 | # which covers a pull request opened with it just as it covers a push, so | |
| 55 | # the `pull_request` trigger never fires and nothing would ever report | |
| 56 | # against the required contexts. Dispatching CI at the head branch does | |
| 57 | # report: a check run is attached to a commit, and that commit is the one | |
| 58 | # the pull request is gated on. | |
| 59 | - name: Land the commit through a pull request | |
| 60 | id: land | |
| 61 | shell: bash | |
| 62 | env: | |
| 63 | GH_TOKEN: ${{ inputs.token }} | |
| 64 | REPO: ${{ github.repository }} | |
| 65 | BASE: ${{ github.event.repository.default_branch || 'main' }} | |
| 66 | PREFIX: ${{ inputs.branch-prefix }} | |
| 67 | TITLE_IN: ${{ inputs.title }} | |
| 68 | BODY_IN: ${{ inputs.body }} | |
| 69 | CHECKS: ${{ inputs.checks }} | |
| 70 | WORKFLOW: ${{ inputs.workflow }} | |
| 71 | TIMEOUT_MIN: ${{ inputs.timeout-minutes }} | |
| 72 | RUN_ID: ${{ github.run_id }} | |
| 73 | RUN_ATTEMPT: ${{ github.run_attempt }} | |
| 74 | run: | | |
| 75 | set -uo pipefail | |
| 76 | ||
| 77 | BRANCH="${PREFIX}/${RUN_ID}-${RUN_ATTEMPT}" | |
| 78 | SHA="$(git rev-parse HEAD)" | |
| 79 | TITLE="${TITLE_IN:-$(git log -1 --pretty=%s)}" | |
| 80 | echo "merged=false" >> "$GITHUB_OUTPUT" | |
| 81 | ||
| 82 | # Each run's commit regenerates the whole of what the last one wrote, so | |
| 83 | # an older open pull request from this same prefix is superseded rather | |
| 84 | # than merely stale. Closing it keeps a red or slow run from piling up a | |
| 85 | # queue of pull requests that all say the same thing. | |
| 86 | gh pr list --repo "$REPO" --state open --json number,headRefName \ | |
| 87 | --jq ".[] | select(.headRefName | startswith(\"${PREFIX}/\")) | .number" 2>/dev/null \ | |
| 88 | | while read -r stale; do | |
| 89 | [ -n "$stale" ] || continue | |
| 90 | echo "Superseding #${stale}" | |
| 91 | gh pr close "$stale" --repo "$REPO" --delete-branch \ | |
| 92 | --comment "Superseded by a newer automated run." || true | |
| 93 | done | |
| 94 | ||
| 95 | if ! git push origin "HEAD:refs/heads/${BRANCH}"; then | |
| 96 | echo "::error::could not push ${BRANCH}" | |
| 97 | exit 1 | |
| 98 | fi | |
| 99 | ||
| 100 | PR_URL="$(gh pr create --repo "$REPO" --base "$BASE" --head "$BRANCH" \ | |
| 101 | --title "$TITLE" --body "${BODY_IN:-Opened automatically so the required checks run on generated output.}")" | |
| 102 | if [ -z "$PR_URL" ]; then | |
| 103 | echo "::error::could not open a pull request for ${BRANCH}" | |
| 104 | git push origin --delete "$BRANCH" || true | |
| 105 | exit 1 | |
| 106 | fi | |
| 107 | PR_NUMBER="${PR_URL##*/}" | |
| 108 | echo "pr-number=${PR_NUMBER}" >> "$GITHUB_OUTPUT" | |
| 109 | echo "pr-url=${PR_URL}" >> "$GITHUB_OUTPUT" | |
| 110 | echo "Opened ${PR_URL}" | |
| 111 | ||
| 112 | if ! gh workflow run "$WORKFLOW" --repo "$REPO" --ref "$BRANCH"; then | |
| 113 | echo "::error::could not dispatch ${WORKFLOW} at ${BRANCH}; nothing would report on ${SHA}" | |
| 114 | exit 1 | |
| 115 | fi | |
| 116 | ||
| 117 | IFS=',' read -ra WANTED <<< "$CHECKS" | |
| 118 | DEADLINE=$(( $(date +%s) + TIMEOUT_MIN * 60 )) | |
| 119 | while :; do | |
| 120 | if [ "$(date +%s)" -ge "$DEADLINE" ]; then | |
| 121 | echo "::error::${CHECKS} did not all report on ${SHA} within ${TIMEOUT_MIN}m; ${PR_URL} is left open" | |
| 122 | exit 1 | |
| 123 | fi | |
| 124 | ||
| 125 | RUNS="$(gh api "repos/${REPO}/commits/${SHA}/check-runs?per_page=100" \ | |
| 126 | --jq '.check_runs[] | "\(.name)\t\(.status)\t\(.conclusion // "")"' 2>/dev/null)" | |
| 127 | ||
| 128 | PASSED=0 | |
| 129 | FAILED='' | |
| 130 | for want in "${WANTED[@]}"; do | |
| 131 | line="$(printf '%s\n' "$RUNS" | awk -F'\t' -v n="$want" '$1 == n { print; exit }')" | |
| 132 | [ -n "$line" ] || continue | |
| 133 | status="$(printf '%s' "$line" | cut -f2)" | |
| 134 | [ "$status" = "completed" ] || continue | |
| 135 | case "$(printf '%s' "$line" | cut -f3)" in | |
| 136 | success|skipped|neutral) PASSED=$((PASSED + 1)) ;; | |
| 137 | *) FAILED="${FAILED:+$FAILED, }${want}" ;; | |
| 138 | esac | |
| 139 | done | |
| 140 | ||
| 141 | if [ -n "$FAILED" ]; then | |
| 142 | echo "::error::required checks failed on generated output: ${FAILED}. ${PR_URL} is left open to show why." | |
| 143 | exit 1 | |
| 144 | fi | |
| 145 | [ "$PASSED" -eq "${#WANTED[@]}" ] && break | |
| 146 | sleep 20 | |
| 147 | done | |
| 148 | ||
| 149 | if ! gh pr merge "$PR_NUMBER" --repo "$REPO" --squash --delete-branch; then | |
| 150 | echo "::error:__stx_checks="eyJzdGF0ZSI6Im5ldXRyYWwiLCJjb3VudHMiOnsiZmFpbHVyZSI6MCwicGVuZGluZyI6MCwic3VjY2VzcyI6MCwibmV1dHJhbCI6MH0sImVudHJpZXMiOltdLCJyZXF1aXJlZCI6eyJzYXRpc2ZpZWQiOnRydWUsIm1pc3NpbmciOltdLCJmYWlsaW5nIjpbXSwicGVuZGluZyI6W119LCJhbm5vdGF0aW9ucyI6W119" passed but ${PR_URL} would not merge; it is left open" | |
| 151 | exit 1 | |
| 152 | fi | |
| 153 | echo "merged=true" >> "$GITHUB_OUTPUT" | |
| 154 | echo "Merged ${PR_URL}" | |
| @@ -142,6 +142,10 @@ jobs: | ||
| 142 | 142 | # the commit — the gate cannot let a stale manifest through. |
| 143 | 143 | record: |
| 144 | 144 | needs: [publish-ubuntu, publish-macos] |
| 145 | permissions: | |
| 146 | contents: write | |
| 147 | actions: write | |
| 148 | pull-requests: write | |
| 145 | 149 | if: >- |
| 146 | 150 | always() && |
| 147 | 151 | needs.publish-ubuntu.result == 'success' && |
| @@ -160,17 +164,14 @@ jobs: | ||
| 160 | 164 | - name: Record verified registry state |
| 161 | 165 | working-directory: packages/ts-pantry |
| 162 | 166 | run: bun scripts/check-desktop-updates.ts --require-current --commit |
| 163 | - name: Push verified manifest commit | |
| 164 | working-directory: packages/ts-pantry | |
| 165 | run: | | |
| 166 | for attempt in 1 2 3 4 5; do | |
| 167 | if git push; then | |
| 168 | echo "push ok (attempt $attempt)" | |
| 169 | exit 0 | |
| 170 | fi | |
| 171 | echo "push rejected (attempt $attempt); rebasing onto latest main" | |
| 172 | git fetch origin main | |
| 173 | git rebase origin/main | |
| 174 | done | |
| 175 | echo "ERROR: could not push manifest after 5 attempts" >&2 | |
| 176 | exit 1 | |
| 167 | # The rebase-and-retry loop this replaces answered a race with another | |
| 168 | # push. It cannot answer the ruleset: main requires the CI contexts, a | |
| 169 | # bot push holds no repository role to be excused by, and retrying a | |
| 170 | # GH013 five times only rebases five times before failing anyway. | |
| 171 | - name: Land the verified manifest through a pull request | |
| 172 | uses: ./.github/actions/merge-via-pr | |
| 173 | with: | |
| 174 | token: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }} | |
| 175 | branch-prefix: chore/desktop-manifest | |
| 176 | body: | | |
| 177 | Verified desktop manifest state from `check-desktop-updates.yml`. | |
| @@ -53,10 +53,12 @@ jobs: | ||
| 53 | 53 | update-packages: |
| 54 | 54 | name: Update packages and index |
| 55 | 55 | runs-on: ubuntu-latest |
| 56 | timeout-minutes: 30 | |
| 56 | # Covers the sweep plus the wait for CI to report on the pull request. | |
| 57 | timeout-minutes: 80 | |
| 57 | 58 | permissions: |
| 58 | 59 | contents: write |
| 59 | 60 | actions: write |
| 61 | pull-requests: write | |
| 60 | 62 | |
| 61 | 63 | steps: |
| 62 | 64 | - name: Checkout repository |
| @@ -221,7 +223,7 @@ jobs: | ||
| 221 | 223 | fi |
| 222 | 224 | echo "safe_to_commit=true" >> $GITHUB_OUTPUT |
| 223 | 225 | |
| 224 | - name: Commit and push changes | |
| 226 | - name: Commit changes | |
| 225 | 227 | id: commit |
| 226 | 228 | if: steps.git-check.outputs.changes == 'true' && steps.deletion-check.outputs.safe_to_commit == 'true' |
| 227 | 229 | run: | |
| @@ -234,12 +236,32 @@ jobs: | ||
| 234 | 236 | test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" |
| 235 | 237 | git add packages/ts-pantry/src/packages/ packages/ts-pantry/src/generated-package-names.ts packages/zig/src/packages/generated.zig packages/action/dist/index.js packages/action/dist/post.js |
| 236 | 238 | git commit -F /tmp/pantry-update-commit-message.txt |
| 237 | git push origin HEAD:refs/heads/main | |
| 238 | 239 | |
| 239 | echo "committed=true" >> $GITHUB_OUTPUT | |
| 240 | # This commit used to go straight to main. It cannot any more: main | |
| 241 | # requires the CI contexts, and a bot push carries no repository role to | |
| 242 | # be excused by, so the push comes back GH013. The alternative to a pull | |
| 243 | # request was excusing the Actions app from the checks, which would have | |
| 244 | # exempted every workflow that ever pushes rather than this one, and | |
| 245 | # would have kept the generated catalog the only thing on main nobody | |
| 246 | # checks. So it is checked now, like everything else. | |
| 247 | - name: Land the update through a pull request | |
| 248 | id: land | |
| 249 | if: steps.commit.conclusion == 'success' | |
| 250 | uses: ./.github/actions/merge-via-pr | |
| 251 | with: | |
| 252 | token: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }} | |
| 253 | branch-prefix: chore/package-updates | |
| 254 | body: | | |
| 255 | Automated catalog refresh from `update-packages.yml`. | |
| 256 | ||
| 257 | Opened rather than pushed because `main` requires the CI contexts | |
| 258 | and a bot push holds no role to be excused by. CI is dispatched at | |
| 259 | this branch explicitly: a pull request opened with `GITHUB_TOKEN` | |
| 260 | does not fire `pull_request`, so without the dispatch nothing would | |
| 261 | ever report here. | |
| 240 | 262 | |
| 241 | 263 | - name: Publish updated packages to the registry |
| 242 | if: steps.commit.outputs.committed == 'true' | |
| 264 | if: steps.land.outputs.merged == 'true' | |
| 243 | 265 | env: |
| 244 | 266 | GH_TOKEN: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }} |
| 245 | 267 | run: | |
| @@ -54,7 +54,11 @@ export const craftPackage = { | ||
| 54 | 54 | 'craft', |
| 55 | 55 | ] as const, |
| 56 | 56 | companions: [] as const, |
| 57 | dependencies: [] as const, | |
| 57 | dependencies: [ | |
| 58 | 'linux:gtk.org/gtk3^3.24', | |
| 59 | 'linux:gnome.org/glib^2', | |
| 60 | 'linux:webkitgtk.org^2.54', | |
| 61 | ] as const, | |
| 58 | 62 | /** |
| 59 | 63 | * Build dependencies for this package. |
| 60 | 64 | * These are only required when building the package from source. |
| @@ -1688,6 +1688,7 @@ import { waterlanhomexs4allnldos2unixPackage } from './waterlan.home.xs4all.nl/d | ||
| 1688 | 1688 | import { wavpackcomPackage } from './wavpackcom' |
| 1689 | 1689 | import { waylandfreedesktoporgprotocolsPackage } from './wayland.freedesktop.org/protocols' |
| 1690 | 1690 | import { waylandfreedesktoporgPackage } from './waylandfreedesktoporg' |
| 1691 | import { webkitgtkorgPackage } from './webkitgtkorg' | |
| 1691 | 1692 | import { webmprojectorglibvpxPackage } from './webmproject.org/libvpx' |
| 1692 | 1693 | import { werfioPackage } from './werfio' |
| 1693 | 1694 | import { wezfurlongorgweztermPackage } from './wezfurlong.org/wezterm' |
| @@ -4564,6 +4565,7 @@ export interface Pantry { | ||
| 4564 | 4565 | protocols: typeof waylandfreedesktoporgprotocolsPackage |
| 4565 | 4566 | waylandfreedesktoporgprotocols: typeof waylandfreedesktoporgprotocolsPackage |
| 4566 | 4567 | waylandfreedesktoporg: typeof waylandfreedesktoporgPackage |
| 4568 | webkitgtkorg: typeof webkitgtkorgPackage | |
| 4567 | 4569 | |
| 4568 | 4570 | webmprojectorglibvpx: typeof webmprojectorglibvpxPackage |
| 4569 | 4571 | werfio: typeof werfioPackage |
| @@ -9272,6 +9274,7 @@ export const pantry: Pantry = { | ||
| 9272 | 9274 | protocols: waylandfreedesktoporgprotocolsPackage, |
| 9273 | 9275 | waylandfreedesktoporgprotocols: waylandfreedesktoporgprotocolsPackage, |
| 9274 | 9276 | waylandfreedesktoporg: waylandfreedesktoporgPackage, |
| 9277 | webkitgtkorg: webkitgtkorgPackage, | |
| 9275 | 9278 | |
| 9276 | 9279 | webmprojectorglibvpx: webmprojectorglibvpxPackage, |
| 9277 | 9280 | werfio: werfioPackage, |
| @@ -0,0 +1,110 @@ | ||
| 1 | /** | |
| 2 | * **webkitgtk** - WebKit rendering engine for GTK, providing the webkit2gtk-4.1 API | |
| 3 | * | |
| 4 | * @domain `webkitgtk.org` | |
| 5 | * @version `2.54.2` (3 versions available) | |
| 6 | * @versions From newest version to oldest. | |
| 7 | * | |
| 8 | * @install `pantry install webkitgtk.org` | |
| 9 | * @homepage https://webkitgtk.org | |
| 10 | * @dependencies `gtk.org/gtk3^3.24`, `gnome.org/glib^2`, `libsoup.org^3`, ... (+26 more) | |
| 11 | * @buildDependencies `cmake.org^3`, `ninja-build.org`, `freedesktop.org/pkg-config`, ... (+4 more) - required only when building from source | |
| 12 | * | |
| 13 | * @example | |
| 14 | * ```typescript | |
| 15 | * import { pantry } from 'ts-pantry' | |
| 16 | * | |
| 17 | * const pkg = pantry.webkitgtkorg | |
| 18 | * console.log(pkg.name) // "webkitgtk" | |
| 19 | * console.log(pkg.description) // "WebKit rendering engine for GTK, providing the ..." | |
| 20 | * console.log(pkg.versions[0]) // "2.54.2" (latest) | |
| 21 | * ``` | |
| 22 | * | |
| 23 | * @see https://ts-pantry.netlify.app/packages/webkitgtk-org.md | |
| 24 | * @see https://ts-pantry.netlify.app/usage | |
| 25 | */ | |
| 26 | export const webkitgtkorgPackage = { | |
| 27 | /** | |
| 28 | * The display name of this package. | |
| 29 | */ | |
| 30 | name: 'webkitgtk' as const, | |
| 31 | /** | |
| 32 | * The canonical domain name for this package. | |
| 33 | */ | |
| 34 | domain: 'webkitgtk.org' as const, | |
| 35 | /** | |
| 36 | * Brief description of what this package does. | |
| 37 | */ | |
| 38 | description: 'WebKit rendering engine for GTK, providing the webkit2gtk-4.1 API' as const, | |
| 39 | packageYmlUrl: '' as const, | |
| 40 | homepageUrl: 'https://webkitgtk.org' as const, | |
| 41 | githubUrl: 'https://github.com/WebKit/WebKit' as const, | |
| 42 | /** | |
| 43 | * Command to install this package using pantry. | |
| 44 | * @example pantry install package-name | |
| 45 | */ | |
| 46 | installCommand: 'pantry install webkitgtk.org' as const, | |
| 47 | pantryInstallCommand: 'pantry install webkitgtk.org' as const, | |
| 48 | programs: [] as const, | |
| 49 | companions: [] as const, | |
| 50 | /** | |
| 51 | * Runtime dependencies for this package. | |
| 52 | * These are required when running the package. | |
| 53 | */ | |
| 54 | dependencies: [ | |
| 55 | 'gtk.org/gtk3^3.24', | |
| 56 | 'gnome.org/glib^2', | |
| 57 | 'libsoup.org^3', | |
| 58 | 'unicode.org', | |
| 59 | 'cairographics.org', | |
| 60 | 'gnome.org/pango', | |
| 61 | 'harfbuzz.org', | |
| 62 | 'freetype.org', | |
| 63 | 'freedesktop.org/fontconfig', | |
| 64 | 'gnome.org/libxml2', | |
| 65 | 'gnome.org/libxslt', | |
| 66 | 'sqlite.org', | |
| 67 | 'libjpeg-turbo.org', | |
| 68 | 'libpng.org', | |
| 69 | 'google.com/webp', | |
| 70 | 'google.com/woff2', | |
| 71 | 'gnu.org/libtasn1', | |
| 72 | 'gnupg.org/libgcrypt', | |
| 73 | 'littlecms.com', | |
| 74 | 'gnome.org/atk', | |
| 75 | 'gnome.org/gdk-pixbuf', | |
| 76 | 'github.com/anholt/libepoxy', | |
| 77 | 'gnome.org/libsecret', | |
| 78 | 'openjpeg.org', | |
| 79 | 'zlib.net', | |
| 80 | 'x.org/x11', | |
| 81 | 'x.org/exts', | |
| 82 | 'wayland.freedesktop.org', | |
| 83 | 'mesa3d.org', | |
| 84 | ] as const, | |
| 85 | /** | |
| 86 | * Available versions from newest to oldest. | |
| 87 | * @see https://ts-pantry.netlify.app/usage for installation instructions | |
| 88 | */ | |
| 89 | versions: [ | |
| 90 | '2.54.2', | |
| 91 | '2.54.1', | |
| 92 | '2.54.0', | |
| 93 | ] as const, | |
| 94 | /** | |
| 95 | * Build dependencies for this package. | |
| 96 | * These are only required when building the package from source. | |
| 97 | */ | |
| 98 | buildDependencies: [ | |
| 99 | 'cmake.org^3', | |
| 100 | 'ninja-build.org', | |
| 101 | 'freedesktop.org/pkg-config', | |
| 102 | 'gnu.org/gettext', | |
| 103 | 'gnu.org/gperf', | |
| 104 | 'ruby-lang.org', | |
| 105 | 'python.org^3', | |
| 106 | ] as const, | |
| 107 | aliases: [] as const, | |
| 108 | } | |
| 109 | ||
| 110 | export type WebkitgtkorgPackage = typeof webkitgtkorgPackage | |
| @@ -7,6 +7,20 @@ export const recipe: Recipe = { | ||
| 7 | 7 | homepage: 'https://craft-native.org', |
| 8 | 8 | github: 'https://github.com/craft-native/craft', |
| 9 | 9 | programs: ['craft'], |
| 10 | ||
| 11 | // Craft's Linux binary links GTK3 (libgtk-3, libgdk-3), GLib (libglib-2.0, | |
| 12 | // libgobject-2.0, libgio-2.0) and the GTK3 WebKit API (libwebkit2gtk-4.1, | |
| 13 | // libjavascriptcoregtk-4.1). It downloaded none of them, so ELF | |
| 14 | // normalization correctly refused to publish the Linux artifact with seven | |
| 15 | // unresolved libraries. Keyed under `linux` because the Darwin binaries use | |
| 16 | // the system WebKit framework and must not acquire these. | |
| 17 | dependencies: { | |
| 18 | linux: { | |
| 19 | 'gtk.org/gtk3': '^3.24', | |
| 20 | 'gnome.org/glib': '^2', | |
| 21 | 'webkitgtk.org': '^2.54', | |
| 22 | }, | |
| 23 | }, | |
| 10 | 24 | revisions: { '0.0.350': 1, '0.0.423': 1 }, |
| 11 | 25 | // Many craft GitHub releases (v0.0.16 and everything older) ship NO binary |
| 12 | 26 | // assets at all — they predate upstream's binary publishing. The scheduled |
| @@ -0,0 +1,174 @@ | ||
| 1 | import type { Recipe } from '../../scripts/recipe-types' | |
| 2 | ||
| 3 | export const recipe: Recipe = { | |
| 4 | domain: 'webkitgtk.org', | |
| 5 | name: 'webkitgtk', | |
| 6 | description: 'WebKit rendering engine for GTK, providing the webkit2gtk-4.1 API', | |
| 7 | homepage: 'https://webkitgtk.org', | |
| 8 | github: 'https://github.com/WebKit/WebKit', | |
| 9 | programs: [], | |
| 10 | ||
| 11 | // WebKitGTK 2.x builds exactly one API per configure, chosen by USE_GTK4: | |
| 12 | // ON (upstream's default) gives GTK4 + webkitgtk-6.0, OFF gives GTK3 + | |
| 13 | // webkit2gtk-4.1. Source/cmake/OptionsGTK.cmake sets WEBKITGTK_API_INFIX to | |
| 14 | // "2" for 4.1, which is why the sonames are libwebkit2gtk-4.1.so.0 and | |
| 15 | // libjavascriptcoregtk-4.1.so.0 — the two craft-native.org's Linux binary | |
| 16 | // fails to resolve. 4.1 is GTK3 + libsoup3; upstream deprecated libsoup2 | |
| 17 | // (API 4.0), and 2.54's OptionsGTK.cmake now calls find_package(Soup3 3.0.0 | |
| 18 | // REQUIRED) unconditionally, so there is no soup2 variant left to pick. | |
| 19 | // WPE and the GTK4 6.0 API are DIFFERENT APIs, not substitutes: neither | |
| 20 | // provides these sonames. | |
| 21 | platforms: ['linux/x86-64'], | |
| 22 | ||
| 23 | versionSource: { | |
| 24 | type: 'github-tags', | |
| 25 | repo: 'WebKit/WebKit', | |
| 26 | // The WebKit monorepo tags every port; only webkitgtk-* releases are ours. | |
| 27 | // Anchored, with a bounded numeric capture, so a hypothetical | |
| 28 | // webkitgtk-2.54.0-rc1 cannot match (github-tags carries no prerelease | |
| 29 | // flag) and the pattern cannot backtrack super-linearly. | |
| 30 | tagPattern: /^webkitgtk-(\d+(?:\.\d+){0,3})$/, | |
| 31 | }, | |
| 32 | ||
| 33 | distributable: { | |
| 34 | // Upstream's own release tarballs, not the monorepo archive: the GitHub | |
| 35 | // tag tree is the whole of WebKit (every port) and does not carry the | |
| 36 | // generated files the release tarball ships. | |
| 37 | url: 'https://webkitgtk.org/releases/webkitgtk-.tar.xz', | |
| 38 | stripComponents: 1, | |
| 39 | }, | |
| 40 | ||
| 41 | // libwebkit2gtk does not do its own rendering in-process: it spawns | |
| 42 | // WebKitWebProcess and WebKitNetworkProcess from PKGLIBEXECDIR and loads the | |
| 43 | // injected bundle from the lib tree (Source/WebKit/PlatformGTK.cmake installs | |
| 44 | // it under lib/webkit2gtk-4.1/injected-bundle). A consumer that bundles only | |
| 45 | // the .so gets a library that loads and then fails the moment a page is | |
| 46 | // created, so both directories travel with it. | |
| 47 | runtimeResources: [ | |
| 48 | 'libexec/webkit2gtk-4.1', | |
| 49 | 'lib/webkit2gtk-4.1/injected-bundle', | |
| 50 | ], | |
| 51 | ||
| 52 | // Every domain below is published for linux-x86-64 today; this closure was | |
| 53 | // checked against the registry before the recipe was written, because a | |
| 54 | // dependency declaration naming a provider that does not exist fails at | |
| 55 | // install time rather than at publish time. | |
| 56 | dependencies: { | |
| 57 | 'gtk.org/gtk3': '^3.24', | |
| 58 | 'gnome.org/glib': '^2', | |
| 59 | 'libsoup.org': '^3', | |
| 60 | 'unicode.org': '*', | |
| 61 | 'cairographics.org': '*', | |
| 62 | 'gnome.org/pango': '*', | |
| 63 | 'harfbuzz.org': '*', | |
| 64 | 'freetype.org': '*', | |
| 65 | 'freedesktop.org/fontconfig': '*', | |
| 66 | 'gnome.org/libxml2': '*', | |
| 67 | 'gnome.org/libxslt': '*', | |
| 68 | 'sqlite.org': '*', | |
| 69 | 'libjpeg-turbo.org': '*', | |
| 70 | 'libpng.org': '*', | |
| 71 | 'google.com/webp': '*', | |
| 72 | 'google.com/woff2': '*', | |
| 73 | 'gnu.org/libtasn1': '*', | |
| 74 | 'gnupg.org/libgcrypt': '*', | |
| 75 | 'littlecms.com': '*', | |
| 76 | 'gnome.org/atk': '*', | |
| 77 | 'gnome.org/gdk-pixbuf': '*', | |
| 78 | 'github.com/anholt/libepoxy': '*', | |
| 79 | 'gnome.org/libsecret': '*', | |
| 80 | 'openjpeg.org': '*', | |
| 81 | 'zlib.net': '*', | |
| 82 | 'x.org/x11': '*', | |
| 83 | 'x.org/exts': '*', | |
| 84 | 'wayland.freedesktop.org': '*', | |
| 85 | 'mesa3d.org': '*', | |
| 86 | }, | |
| 87 | ||
| 88 | buildDependencies: { | |
| 89 | 'cmake.org': '^3', | |
| 90 | 'ninja-build.org': '*', | |
| 91 | 'freedesktop.org/pkg-config': '*', | |
| 92 | 'gnu.org/gettext': '*', | |
| 93 | 'gnu.org/gperf': '*', | |
| 94 | 'ruby-lang.org': '*', | |
| 95 | 'python.org': '^3', | |
| 96 | }, | |
| 97 | ||
| 98 | build: { | |
| 99 | script: [ | |
| 100 | 'cmake -S . -B build -G Ninja $CMAKE_ARGS', | |
| 101 | 'cmake --build build', | |
| 102 | 'cmake --install build', | |
| 103 | ], | |
| 104 | env: { | |
| 105 | CMAKE_ARGS: [ | |
| 106 | '-DPORT=GTK', | |
| 107 | '-DCMAKE_BUILD_TYPE=Release', | |
| 108 | '-DCMAKE_INSTALL_PREFIX=', | |
| 109 | '-DCMAKE_INSTALL_LIBDIR=lib', | |
| 110 | '-DCMAKE_INSTALL_LIBEXECDIR=libexec', | |
| 111 | '-DCMAKE_INSTALL_RPATH=/lib', | |
| 112 | '-DCMAKE_FIND_FRAMEWORK=LAST', | |
| 113 | '-Wno-dev', | |
| 114 | ||
| 115 | // The API selector. Everything else here exists to keep that build's | |
| 116 | // dependency closure inside what Pantry actually publishes. | |
| 117 | '-DUSE_GTK4=OFF', | |
| 118 | ||
| 119 | // GStreamer is NOT optional behind ENABLE_VIDEO. GStreamerChecks.cmake | |
| 120 | // guards on USE_GSTREAMER and then calls find_package(GStreamer 1.18.4 | |
| 121 | // REQUIRED COMPONENTS app pbutils) with app/pbutils listed | |
| 122 | // unconditionally — turning off video and web audio alone still fails | |
| 123 | // configure. Pantry's catalog has gstreamer.freedesktop.org/orc and no | |
| 124 | // GStreamer core or gst-plugins-base, and neither does pkgx, so the | |
| 125 | // whole subsystem is off until those recipes exist. Consequence, stated | |
| 126 | // plainly: <video>, <audio> and WebAudio do not work in this build. | |
| 127 | '-DUSE_GSTREAMER=OFF', | |
| 128 | '-DENABLE_VIDEO=OFF', | |
| 129 | '-DENABLE_WEB_AUDIO=OFF', | |
| 130 | '-DENABLE_MEDIA_SOURCE=OFF', | |
| 131 | '-DENABLE_MEDIA_STREAM=OFF', | |
| 132 | '-DENABLE_MEDIA_RECORDER=OFF', | |
| 133 | '-DENABLE_MEDIA_SESSION=OFF', | |
| 134 | '-DUSE_GSTREAMER_WEBRTC=OFF', | |
| 135 | // ENABLE_WEB_RTC already defaults OFF for this port; pinning it keeps | |
| 136 | // the ENABLE_MEDIA_STREAM AND ENABLE_WEB_RTC branch in | |
| 137 | // GStreamerChecks.cmake — which sits OUTSIDE the USE_GSTREAMER guard | |
| 138 | // and would otherwise turn on the bundled libwebrtc — unreachable. | |
| 139 | '-DENABLE_WEB_RTC=OFF', | |
| 140 | ||
| 141 | // Each of these has a find_package ... FATAL_ERROR in OptionsGTK.cmake | |
| 142 | // and no provider in the catalog: Enchant (spellcheck), libhyphen | |
| 143 | // (automatic hyphenation), libmanette (gamepad), libdrm/GBM — and | |
| 144 | // ENABLE_GPU_PROCESS depends on USE_GBM, so it goes with them. | |
| 145 | '-DENABLE_SPELLCHECK=OFF', | |
| 146 | '-DUSE_LIBHYPHEN=OFF', | |
| 147 | '-DENABLE_GAMEPAD=OFF', | |
| 148 | '-DUSE_LIBDRM=OFF', | |
| 149 | '-DUSE_GBM=OFF', | |
| 150 | '-DENABLE_GPU_PROCESS=OFF', | |
| 151 | '-DENABLE_SPEECH_SYNTHESIS=OFF', | |
| 152 | '-DENABLE_JOURNALD_LOG=OFF', | |
| 153 | '-DUSE_LIBBACKTRACE=OFF', | |
| 154 | '-DUSE_JPEGXL=OFF', | |
| 155 | '-DUSE_AVIF=OFF', | |
| 156 | ||
| 157 | // The sandbox needs bubblewrap and xdg-dbus-proxy at RUNTIME, found by | |
| 158 | // absolute path; neither is a Pantry package, and a sandbox that cannot | |
| 159 | // find its helper refuses to start the web process. | |
| 160 | '-DENABLE_BUBBLEWRAP_SANDBOX=OFF', | |
| 161 | ||
| 162 | // Introspection pulls gi-docgen for documentation; craft links the C | |
| 163 | // ABI directly and needs no GIR, so both stay off to keep the build | |
| 164 | // closure to libraries we publish. | |
| 165 | '-DENABLE_INTROSPECTION=OFF', | |
| 166 | '-DENABLE_DOCUMENTATION=OFF', | |
| 167 | ||
| 168 | // MiniBrowser is a developer tool; this package ships libraries only | |
| 169 | // (programs: []), so building it would be dead weight in the artifact. | |
| 170 | '-DENABLE_MINIBROWSER=OFF', | |
| 171 | ], | |
| 172 | }, | |
| 173 | }, | |
| 174 | } | |
| @@ -0,0 +1,105 @@ | ||
| 1 | // craft-native.org's Linux artifact could not be published: its binary links | |
| 2 | // seven libraries the recipe never provided, and ELF normalization refused it. | |
| 3 | // Three of those sonames belong to a WebKit API that had no owner in the | |
| 4 | // catalog at all, so a dependency declaration alone could not have fixed it. | |
| 5 | // These tests pin the provider's identity and the closure that must exist. | |
| 6 | ||
| 7 | import { describe, expect, it } from 'bun:test' | |
| 8 | import { recipeDepsToSpecs } from '../src/dependency-spec' | |
| 9 | import { pantry } from '../src/packages' | |
| 10 | import { recipe as craft } from '../src/recipes/craft-native.org' | |
| 11 | import { recipe as webkitgtk } from '../src/recipes/webkitgtk.org' | |
| 12 | ||
| 13 | const cmakeArgs = (webkitgtk.build?.env?.CMAKE_ARGS ?? []) as string[] | |
| 14 | const byDomain = new Map(Object.values(pantry).map(entry => [(entry as any).domain, entry as any])) | |
| 15 | ||
| 16 | describe('the WebKitGTK provider owns the API craft actually links', () => { | |
| 17 | it('selects the GTK3 4.1 API rather than the GTK4 6.0 default', () => { | |
| 18 | // OptionsGTK.cmake defaults USE_GTK4 ON, which produces webkitgtk-6.0. | |
| 19 | // Only USE_GTK4=OFF yields WEBKITGTK_API_INFIX "2" and so the | |
| 20 | // libwebkit2gtk-4.1 / libjavascriptcoregtk-4.1 sonames craft needs. | |
| 21 | expect(cmakeArgs).toContain('-DUSE_GTK4=OFF') | |
| 22 | expect(cmakeArgs).toContain('-DPORT=GTK') | |
| 23 | }) | |
| 24 | ||
| 25 | it('is not a WPE or GTK4 substitute', () => { | |
| 26 | expect(webkitgtk.domain).toBe('webkitgtk.org') | |
| 27 | expect(webkitgtk.domain).not.toContain('wpewebkit') | |
| 28 | expect(JSON.stringify(webkitgtk.dependencies)).not.toContain('wpewebkit') | |
| 29 | expect(JSON.stringify(webkitgtk.dependencies)).not.toContain('gtk4') | |
| 30 | }) | |
| 31 | ||
| 32 | it('ships the helper processes and injected bundle its libraries spawn', () => { | |
| 33 | // libwebkit2gtk does not render in-process: it execs WebKitWebProcess and | |
| 34 | // WebKitNetworkProcess from PKGLIBEXECDIR and dlopens the injected bundle. | |
| 35 | // A consumer that bundles only the .so gets a library that fails on the | |
| 36 | // first page it creates. | |
| 37 | expect(webkitgtk.runtimeResources).toEqual([ | |
| 38 | 'libexec/webkit2gtk-4.1', | |
| 39 | 'lib/webkit2gtk-4.1/injected-bundle', | |
| 40 | ]) | |
| 41 | }) | |
| 42 | ||
| 43 | it('builds only where the GTK3 stack is published', () => { | |
| 44 | expect(webkitgtk.platforms).toEqual(['linux/x86-64']) | |
| 45 | }) | |
| 46 | }) | |
| 47 | ||
| 48 | describe('the provider only claims a closure the catalog can satisfy', () => { | |
| 49 | it('disables GStreamer itself, not merely video and web audio', () => { | |
| 50 | // GStreamerChecks.cmake guards on USE_GSTREAMER and then calls | |
| 51 | // find_package(GStreamer REQUIRED COMPONENTS app pbutils) with app and | |
| 52 | // pbutils listed unconditionally — ENABLE_VIDEO=OFF alone still fails | |
| 53 | // configure. Pantry publishes gstreamer.freedesktop.org/orc and no | |
| 54 | // GStreamer core, so the subsystem is off until those recipes exist. | |
| 55 | expect(cmakeArgs).toContain('-DUSE_GSTREAMER=OFF') | |
| 56 | expect(cmakeArgs).toContain('-DENABLE_VIDEO=OFF') | |
| 57 | expect(cmakeArgs).toContain('-DENABLE_WEB_AUDIO=OFF') | |
| 58 | expect(JSON.stringify(webkitgtk.dependencies)).not.toContain('gstreamer') | |
| 59 | }) | |
| 60 | ||
| 61 | it('turns off every feature whose provider the catalog lacks', () => { | |
| 62 | // Each has a find_package ... FATAL_ERROR in OptionsGTK.cmake and no | |
| 63 | // provider here: Enchant, libhyphen, libmanette, libdrm/GBM. | |
| 64 | for (const flag of ['-DENABLE_SPELLCHECK=OFF', '-DUSE_LIBHYPHEN=OFF', '-DENABLE_GAMEPAD=OFF', '-DUSE_LIBDRM=OFF', '-DUSE_GBM=OFF']) | |
| 65 | expect(cmakeArgs).toContain(flag) | |
| 66 | }) | |
| 67 | ||
| 68 | it('requires libsoup3, which is what the 4.1 API is', () => { | |
| 69 | // 2.54 calls find_package(Soup3 3.0.0 REQUIRED) unconditionally; the | |
| 70 | // libsoup2 API 4.0 variant is gone. | |
| 71 | expect((webkitgtk.dependencies as any)['libsoup.org']).toBe('^3') | |
| 72 | }) | |
| 73 | ||
| 74 | it('names only domains that exist in the catalog', () => { | |
| 75 | const declared = Object.keys(webkitgtk.dependencies ?? {}) | |
| 76 | expect(declared.length).toBeGreaterThan(0) | |
| 77 | expect(declared.filter(domain => !byDomain.has(domain))).toEqual([]) | |
| 78 | }) | |
| 79 | }) | |
| 80 | ||
| 81 | describe("craft declares its Linux runtime closure and nothing on Darwin", () => { | |
| 82 | const specs = recipeDepsToSpecs(craft.dependencies as any) | |
| 83 | ||
| 84 | it('covers each unresolved library through its owning provider', () => { | |
| 85 | // libgtk-3 / libgdk-3 → gtk3; libglib-2.0 / libgobject-2.0 / libgio-2.0 → | |
| 86 | // glib; libwebkit2gtk-4.1 / libjavascriptcoregtk-4.1 → webkitgtk. | |
| 87 | expect(specs).toEqual([ | |
| 88 | 'linux:gtk.org/gtk3^3.24', | |
| 89 | 'linux:gnome.org/glib^2', | |
| 90 | 'linux:webkitgtk.org^2.54', | |
| 91 | ]) | |
| 92 | }) | |
| 93 | ||
| 94 | it('adds nothing on Darwin, which uses the system WebKit framework', () => { | |
| 95 | expect(specs.every(spec => spec.startsWith('linux:'))).toBe(true) | |
| 96 | expect(specs.some(spec => spec.startsWith('darwin'))).toBe(false) | |
| 97 | }) | |
| 98 | ||
| 99 | it('points every declared provider at a real catalog entry', () => { | |
| 100 | for (const spec of specs) { | |
| 101 | const domain = spec.slice('linux:'.length).replace(/[@^~<>=].*$/, '') | |
| 102 | expect(byDomain.get(domain)).toBeDefined() | |
| 103 | } | |
| 104 | }) | |
| 105 | }) | |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | //! Package definitions generated from ts-pantry |
| 2 | 2 | //! DO NOT EDIT MANUALLY - This file is auto-generated |
| 3 | //! Total packages: 1767 | |
| 3 | //! Total packages: 1768 | |
| 4 | 4 | |
| 5 | 5 | const std = ; |
| 6 | 6 | |
| @@ -28,7 +28,7 @@ pub const PackageInfo = struct { | ||
| 28 | 28 | versions: []const []const u8, |
| 29 | 29 | }; |
| 30 | 30 | |
| 31 | /// All known packages (1767 total) | |
| 31 | /// All known packages (1768 total) | |
| 32 | 32 | pub const packages = [_]PackageInfo{ .{ |
| 33 | 33 | .name = "1Password", |
| 34 | 34 | .domain = "1password.com", |
| @@ -1829,7 +1829,7 @@ pub const packages = [_]PackageInfo{ .{ | ||
| 1829 | 1829 | .description = "Build desktop apps with web languages, powered by Zig", |
| 1830 | 1830 | .homepage_url = "https://craft-native.org", |
| 1831 | 1831 | .programs = &[_][]const u8{"craft"}, |
| 1832 | .dependencies = &[_][]const u8{}, | |
| 1832 | .dependencies = &[_][]const u8{ "linux:gtk.org/gtk3^3.24", "linux:gnome.org/glib^2", "linux:webkitgtk.org^2.54" }, | |
| 1833 | 1833 | .build_dependencies = &[_][]const u8{"ziglang.org"}, |
| 1834 | 1834 | .aliases = &[_][]const u8{"craft"}, |
| 1835 | 1835 | .versions = &[_][]const u8{ "0.0.424", "0.0.423.1", "0.0.423", "0.0.420", "0.0.418", "0.0.417", "0.0.416", "0.0.415", "0.0.414", "0.0.413", "0.0.411", "0.0.410", "0.0.409", "0.0.408", "0.0.396", "0.0.395", "0.0.394", "0.0.393", "0.0.392", "0.0.390", "0.0.387", "0.0.385", "0.0.384", "0.0.382", "0.0.380", "0.0.377", "0.0.375", "0.0.374", "0.0.369", "0.0.368", "0.0.366", "0.0.365", "0.0.361", "0.0.360", "0.0.359", "0.0.358", "0.0.355", "0.0.354", "0.0.353", "0.0.352", "0.0.351", "0.0.350.1", "0.0.350", "0.0.348", "0.0.346", "0.0.345", "0.0.344", "0.0.341", "0.0.340", "0.0.338", "0.0.330", "0.0.329", "0.0.328", "0.0.319", "0.0.304", "0.0.301", "0.0.299", "0.0.296", "0.0.293", "0.0.290", "0.0.278", "0.0.276", "0.0.272", "0.0.262", "0.0.254", "0.0.251", "0.0.250", "0.0.249", "0.0.248", "0.0.247", "0.0.246", "0.0.245", "0.0.244", "0.0.243", "0.0.242", "0.0.241", "0.0.238", "0.0.237", "0.0.236", "0.0.235", "0.0.234", "0.0.233", "0.0.232", "0.0.231", "0.0.228", "0.0.227", "0.0.226", "0.0.225", "0.0.224", "0.0.223", "0.0.222", "0.0.221", "0.0.220", "0.0.219", "0.0.218", "0.0.217", "0.0.216", "0.0.215", "0.0.214", "0.0.213", "0.0.212", "0.0.211", "0.0.210", "0.0.209", "0.0.207", "0.0.206", "0.0.205", "0.0.204", "0.0.203", "0.0.202", "0.0.201", "0.0.200", "0.0.199", "0.0.198", "0.0.197", "0.0.196", "0.0.195", "0.0.194", "0.0.193", "0.0.192", "0.0.191", "0.0.189", "0.0.187", "0.0.186", "0.0.185", "0.0.184", "0.0.183", "0.0.182", "0.0.181", "0.0.180", "0.0.179", "0.0.178", "0.0.177", "0.0.176", "0.0.175", "0.0.174", "0.0.173", "0.0.172", "0.0.171", "0.0.170", "0.0.169", "0.0.168", "0.0.167", "0.0.166", "0.0.164", "0.0.163", "0.0.162", "0.0.161", "0.0.160", "0.0.158", "0.0.157", "0.0.156", "0.0.155", "0.0.154", "0.0.153", "0.0.152", "0.0.151", "0.0.150", "0.0.149", "0.0.148", "0.0.147", "0.0.146", "0.0.145", "0.0.144", "0.0.143", "0.0.142", "0.0.141", "0.0.140", "0.0.139", "0.0.138", "0.0.136", "0.0.135", "0.0.134", "0.0.133", "0.0.132", "0.0.128", "0.0.127", "0.0.126", "0.0.125", "0.0.124", "0.0.123", "0.0.122", "0.0.121", "0.0.120", "0.0.119", "0.0.118", "0.0.115", "0.0.113", "0.0.112", "0.0.111", "0.0.110", "0.0.109", "0.0.107", "0.0.105", "0.0.104", "0.0.103", "0.0.101", "0.0.100", "0.0.99", "0.0.98", "0.0.97", "0.0.96", "0.0.92", "0.0.91", "0.0.90", "0.0.88", "0.0.87", "0.0.86", "0.0.85", "0.0.84", "0.0.83", "0.0.81", "0.0.80", "0.0.79", "0.0.37", "0.0.23", "0.0.20", "0.0.19" }, |
| @@ -18565,6 +18565,17 @@ pub const packages = [_]PackageInfo{ .{ | ||
| 18565 | 18565 | .build_dependencies = &[_][]const u8{ "mesonbuild.com", "python.org@~3.11", "wayland.freedesktop.org", "curl.se" }, |
| 18566 | 18566 | .aliases = &[_][]const u8{}, |
| 18567 | 18567 | .versions = &[_][]const u8{ "1.47.0", "1.46.0", "1.45.0", "1.44.0", "1.43.0", "1.42.0", "1.41.0", "1.40.0", "1.39.0", "1.38.0", "1.37.0", "1.36.0", "1.35.0", "1.34.0", "1.33.0", "1.32.0" }, |
| 18568 | }, .{ | |
| 18569 | .name = "webkitgtk", | |
| 18570 | .domain = "webkitgtk.org", | |
| 18571 | .kind = .library, | |
| 18572 | .description = "WebKit rendering engine for GTK, providing the webkit2gtk-4.1 API", | |
| 18573 | .homepage_url = "https://webkitgtk.org", | |
| 18574 | .programs = &[_][]const u8{}, | |
| 18575 | .dependencies = &[_][]const u8{ "gtk.org/gtk3^3.24", "gnome.org/glib^2", "libsoup.org^3", "unicode.org", "cairographics.org", "gnome.org/pango", "harfbuzz.org", "freetype.org", "freedesktop.org/fontconfig", "gnome.org/libxml2", "gnome.org/libxslt", "sqlite.org", "libjpeg-turbo.org", "libpng.org", "google.com/webp", "google.com/woff2", "gnu.org/libtasn1", "gnupg.org/libgcrypt", "littlecms.com", "gnome.org/atk", "gnome.org/gdk-pixbuf", "github.com/anholt/libepoxy", "gnome.org/libsecret", "openjpeg.org", "zlib.net", "x.org/x11", "x.org/exts", "wayland.freedesktop.org", "mesa3d.org" }, | |
| 18576 | .build_dependencies = &[_][]const u8{ "cmake.org^3", "ninja-build.org", "freedesktop.org/pkg-config", "gnu.org/gettext", "gnu.org/gperf", "ruby-lang.org", "python.org^3" }, | |
| 18577 | .aliases = &[_][]const u8{}, | |
| 18578 | .versions = &[_][]const u8{ "2.54.2", "2.54.1", "2.54.0" }, | |
| 18568 | 18579 | }, .{ |
| 18569 | 18580 | .name = "libvpx", |
| 18570 | 18581 | .domain = "webmproject.org/libvpx", |