Merge branch 'master' into leela-zero
This commit is contained in:
@@ -89,6 +89,13 @@ trim_trailing_whitespace = unset
|
||||
end_of_line = unset
|
||||
insert_final_newline = unset
|
||||
|
||||
# see https://manual.jule.dev/project/code-style.html#indentions
|
||||
[*.jule]
|
||||
indent_style = tab
|
||||
|
||||
[jule.mod]
|
||||
insert_final_newline = unset
|
||||
|
||||
# Keep this hint at the bottom:
|
||||
# Please don't add entries for subfolders here.
|
||||
# Create <subfolder>/.editorconfig instead.
|
||||
|
||||
@@ -193,6 +193,10 @@ cffc27daf06c77c0d76bc35d24b929cb9d68c3c9
|
||||
# nixos/kanidm: inherit lib, nixfmt
|
||||
8f18393d380079904d072007fb19dc64baef0a3a
|
||||
|
||||
# fetchgit, fetchurl, fetchzip:
|
||||
# format after refactoring with lib.extendMkDerivation (#455994)
|
||||
aeddd850c6d3485fc1af2edfb111e58141d18dc1
|
||||
|
||||
# fetchhg: format after refactoring with lib.extendMkDerivation and make overridable (#423539)
|
||||
34a5b1eb23129f8fb62c677e3760903f6d43228f
|
||||
|
||||
@@ -300,3 +304,6 @@ f7611cad5154a9096faa26d156a4079577bfae17
|
||||
90e7159c559021ac4f4cc1222000f08a91feff69 # !autorebase nix-shell --run treefmt
|
||||
c283f32d296564fd649ef3ed268c1f1f7b199c49 # !autorebase nix-shell --run treefmt
|
||||
91a8fee3aaf79348aa2dc1552a29fc1b786c5133 # !autorebase nix-shell --run treefmt
|
||||
|
||||
# aliases: keep-sorted
|
||||
48ce0739044bd6eba83c3a43bd4ad1046399cdad # !autorebase nix-shell --run treefmt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# This file is used by .github/workflows/labels.yml
|
||||
# This file is used by .github/workflows/bot.yml
|
||||
# This version is only run for Pull Requests from development branches like staging-next, haskell-updates or python-updates.
|
||||
|
||||
"4.workflow: package set update":
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# This file is used by .github/workflows/labels.yml
|
||||
# This file is used by .github/workflows/bot.yml
|
||||
# This version uses `sync-labels: false`, meaning that a non-match will NOT remove the label
|
||||
|
||||
# keep-sorted start case=no numeric=yes newline_separated=yes skip_lines=1
|
||||
@@ -29,5 +29,6 @@
|
||||
- .github/actions/*
|
||||
- .github/workflows/*
|
||||
- ci/**/*.*
|
||||
- maintainers/github-teams.json
|
||||
|
||||
# keep-sorted end
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# This file is used by .github/workflows/labels.yml
|
||||
# This file is used by .github/workflows/bot.yml
|
||||
# This version uses `sync-labels: true`, meaning that a non-match will remove the label
|
||||
|
||||
# keep-sorted start case=no numeric=yes newline_separated=yes skip_lines=1
|
||||
|
||||
@@ -64,7 +64,7 @@ This results in a key with the following semantics:
|
||||
|
||||
## Required Status Checks
|
||||
|
||||
The "Required Status Checks" branch ruleset is implemented in two top-level workflows: `pr.yml` and `merge-group.yml`.
|
||||
The "Required Status Checks" branch ruleset is implemented in two top-level workflows: `pull-request-target.yml` and `merge-group.yml`.
|
||||
|
||||
The PR workflow defines all checks that need to succeed to add a Pull Request to the Merge Queue.
|
||||
If no Merge Queue is set up for a branch, the PR workflow defines the checks required to merge into the target branch.
|
||||
|
||||
@@ -40,6 +40,7 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Log current API rate limits
|
||||
env:
|
||||
@@ -48,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Create backport PRs
|
||||
id: backport
|
||||
uses: korthout/backport-action@ca4972adce8039ff995e618f5fc02d1b7961f27a # v3.3.0
|
||||
uses: korthout/backport-action@d07416681cab29bf2661702f925f020aaa962997 # v3.4.1
|
||||
with:
|
||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||
copy_labels_pattern: 'severity:\ssecurity'
|
||||
@@ -56,8 +57,9 @@ jobs:
|
||||
pull_description: |-
|
||||
Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}.
|
||||
|
||||
* [ ] Before merging, ensure that this backport is [acceptable for the release](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#changes-acceptable-for-releases).
|
||||
* Even as a non-committer, if you find that it is not acceptable, leave a comment.
|
||||
**Before merging, ensure that this backport is [acceptable for the release](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#changes-acceptable-for-releases).**
|
||||
|
||||
Even as a non-committer, if you find that it is not acceptable, leave a comment.
|
||||
|
||||
- name: Log current API rate limits
|
||||
env:
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
# access to the GitHub API. This means that it should not evaluate user input in
|
||||
# a way that allows code injection.
|
||||
|
||||
name: Labels
|
||||
name: Bot
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '07,17,27,37,47,57 * * * *'
|
||||
# Run every 10m
|
||||
# i.e., at each of the listed minutes, every hour
|
||||
- cron: '05,15,25,35,45,55 * * * *'
|
||||
workflow_call:
|
||||
inputs:
|
||||
headBranch:
|
||||
@@ -21,7 +23,7 @@ on:
|
||||
concurrency:
|
||||
# This explicitly avoids using `run_id` for the concurrency key to make sure that only
|
||||
# *one* scheduled run can run at a time.
|
||||
group: labels-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number }}
|
||||
group: bot-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number }}
|
||||
# PR-triggered runs will be cancelled, but scheduled runs will be queued.
|
||||
cancel-in-progress: ${{ github.event_name != 'schedule' }}
|
||||
|
||||
@@ -36,7 +38,7 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
run:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
if: github.event_name != 'schedule' || github.repository_owner == 'NixOS'
|
||||
env:
|
||||
@@ -46,6 +48,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
|
||||
@@ -59,7 +62,10 @@ jobs:
|
||||
with:
|
||||
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
|
||||
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
permission-administration: read
|
||||
permission-contents: write
|
||||
permission-issues: write
|
||||
permission-members: read
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Log current API rate limits
|
||||
@@ -67,13 +73,13 @@ jobs:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Labels from API data and Eval results
|
||||
- name: Run bot
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token || github.token }}
|
||||
retries: 3
|
||||
script: |
|
||||
require('./ci/github-script/labels.js')({
|
||||
require('./ci/github-script/bot.js')({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
@@ -3,6 +3,9 @@ name: Build
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
artifact-prefix:
|
||||
required: true
|
||||
type: string
|
||||
baseBranch:
|
||||
required: true
|
||||
type: string
|
||||
@@ -46,13 +49,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Checkout the merge commit
|
||||
uses: ./.github/actions/checkout
|
||||
with:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
|
||||
- uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
- uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
with:
|
||||
# Sandbox is disabled on MacOS by default.
|
||||
extra_nix_config: sandbox = true
|
||||
@@ -97,7 +101,7 @@ jobs:
|
||||
if: |
|
||||
contains(matrix.builds, 'manual-nixos') && !cancelled() &&
|
||||
contains(fromJSON(inputs.baseBranch).type, 'primary')
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: nixos-manual-${{ matrix.name }}
|
||||
name: ${{ inputs.artifact-prefix }}nixos-manual-${{ matrix.name }}
|
||||
path: nixos-manual
|
||||
|
||||
@@ -34,6 +34,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
@@ -73,13 +74,15 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Checkout merge and target commits
|
||||
uses: ./.github/actions/checkout
|
||||
with:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
- uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||
with:
|
||||
@@ -90,7 +93,7 @@ jobs:
|
||||
pushFilter: -source$
|
||||
|
||||
- name: Build codeowners validator
|
||||
run: nix-build nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A codeownersValidator
|
||||
run: nix-build nixpkgs/trusted/ci --arg nixpkgs ./nixpkgs/trusted-pinned -A codeownersValidator
|
||||
|
||||
- name: Validate codeowners
|
||||
env:
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Comment
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
# This is used as fallback without app only.
|
||||
# This happens when testing in forks without setting up that app.
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# The `bot` workflow reacts to comments with @NixOS/nixpkgs-merge-bot references, but might only
|
||||
# pick up a comment after up to 10 minutes. To give the user instant feedback, this job adds
|
||||
# a reaction to these comments.
|
||||
react:
|
||||
name: React with eyes
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 2
|
||||
if: contains(github.event.comment.body, '@NixOS/nixpkgs-merge-bot merge')
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
|
||||
# Use the GitHub App to make sure the reaction happens with the same user who will later merge.
|
||||
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
|
||||
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
|
||||
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
permission-pull-requests: write
|
||||
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token || github.token }}
|
||||
retries: 3
|
||||
script: |
|
||||
const { handleMergeComment } = require('./ci/github-script/merge.js')
|
||||
const { body, node_id } = context.payload.comment
|
||||
|
||||
await handleMergeComment({
|
||||
github,
|
||||
body,
|
||||
node_id,
|
||||
reaction: 'EYES',
|
||||
})
|
||||
@@ -1,66 +0,0 @@
|
||||
name: Dismissed review
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Review dismissed
|
||||
types: [completed]
|
||||
|
||||
concurrency:
|
||||
group: dismissed-review-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# The `check-cherry-picks` workflow creates review comments which reviewers
|
||||
# are encouraged to manually dismiss if they're not relevant.
|
||||
# When a CI-generated review is dismissed, this job automatically minimizes
|
||||
# it, preventing it from cluttering the PR.
|
||||
minimize:
|
||||
name: Minimize as resolved
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
script: |
|
||||
// PRs from forks don't have any PRs associated by default.
|
||||
// Thus, we request the PR number with an API call *to* the fork's repo.
|
||||
// Multiple pull requests can be open from the same head commit, either via
|
||||
// different base branches or head branches.
|
||||
const { head_repository, head_sha, repository } = context.payload.workflow_run
|
||||
await Promise.all(
|
||||
(await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, {
|
||||
owner: head_repository.owner.login,
|
||||
repo: head_repository.name,
|
||||
commit_sha: head_sha
|
||||
}))
|
||||
.filter(pull_request => pull_request.base.repo.id == repository.id)
|
||||
.map(async (pull_request) =>
|
||||
Promise.all(
|
||||
(await github.paginate(github.rest.pulls.listReviews, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pull_request.number
|
||||
})).filter(review =>
|
||||
review.user?.login == 'github-actions[bot]' &&
|
||||
review.state == 'DISMISSED'
|
||||
).map(review => github.graphql(`
|
||||
mutation($node_id:ID!) {
|
||||
minimizeComment(input: {
|
||||
classifier: RESOLVED,
|
||||
subjectId: $node_id
|
||||
})
|
||||
{ clientMutationId }
|
||||
}`,
|
||||
{ node_id: review.node_id }
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
+53
-30
@@ -3,6 +3,9 @@ name: Eval
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
artifact-prefix:
|
||||
required: true
|
||||
type: string
|
||||
mergedSha:
|
||||
required: true
|
||||
type: string
|
||||
@@ -34,6 +37,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
sparse-checkout: |
|
||||
ci/supportedVersions.nix
|
||||
@@ -41,13 +45,14 @@ jobs:
|
||||
- name: Check out the PR at the test merge commit
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ inputs.mergedSha }}
|
||||
path: untrusted
|
||||
sparse-checkout: |
|
||||
ci/pinned.json
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- name: Load supported versions
|
||||
id: versions
|
||||
@@ -84,6 +89,7 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Check out the PR at merged and target commits
|
||||
uses: ./.github/actions/checkout
|
||||
@@ -92,7 +98,7 @@ jobs:
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||
with:
|
||||
@@ -107,7 +113,7 @@ jobs:
|
||||
MATRIX_SYSTEM: ${{ matrix.system }}
|
||||
MATRIX_VERSION: ${{ matrix.version || 'nixVersions.latest' }}
|
||||
run: |
|
||||
nix-build nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A eval.singleSystem \
|
||||
nix-build nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A eval.singleSystem \
|
||||
--argstr evalSystem "$MATRIX_SYSTEM" \
|
||||
--arg chunkSize 8000 \
|
||||
--argstr nixPath "$MATRIX_VERSION" \
|
||||
@@ -116,19 +122,29 @@ jobs:
|
||||
# Note: Keep the same further down in sync!
|
||||
|
||||
- name: Evaluate the ${{ matrix.system }} output paths at the target commit
|
||||
if: inputs.targetSha
|
||||
env:
|
||||
MATRIX_SYSTEM: ${{ matrix.system }}
|
||||
# This is very quick, because it pulls the eval results from Cachix.
|
||||
run: |
|
||||
nix-build nixpkgs/trusted/ci --arg nixpkgs ./nixpkgs/trusted-pinned -A eval.singleSystem \
|
||||
TARGET_DRV=$(nix-instantiate nixpkgs/trusted/ci --arg nixpkgs ./nixpkgs/trusted-pinned -A eval.singleSystem \
|
||||
--argstr evalSystem "$MATRIX_SYSTEM" \
|
||||
--arg chunkSize 8000 \
|
||||
--argstr nixPath "nixVersions.latest" \
|
||||
--out-link target
|
||||
--argstr nixPath "nixVersions.latest")
|
||||
|
||||
# Try to fetch this from Cachix a few times, for up to 30 seconds. This avoids running Eval
|
||||
# twice in the Merge Queue, when a later item finishes Eval at the merge commit earlier.
|
||||
for _i in {1..6}; do
|
||||
# Using --max-jobs 0 will cause nix-build to fail if this can't be substituted from cachix.
|
||||
if nix-build "$TARGET_DRV" --max-jobs 0; then
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Either fetches from Cachix or runs Eval itself. The fallback is required
|
||||
# for pull requests into wip-branches without merge queue.
|
||||
nix-build "$TARGET_DRV" --out-link target
|
||||
|
||||
- name: Compare outpaths against the target branch
|
||||
if: inputs.targetSha
|
||||
env:
|
||||
MATRIX_SYSTEM: ${{ matrix.system }}
|
||||
run: |
|
||||
@@ -139,22 +155,22 @@ jobs:
|
||||
--out-link diff
|
||||
|
||||
- name: Upload outpaths diff and stats
|
||||
if: inputs.targetSha
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: ${{ matrix.version && format('{0}-', matrix.version) || '' }}diff-${{ matrix.system }}
|
||||
name: ${{ inputs.artifact-prefix }}${{ matrix.version && format('{0}-', matrix.version) || '' }}diff-${{ matrix.system }}
|
||||
path: diff/*
|
||||
|
||||
compare:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
needs: [eval]
|
||||
if: inputs.targetSha && !cancelled() && !failure()
|
||||
if: ${{ !cancelled() && !failure() }}
|
||||
permissions:
|
||||
statuses: write
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Check out the PR at the target commit
|
||||
uses: ./.github/actions/checkout
|
||||
@@ -163,14 +179,14 @@ jobs:
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- name: Download output paths and eval stats for all systems
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
||||
with:
|
||||
pattern: diff-*
|
||||
pattern: ${{ inputs.artifact-prefix }}diff-*
|
||||
path: diff
|
||||
merge-multiple: true
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- name: Combine all output paths and eval stats
|
||||
run: |
|
||||
@@ -178,26 +194,31 @@ jobs:
|
||||
--arg diffDir ./diff \
|
||||
--out-link combined
|
||||
|
||||
- name: Upload the maintainer list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifact-prefix }}maintainers
|
||||
path: combined/maintainers.json
|
||||
|
||||
- name: Compare against the target branch
|
||||
env:
|
||||
AUTHOR_ID: ${{ github.event.pull_request.user.id }}
|
||||
TARGET_SHA: ${{ inputs.mergedSha }}
|
||||
run: |
|
||||
git -C nixpkgs/trusted diff --name-only ${{ inputs.mergedSha }} \
|
||||
git -C nixpkgs/trusted diff --name-only "$TARGET_SHA" \
|
||||
| jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json
|
||||
|
||||
# Use the target branch to get accurate maintainer info
|
||||
nix-build nixpkgs/trusted/ci --arg nixpkgs ./nixpkgs/trusted-pinned -A eval.compare \
|
||||
--arg combinedDir ./combined \
|
||||
--arg touchedFilesJson ./touched-files.json \
|
||||
--argstr githubAuthorId "$AUTHOR_ID" \
|
||||
--out-link comparison
|
||||
|
||||
cat comparison/step-summary.md >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Upload the comparison results
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: comparison
|
||||
name: ${{ inputs.artifact-prefix }}comparison
|
||||
path: comparison/*
|
||||
|
||||
- name: Add eval summary to commit statuses
|
||||
@@ -237,7 +258,7 @@ jobs:
|
||||
needs: [versions, eval]
|
||||
steps:
|
||||
- name: Download output paths and eval stats for all versions
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
||||
with:
|
||||
pattern: "*-diff-*"
|
||||
path: versions
|
||||
@@ -245,6 +266,7 @@ jobs:
|
||||
- name: Add version comparison table to job summary
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
ARTIFACT_PREFIX: ${{ inputs.artifact-prefix }}
|
||||
SYSTEMS: ${{ inputs.systems }}
|
||||
VERSIONS: ${{ needs.versions.outputs.versions }}
|
||||
with:
|
||||
@@ -252,6 +274,7 @@ jobs:
|
||||
const { readFileSync } = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const prefix = process.env.ARTIFACT_PREFIX
|
||||
const systems = JSON.parse(process.env.SYSTEMS)
|
||||
const versions = JSON.parse(process.env.VERSIONS)
|
||||
|
||||
@@ -267,7 +290,7 @@ jobs:
|
||||
[{ data: version }].concat(
|
||||
systems.map((system) => {
|
||||
try {
|
||||
const artifact = path.join('versions', `${version}-diff-${system}`)
|
||||
const artifact = path.join('versions', `${prefix}${version}-diff-${system}`)
|
||||
const time = Math.round(
|
||||
parseFloat(
|
||||
readFileSync(
|
||||
@@ -279,12 +302,11 @@ jobs:
|
||||
const diff = JSON.parse(
|
||||
readFileSync(path.join(artifact, system, 'diff.json'), 'utf-8'),
|
||||
)
|
||||
const attrs = [].concat(
|
||||
diff.added,
|
||||
diff.removed,
|
||||
diff.changed,
|
||||
diff.rebuilds
|
||||
)
|
||||
const attrs = []
|
||||
.concat(diff.added, diff.removed, diff.changed, diff.rebuilds)
|
||||
// There are some special attributes, which are ignored for rebuilds.
|
||||
// These only have a single path component, because they lack the `.<system>` suffix.
|
||||
.filter((attr) => attr.split('.').length > 1)
|
||||
if (attrs.length > 0) {
|
||||
core.setFailed(
|
||||
`${version} on ${system} has changed outpaths!\nNote: Please make sure to update ci/pinned.json separately from changes to other packages.`,
|
||||
@@ -319,6 +341,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Checkout the merge commit
|
||||
uses: ./.github/actions/checkout
|
||||
@@ -326,7 +349,7 @@ jobs:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- name: Run misc eval tasks in parallel
|
||||
run: |
|
||||
|
||||
@@ -26,13 +26,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Checkout the merge commit
|
||||
uses: ./.github/actions/checkout
|
||||
with:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
|
||||
- uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
- uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
# TODO: Figure out how to best enable caching for the treefmt job. Cachix won't work well,
|
||||
# because the cache would be invalidated on every commit - treefmt checks every file.
|
||||
@@ -60,13 +61,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Checkout the merge commit
|
||||
uses: ./.github/actions/checkout
|
||||
with:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
|
||||
- uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
- uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||
with:
|
||||
@@ -87,6 +89,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
- name: Checkout merge and target commits
|
||||
uses: ./.github/actions/checkout
|
||||
@@ -94,7 +97,7 @@ jobs:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
- uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31
|
||||
|
||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||
with:
|
||||
|
||||
@@ -4,6 +4,9 @@ on:
|
||||
merge_group:
|
||||
workflow_call:
|
||||
inputs:
|
||||
artifact-prefix:
|
||||
required: true
|
||||
type: string
|
||||
mergedSha:
|
||||
required: true
|
||||
type: string
|
||||
@@ -24,6 +27,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/supportedSystems.json
|
||||
|
||||
@@ -53,7 +57,9 @@ jobs:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
with:
|
||||
artifact-prefix: ${{ inputs.artifact-prefix }}
|
||||
mergedSha: ${{ inputs.mergedSha || github.event.merge_group.head_sha }}
|
||||
targetSha: ${{ inputs.targetSha || github.event.merge_group.base_sha }}
|
||||
systems: ${{ needs.prepare.outputs.systems }}
|
||||
|
||||
# This job's only purpose is to create the target for the "Required Status Checks" branch ruleset.
|
||||
|
||||
@@ -43,4 +43,5 @@ jobs:
|
||||
from: ${{ matrix.pairs.from }}
|
||||
into: ${{ matrix.pairs.into }}
|
||||
name: ${{ matrix.pairs.name || format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }}
|
||||
secrets: inherit
|
||||
secrets:
|
||||
NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
|
||||
@@ -42,4 +42,5 @@ jobs:
|
||||
from: ${{ matrix.pairs.from }}
|
||||
into: ${{ matrix.pairs.into }}
|
||||
name: ${{ format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }}
|
||||
secrets: inherit
|
||||
secrets:
|
||||
NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
|
||||
@@ -11,6 +11,9 @@ on:
|
||||
description: Target branch to merge into.
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
NIXPKGS_CI_APP_PRIVATE_KEY:
|
||||
required: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -32,6 +35,8 @@ jobs:
|
||||
permission-pull-requests: write
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Find merge base between two branches
|
||||
if: contains(inputs.from, ' ')
|
||||
|
||||
@@ -3,14 +3,15 @@ name: PR
|
||||
on:
|
||||
pull_request_target:
|
||||
workflow_call:
|
||||
inputs:
|
||||
artifact-prefix:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN:
|
||||
required: true
|
||||
NIXPKGS_CI_APP_PRIVATE_KEY:
|
||||
required: true
|
||||
OWNER_APP_PRIVATE_KEY:
|
||||
# The Test workflow should not actually request reviews from owners.
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: pr-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -34,12 +35,19 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout-cone-mode: true # default, for clarity
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
- id: prepare
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
retries: 10
|
||||
# The default for this includes code 422, which happens regularly for us when comparing commits:
|
||||
# 422 - Server Error: Sorry, this diff is taking too long to generate.
|
||||
# Listing all other values from here to effectively remove 422:
|
||||
# https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
|
||||
retry-exempt-status-codes: 400,401,403,404
|
||||
script: |
|
||||
require('./ci/github-script/prepare.js')({
|
||||
github,
|
||||
@@ -83,15 +91,16 @@ jobs:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
with:
|
||||
artifact-prefix: ${{ inputs.artifact-prefix }}
|
||||
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
|
||||
targetSha: ${{ needs.prepare.outputs.targetSha }}
|
||||
systems: ${{ needs.prepare.outputs.systems }}
|
||||
testVersions: ${{ contains(fromJSON(needs.prepare.outputs.touched), 'pinned') && !contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development') }}
|
||||
|
||||
labels:
|
||||
name: Labels
|
||||
bot:
|
||||
name: Bot
|
||||
needs: [prepare, eval]
|
||||
uses: ./.github/workflows/labels.yml
|
||||
uses: ./.github/workflows/bot.yml
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
@@ -100,16 +109,6 @@ jobs:
|
||||
with:
|
||||
headBranch: ${{ needs.prepare.outputs.headBranch }}
|
||||
|
||||
reviewers:
|
||||
name: Reviewers
|
||||
needs: [prepare, eval]
|
||||
if: |
|
||||
needs.prepare.outputs.targetSha &&
|
||||
!contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development')
|
||||
uses: ./.github/workflows/reviewers.yml
|
||||
secrets:
|
||||
OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }}
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: [prepare]
|
||||
@@ -117,6 +116,7 @@ jobs:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
with:
|
||||
artifact-prefix: ${{ inputs.artifact-prefix }}
|
||||
baseBranch: ${{ needs.prepare.outputs.baseBranch }}
|
||||
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
name: Review
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Reviewed
|
||||
types: [completed]
|
||||
|
||||
# This is used as fallback without app only.
|
||||
# This happens when testing in forks without setting up that app.
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
process:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
|
||||
# Use the GitHub App to make sure the reaction happens with the same user who will later merge.
|
||||
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
|
||||
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
|
||||
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
permission-pull-requests: write
|
||||
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token || github.token }}
|
||||
retries: 3
|
||||
script: |
|
||||
const { handleMergeComment } = require('./ci/github-script/merge.js')
|
||||
|
||||
// PRs from forks don't have any PRs associated by default.
|
||||
// Thus, we request the PR number with an API call *to* the fork's repo.
|
||||
// Multiple pull requests can be open from the same head commit, either via
|
||||
// different base branches or head branches.
|
||||
const { head_repository, head_sha, repository } = context.payload.workflow_run
|
||||
await Promise.all(
|
||||
(await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, {
|
||||
owner: head_repository.owner.login,
|
||||
repo: head_repository.name,
|
||||
commit_sha: head_sha
|
||||
}))
|
||||
.filter(pull_request => pull_request.base.repo.id == repository.id)
|
||||
.map(async (pull_request) =>
|
||||
Promise.all(
|
||||
(await github.paginate(github.rest.pulls.listReviews, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pull_request.number
|
||||
})).map(review => {
|
||||
// The `check` workflow creates review comments which reviewers
|
||||
// are encouraged to manually dismiss if they're not relevant.
|
||||
// When a CI-generated review is dismissed, this job automatically minimizes
|
||||
// it, preventing it from cluttering the PR.
|
||||
if (review.user?.login == 'github-actions[bot]' && review.state == 'DISMISSED')
|
||||
return github.graphql(`
|
||||
mutation($node_id:ID!) {
|
||||
minimizeComment(input: {
|
||||
classifier: RESOLVED,
|
||||
subjectId: $node_id
|
||||
})
|
||||
{ clientMutationId }
|
||||
}`,
|
||||
{ node_id: review.node_id }
|
||||
)
|
||||
|
||||
// The `bot` workflow reacts to comments with @NixOS/nixpkgs-merge-bot references, but might only
|
||||
// pick up a comment after up to 10 minutes. To give the user instant feedback, this job adds
|
||||
// a reaction to these comments.
|
||||
return handleMergeComment({
|
||||
github,
|
||||
body: review.body,
|
||||
node_id: review.node_id,
|
||||
reaction: 'EYES',
|
||||
})
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1,8 +1,8 @@
|
||||
name: Review dismissed
|
||||
name: Reviewed
|
||||
|
||||
on:
|
||||
pull_request_review:
|
||||
types: [dismissed]
|
||||
types: [submitted, dismissed]
|
||||
|
||||
permissions: {}
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
# This workflow will request reviews from the maintainers of each package
|
||||
# listed in the PR's most recent eval comparison artifact.
|
||||
|
||||
name: Reviewers
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ready_for_review]
|
||||
workflow_call:
|
||||
secrets:
|
||||
OWNER_APP_PRIVATE_KEY:
|
||||
required: true
|
||||
|
||||
concurrency:
|
||||
group: reviewers-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
request:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Check out the PR at the base commit
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
path: trusted
|
||||
sparse-checkout: ci
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31
|
||||
|
||||
- name: Build the requestReviews derivation
|
||||
run: nix-build trusted/ci -A requestReviews
|
||||
|
||||
# For requesting reviewers, this job depends on a GitHub App with the following permissions:
|
||||
# - Permissions:
|
||||
# - Repository > Administration: read-only
|
||||
# - Organization > Members: read-only
|
||||
# - Repository > Pull Requests: read-write
|
||||
# - Install App on this repository, setting these variables:
|
||||
# - OWNER_APP_ID (variable)
|
||||
# - OWNER_APP_PRIVATE_KEY (secret)
|
||||
#
|
||||
# Can't use the token received from permissions above, because it can't get enough permissions.
|
||||
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
|
||||
if: github.event_name == 'pull_request_target' && vars.OWNER_APP_ID
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.OWNER_APP_ID }}
|
||||
private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }}
|
||||
permission-administration: read
|
||||
permission-members: read
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Log current API rate limits (app-token)
|
||||
if: ${{ steps.app-token.outputs.token }}
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Requesting code owner reviews
|
||||
if: steps.app-token.outputs.token
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
NUMBER: ${{ github.event.number }}
|
||||
# Don't do anything on draft PRs
|
||||
DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }}
|
||||
run: result/bin/request-code-owner-reviews.sh "$REPOSITORY" "$NUMBER" ci/OWNERS
|
||||
|
||||
- name: Log current API rate limits (app-token)
|
||||
if: ${{ steps.app-token.outputs.token }}
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Log current API rate limits (github.token)
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
# In the regular case, this workflow is called via workflow_call from the eval workflow directly.
|
||||
# In the more special case, when a PR is undrafted an eval run will have started already.
|
||||
- name: Wait for comparison to be done
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
id: eval
|
||||
with:
|
||||
script: |
|
||||
const run_id = (await github.rest.actions.listWorkflowRuns({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: context.eventName === 'pull_request' ? 'test.yml' : 'pr.yml',
|
||||
event: context.eventName,
|
||||
head_sha: context.payload.pull_request.head.sha
|
||||
})).data.workflow_runs[0].id
|
||||
|
||||
core.setOutput('run-id', run_id)
|
||||
|
||||
// Waiting 120 * 5 sec = 10 min. max.
|
||||
// The extreme case is an Eval run that just started when the PR is undrafted.
|
||||
// Eval takes max 5-6 minutes, normally.
|
||||
for (let i = 0; i < 120; i++) {
|
||||
const result = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id,
|
||||
name: 'comparison'
|
||||
})
|
||||
if (result.data.total_count > 0) return
|
||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||
}
|
||||
throw new Error("No comparison artifact found.")
|
||||
|
||||
- name: Log current API rate limits (github.token)
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Download the comparison results
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
run-id: ${{ steps.eval.outputs.run-id }}
|
||||
github-token: ${{ github.token }}
|
||||
pattern: comparison
|
||||
path: comparison
|
||||
merge-multiple: true
|
||||
|
||||
- name: Log current API rate limits (app-token)
|
||||
if: ${{ steps.app-token.outputs.token }}
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Log current API rate limits (github.token)
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Requesting maintainer reviews
|
||||
if: ${{ steps.app-token.outputs.token }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
NUMBER: ${{ github.event.number }}
|
||||
AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
# Don't request reviewers on draft PRs
|
||||
DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }}
|
||||
run: |
|
||||
# maintainers.json contains GitHub IDs. Look up handles to request reviews from.
|
||||
# There appears to be no API to request reviews based on GitHub IDs
|
||||
jq -r 'keys[]' comparison/maintainers.json \
|
||||
| while read -r id; do gh api /user/"$id" --jq .login; done \
|
||||
| GH_TOKEN=${{ steps.app-token.outputs.token }} result/bin/request-reviewers.sh "$REPOSITORY" "$NUMBER" "$AUTHOR"
|
||||
|
||||
- name: Log current API rate limits (app-token)
|
||||
if: ${{ steps.app-token.outputs.token }}
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- name: Log current API rate limits (github.token)
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
@@ -0,0 +1,79 @@
|
||||
name: Teams
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Every Tuesday at 19:42 (randomly chosen)
|
||||
- cron: '42 19 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
# Use a GitHub App to create the PR so that CI gets triggered and to
|
||||
# request team member lists.
|
||||
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
|
||||
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
permission-administration: read
|
||||
permission-contents: write
|
||||
permission-members: read
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Fetch source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
maintainers/github-teams.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install bottleneck
|
||||
|
||||
- name: Synchronise teams
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token }}
|
||||
script: |
|
||||
require('./ci/github-script/get-teams.js')({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
outFile: "maintainers/github-teams.json"
|
||||
})
|
||||
|
||||
- name: Get GitHub App User Git String
|
||||
id: user
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
|
||||
run: |
|
||||
name="${APP_SLUG}[bot]"
|
||||
userId=$(gh api "/users/$name" --jq .id)
|
||||
email="$userId+$name@users.noreply.github.com"
|
||||
echo "git-string=$name <$email>" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
add-paths: maintainers/github-teams.json
|
||||
author: ${{ steps.user.outputs.git-string }}
|
||||
committer: ${{ steps.user.outputs.git-string }}
|
||||
commit-message: "maintainers/github-teams.json: Automated sync"
|
||||
branch: pr/github-team-sync
|
||||
title: "maintainers/github-teams.json: Automated sync"
|
||||
body: |
|
||||
This is an automated PR to sync the GitHub teams with access to this repository to the `lib.teams` list.
|
||||
|
||||
This PR can be merged without taking any further action.
|
||||
|
||||
@@ -21,12 +21,19 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout-cone-mode: true # default, for clarity
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
- id: prepare
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
retries: 10
|
||||
# The default for this includes code 422, which happens regularly for us when comparing commits:
|
||||
# 422 - Server Error: Sorry, this diff is taking too long to generate.
|
||||
# Listing all other values from here to effectively remove 422:
|
||||
# https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
|
||||
retry-exempt-status-codes: 400,401,403,404
|
||||
script: |
|
||||
require('./ci/github-script/prepare.js')({
|
||||
github,
|
||||
@@ -56,14 +63,16 @@ jobs:
|
||||
|
||||
if (files.some(file => [
|
||||
'.github/actions/checkout/action.yml',
|
||||
'.github/workflows/bot.yml',
|
||||
'.github/workflows/build.yml',
|
||||
'.github/workflows/check.yml',
|
||||
'.github/workflows/eval.yml',
|
||||
'.github/workflows/labels.yml',
|
||||
'.github/workflows/lint.yml',
|
||||
'.github/workflows/pr.yml',
|
||||
'.github/workflows/reviewers.yml',
|
||||
'.github/workflows/pull-request-target.yml',
|
||||
'.github/workflows/test.yml',
|
||||
'ci/github-script/bot.js',
|
||||
'ci/github-script/merge.js',
|
||||
'ci/github-script/withRateLimit.js',
|
||||
].includes(file))) core.setOutput('pr', true)
|
||||
|
||||
merge-group:
|
||||
@@ -77,6 +86,7 @@ jobs:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
with:
|
||||
artifact-prefix: mg-
|
||||
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
|
||||
targetSha: ${{ needs.prepare.outputs.targetSha }}
|
||||
|
||||
@@ -84,7 +94,7 @@ jobs:
|
||||
if: needs.prepare.outputs.pr
|
||||
name: PR
|
||||
needs: [prepare]
|
||||
uses: ./.github/workflows/pr.yml
|
||||
uses: ./.github/workflows/pull-request-target.yml
|
||||
# Those are actually only used on the pull_request_target event, but will throw an error if not set.
|
||||
permissions:
|
||||
issues: write
|
||||
@@ -93,3 +103,5 @@ jobs:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
|
||||
with:
|
||||
artifact-prefix: pr-
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# This file defines the ignore rules for zizmor.
|
||||
#
|
||||
# For rules that contain a high number of false positives, prefer listing them here
|
||||
# instead of adding ignore comments. Note that zizmor cannot ignore by line-within-a-string, so
|
||||
# there are some ignore items that encompass multiple problems within one `run` block. An issue
|
||||
# tracking this is at https://github.com/woodruffw/zizmor/issues/648.
|
||||
#
|
||||
# For more info, see the documentation: https://woodruffw.github.io/zizmor/usage/#ignoring-results
|
||||
|
||||
rules:
|
||||
dangerous-triggers:
|
||||
disable: true
|
||||
+2
-2
@@ -430,7 +430,7 @@ gitGraph
|
||||
|
||||
Here's an overview of the different branches:
|
||||
|
||||
| branch | `master` | `staging-next` | `staging` | [`staging-nixos`](#test-driver-rebuild) |
|
||||
| branch | `master` | `staging-next` | `staging` | [`staging-nixos`][test-driver-rebuild] |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Used for development | ✔️ | ❌ | ✔️ | ✔️ |
|
||||
| Built by Hydra | ✔️ | ✔️ | ❌ | ❌ |
|
||||
@@ -501,7 +501,7 @@ Please note that changes to the Linux kernel are an exception to this rule.
|
||||
These PRs go to `staging-nixos`, see [the next section for more context](#changes-rebuilding-all-tests).
|
||||
|
||||
### Changes rebuilding all NixOS tests
|
||||
[test-driver-rebuild]: #changes-rebuilding-all-tests
|
||||
[test-driver-rebuild]: #changes-rebuilding-all-nixos-tests
|
||||
|
||||
Changes causing a rebuild of all NixOS tests get a special [`10.rebuild-nixos-tests`](https://github.com/NixOS/nixpkgs/issues?q=state%3Aopen%20label%3A10.rebuild-nixos-tests) label.
|
||||
These changes pose a significant impact on the build infrastructure.
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
/lib/asserts.nix @infinisil @hsjobeki @Profpatsch
|
||||
/lib/path/* @infinisil @hsjobeki
|
||||
/lib/fileset @infinisil @hsjobeki
|
||||
/maintainers/github-teams.json @infinisil
|
||||
/maintainers/computed-team-list.nix @infinisil
|
||||
## Standard environment–related libraries
|
||||
/lib/customisation.nix @alyssais @NixOS/stdenv
|
||||
/lib/derivations.nix @alyssais @NixOS/stdenv
|
||||
@@ -56,7 +58,8 @@
|
||||
/pkgs/top-level/by-name-overlay.nix @infinisil @philiptaron
|
||||
/pkgs/stdenv @philiptaron @NixOS/stdenv
|
||||
/pkgs/stdenv/generic @Ericson2314 @NixOS/stdenv
|
||||
/pkgs/stdenv/generic/check-meta.nix @Ericson2314 @NixOS/stdenv
|
||||
/pkgs/stdenv/generic/check-meta.nix @Ericson2314 @adisbladis @NixOS/stdenv
|
||||
/pkgs/stdenv/generic/meta-types.nix @adisbladis @NixOS/stdenv
|
||||
/pkgs/stdenv/cross @Ericson2314 @NixOS/stdenv
|
||||
/pkgs/build-support @philiptaron
|
||||
/pkgs/build-support/cc-wrapper @Ericson2314
|
||||
@@ -212,10 +215,10 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @NixOS/nix-team @raitobeza
|
||||
/pkgs/development/r-modules @jbedo
|
||||
|
||||
# Rust
|
||||
/pkgs/development/compilers/rust @alyssais @Mic92 @zowoq @winterqt @figsoda
|
||||
/pkgs/build-support/rust @zowoq @winterqt @figsoda
|
||||
/pkgs/development/compilers/rust @alyssais @Mic92 @zowoq @winterqt
|
||||
/pkgs/build-support/rust @zowoq @winterqt
|
||||
/pkgs/build-support/rust/fetch-cargo-vendor* @TomaSajt
|
||||
/doc/languages-frameworks/rust.section.md @zowoq @winterqt @figsoda
|
||||
/doc/languages-frameworks/rust.section.md @zowoq @winterqt
|
||||
|
||||
# Tcl
|
||||
/pkgs/development/interpreters/tcl @fgaz
|
||||
@@ -341,7 +344,7 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
|
||||
/pkgs/top-level/agda-packages.nix @NixOS/agda
|
||||
/pkgs/development/libraries/agda @NixOS/agda
|
||||
/doc/languages-frameworks/agda.section.md @NixOS/agda
|
||||
/nixos/tests/agda.nix @NixOS/agda
|
||||
/nixos/tests/agda @NixOS/agda
|
||||
|
||||
# Idris
|
||||
/pkgs/development/idris-modules @Infinisil
|
||||
@@ -444,8 +447,8 @@ pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange
|
||||
/pkgs/os-specific/linux/zfs @adamcstephens @amarshall
|
||||
|
||||
# Zig
|
||||
/pkgs/development/compilers/zig @figsoda @RossComputerGuy
|
||||
/doc/hooks/zig.section.md @figsoda @RossComputerGuy
|
||||
/pkgs/development/compilers/zig @RossComputerGuy
|
||||
/doc/hooks/zig.section.md @RossComputerGuy
|
||||
|
||||
# Buildbot
|
||||
nixos/modules/services/continuous-integration/buildbot @Mic92 @zowoq
|
||||
|
||||
@@ -10,6 +10,53 @@ In order to ensure that the needed packages are generally available without buil
|
||||
|
||||
Run [`update-pinned.sh`](./update-pinned.sh) to update it.
|
||||
|
||||
## GitHub specific code
|
||||
|
||||
Some of the code is specific to GitHub.
|
||||
This code is currently spread out over multiple places and written in both Bash and JavaScript.
|
||||
The goal is to eventually have all GitHub specific code in `ci/github-script` and written in JavaScript via `actions/github-script`.
|
||||
A lot of code has already been migrated, but some Bash code still remains.
|
||||
New CI features need to be introduced in JavaScript, not Bash.
|
||||
|
||||
## Nixpkgs merge bot
|
||||
|
||||
The Nixpkgs merge bot empowers package maintainers by enabling them to merge PRs related to their own packages.
|
||||
It serves as a bridge for maintainers to quickly respond to user feedback, facilitating a more self-reliant approach.
|
||||
Especially when considering there are roughly 20 maintainers for every committer, this bot is a game-changer.
|
||||
|
||||
Following [RFC 172] the merge bot was originally implemented as a [python webapp](https://github.com/NixOS/nixpkgs-merge-bot), which has now been integrated into [`ci/github-script/bot.js`](./github-script/bot.js) and [`ci/github-script/merge.js`](./github-script/merge.js).
|
||||
|
||||
### Using the merge bot
|
||||
|
||||
To merge a PR, maintainers can simply comment:
|
||||
```gfm
|
||||
@NixOS/nixpkgs-merge-bot merge
|
||||
```
|
||||
|
||||
The next time the bot runs it will verify the below constraints, then (if satisfied) merge the PR.
|
||||
|
||||
The merge bot will reference [#306934](https://github.com/NixOS/nixpkgs/issues/306934) on PRs it merges successfully, [#305350](https://github.com/NixOS/nixpkgs/issues/305350) for unsuccessful attempts, or [#371492](https://github.com/NixOS/nixpkgs/issues/371492) if an error occurs.
|
||||
These issues effectively list PRs the merge bot has interacted with.
|
||||
|
||||
### Merge bot constraints
|
||||
|
||||
To ensure security and a focused utility, the bot adheres to specific limitations:
|
||||
|
||||
- The PR targets one of the [development branches](#branch-classification).
|
||||
- The PR only touches files of packages located under `pkgs/by-name/*`.
|
||||
- The PR is either:
|
||||
- approved by a [committer][@NixOS/nixpkgs-committers].
|
||||
- backported via label.
|
||||
- opened by a [committer][@NixOS/nixpkgs-committers].
|
||||
- opened by [@r-ryantm](https://nix-community.github.io/nixpkgs-update/r-ryantm/).
|
||||
- The user attempting to merge is a member of [@NixOS/nixpkgs-maintainers].
|
||||
- The user attempting to merge is a maintainer of all packages touched by the PR.
|
||||
|
||||
### Approving merge bot changes
|
||||
|
||||
Changes to the bot can usually be approved by the [@NixOS/nixpkgs-ci] team, as with other CI changes.
|
||||
However, additional acknowledgement from the [@NixOS/nixpkgs-core] team is required for changes to what the merge bot will merge, who is eligible to use the merge bot, or similar changes in scope.
|
||||
|
||||
## `ci/nixpkgs-vet.sh BASE_BRANCH [REPOSITORY]`
|
||||
|
||||
Runs the [`nixpkgs-vet` tool](https://github.com/NixOS/nixpkgs-vet) on the HEAD commit, closely matching what CI does.
|
||||
@@ -50,3 +97,10 @@ Some branches also have a version component, which is either `unstable` or `YY.M
|
||||
`ci/supportedBranches.js` is a script imported by CI to classify the base and head branches of a Pull Request.
|
||||
This classification will then be used to skip certain jobs.
|
||||
This script can also be run locally to print basic test cases.
|
||||
|
||||
|
||||
[@NixOS/nixpkgs-maintainers]: https://github.com/orgs/NixOS/teams/nixpkgs-maintainers
|
||||
[@NixOS/nixpkgs-committers]: https://github.com/orgs/NixOS/teams/nixpkgs-committers
|
||||
[@NixOS/nixpkgs-ci]: https://github.com/orgs/NixOS/teams/nixpkgs-ci
|
||||
[@NixOS/nixpkgs-core]: https://github.com/orgs/NixOS/teams/nixpkgs-core
|
||||
[RFC 172]: https://github.com/NixOS/rfcs/pull/172
|
||||
|
||||
+4
-1
@@ -49,6 +49,8 @@ let
|
||||
|
||||
programs.biome = {
|
||||
enable = true;
|
||||
# Disable settings validation because its inputs are liable to hash mismatch
|
||||
validate.enable = false;
|
||||
settings.formatter = {
|
||||
useEditorconfig = true;
|
||||
};
|
||||
@@ -136,6 +138,8 @@ let
|
||||
[ "--config=${config}" ];
|
||||
includes = [ "*.md" ];
|
||||
};
|
||||
|
||||
programs.zizmor.enable = true;
|
||||
};
|
||||
fs = pkgs.lib.fileset;
|
||||
nixFilesSrc = fs.toSource {
|
||||
@@ -152,7 +156,6 @@ let
|
||||
in
|
||||
rec {
|
||||
inherit pkgs fmt;
|
||||
requestReviews = pkgs.callPackage ./request-reviews { };
|
||||
codeownersValidator = pkgs.callPackage ./codeowners-validator { };
|
||||
|
||||
# FIXME(lf-): it might be useful to test other Nix implementations
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
lib ? import (path + "/lib"),
|
||||
trace ? false,
|
||||
path ? ./../..,
|
||||
extraNixpkgsConfigJson ? "{}",
|
||||
}:
|
||||
let
|
||||
|
||||
@@ -46,6 +47,7 @@ let
|
||||
|
||||
outpaths = import ./outpaths.nix {
|
||||
inherit path;
|
||||
extraNixpkgsConfig = builtins.fromJSON extraNixpkgsConfigJson;
|
||||
attrNamesOnly = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
myChunk,
|
||||
includeBroken,
|
||||
systems,
|
||||
extraNixpkgsConfigJson,
|
||||
}:
|
||||
|
||||
let
|
||||
@@ -17,6 +18,7 @@ let
|
||||
unfiltered = import ./outpaths.nix {
|
||||
inherit path;
|
||||
inherit includeBroken systems;
|
||||
extraNixpkgsConfig = builtins.fromJSON extraNixpkgsConfigJson;
|
||||
};
|
||||
|
||||
# Turns the unfiltered recursive attribute set into one that is limited to myAttrpaths
|
||||
|
||||
+55
-14
@@ -7,6 +7,7 @@
|
||||
python3,
|
||||
stdenvNoCC,
|
||||
makeWrapper,
|
||||
codeowners,
|
||||
}:
|
||||
let
|
||||
python = python3.withPackages (ps: [
|
||||
@@ -48,7 +49,7 @@ in
|
||||
{
|
||||
combinedDir,
|
||||
touchedFilesJson,
|
||||
githubAuthorId,
|
||||
ownersFile ? ../../OWNERS,
|
||||
}:
|
||||
let
|
||||
# Usually we expect a derivation, but when evaluating in multiple separate steps, we pass
|
||||
@@ -155,22 +156,19 @@ let
|
||||
# Only set this label when no other label with indication for staging has been set.
|
||||
# This avoids confusion whether to target staging or batch this with kernel updates.
|
||||
lib.last (lib.sort lib.lessThan (lib.attrValues rebuildCountByKernel)) <= 500;
|
||||
# Set the "11.by: package-maintainer" label to whether all packages directly
|
||||
# changed are maintained by the PR's author.
|
||||
"11.by: package-maintainer" =
|
||||
maintainers ? ${githubAuthorId}
|
||||
&& lib.all (lib.flip lib.elem maintainers.${githubAuthorId}) (
|
||||
lib.flatten (lib.attrValues maintainers)
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
maintainers = callPackage ./maintainers.nix { } {
|
||||
changedattrs = lib.attrNames (lib.groupBy (a: a.name) changedPackagePlatformAttrs);
|
||||
changedpathsjson = touchedFilesJson;
|
||||
removedattrs = lib.attrNames (lib.groupBy (a: a.name) removedPackagePlatformAttrs);
|
||||
};
|
||||
inherit
|
||||
(callPackage ./maintainers.nix { } {
|
||||
changedattrs = lib.attrNames (lib.groupBy (a: a.name) changedPackagePlatformAttrs);
|
||||
changedpathsjson = touchedFilesJson;
|
||||
removedattrs = lib.attrNames (lib.groupBy (a: a.name) removedPackagePlatformAttrs);
|
||||
})
|
||||
maintainers
|
||||
packages
|
||||
;
|
||||
in
|
||||
runCommand "compare"
|
||||
{
|
||||
@@ -178,9 +176,14 @@ runCommand "compare"
|
||||
nativeBuildInputs = map lib.getBin [
|
||||
jq
|
||||
cmp-stats
|
||||
codeowners
|
||||
];
|
||||
maintainers = builtins.toJSON maintainers;
|
||||
passAsFile = [ "maintainers" ];
|
||||
packages = builtins.toJSON packages;
|
||||
passAsFile = [
|
||||
"maintainers"
|
||||
"packages"
|
||||
];
|
||||
}
|
||||
''
|
||||
mkdir $out
|
||||
@@ -222,5 +225,43 @@ runCommand "compare"
|
||||
} >> $out/step-summary.md
|
||||
fi
|
||||
|
||||
jq -r '.[]' "${touchedFilesJson}" > ./touched-files
|
||||
readarray -t touchedFiles < ./touched-files
|
||||
echo "This PR touches ''${#touchedFiles[@]} files"
|
||||
|
||||
# TODO: Move ci/OWNERS to Nix and produce owners.json instead of owners.txt.
|
||||
touch "$out/owners.txt"
|
||||
for file in "''${touchedFiles[@]}"; do
|
||||
result=$(codeowners --file "${ownersFile}" "$file")
|
||||
|
||||
# Remove the file prefix and trim the surrounding spaces
|
||||
read -r owners <<< "''${result#"$file"}"
|
||||
if [[ "$owners" == "(unowned)" ]]; then
|
||||
echo "File $file is unowned"
|
||||
continue
|
||||
fi
|
||||
echo "File $file is owned by $owners"
|
||||
|
||||
# Split up multiple owners, separated by arbitrary amounts of spaces
|
||||
IFS=" " read -r -a entries <<< "$owners"
|
||||
|
||||
for entry in "''${entries[@]}"; do
|
||||
# GitHub technically also supports Emails as code owners,
|
||||
# but we can't easily support that, so let's not
|
||||
if [[ ! "$entry" =~ @(.*) ]]; then
|
||||
echo -e "\e[33mCodeowner \"$entry\" for file $file is not valid: Must start with \"@\"\e[0m"
|
||||
# Don't fail, because the PR for which this script runs can't fix it,
|
||||
# it has to be fixed in the base branch
|
||||
continue
|
||||
fi
|
||||
# The first regex match is everything after the @
|
||||
entry=''${BASH_REMATCH[1]}
|
||||
|
||||
echo "$entry" >> "$out/owners.txt"
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
cp "$maintainersPath" "$out/maintainers.json"
|
||||
cp "$packagesPath" "$out/packages.json"
|
||||
''
|
||||
|
||||
@@ -7,7 +7,13 @@
|
||||
removedattrs,
|
||||
}:
|
||||
let
|
||||
pkgs = import ../../.. { system = "x86_64-linux"; };
|
||||
pkgs = import ../../.. {
|
||||
system = "x86_64-linux";
|
||||
# We should never try to ping maintainers through package aliases, this can only lead to errors.
|
||||
# One example case is, where an attribute is a throw alias, but then re-introduced in a PR.
|
||||
# This would trigger the throw. By disabling aliases, we can fallback gracefully below.
|
||||
config.allowAliases = false;
|
||||
};
|
||||
|
||||
changedpaths = lib.importJSON changedpathsjson;
|
||||
|
||||
@@ -66,7 +72,8 @@ let
|
||||
(lib.unsafeGetAttrPos "src" drv)
|
||||
(lib.unsafeGetAttrPos "pname" drv)
|
||||
(lib.unsafeGetAttrPos "version" drv)
|
||||
|
||||
]
|
||||
++ lib.optionals (drv ? meta.position) [
|
||||
# Use ".meta.position" for cases when most of the package is
|
||||
# defined in a "common" section and the only place where
|
||||
# reference to the file with a derivation the "pos"
|
||||
@@ -76,7 +83,7 @@ let
|
||||
# "pkgs/tools/package-management/nix/default.nix:155"
|
||||
# We transform it to the following:
|
||||
# { file = "pkgs/tools/package-management/nix/default.nix"; }
|
||||
{ file = lib.head (lib.splitString ":" (drv.meta.position or "")); }
|
||||
{ file = lib.head (lib.splitString ":" drv.meta.position); }
|
||||
]
|
||||
)
|
||||
));
|
||||
@@ -98,9 +105,9 @@ let
|
||||
) attrsWithModifiedFiles;
|
||||
|
||||
byMaintainer = lib.groupBy (ping: toString ping.id) listToPing;
|
||||
|
||||
packagesPerMaintainer = lib.mapAttrs (
|
||||
maintainer: packages: map (pkg: pkg.packageName) packages
|
||||
) byMaintainer;
|
||||
in
|
||||
packagesPerMaintainer
|
||||
{
|
||||
maintainers = lib.mapAttrs (_: lib.catAttrs "packageName") byMaintainer;
|
||||
|
||||
packages = lib.catAttrs "packageName" listToPing;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ rec {
|
||||
splittedPath = lib.splitString "." packagePlatformPath;
|
||||
|
||||
# ["python312Packages" "numpy" "aarch64-linux"] -> ["python312Packages" "numpy"]
|
||||
packagePath = lib.sublist 0 (lib.length splittedPath - 1) splittedPath;
|
||||
packagePath = lib.init splittedPath;
|
||||
|
||||
# "python312Packages.numpy"
|
||||
name = lib.concatStringsSep "." packagePath;
|
||||
|
||||
+26
-19
@@ -19,6 +19,17 @@
|
||||
nix,
|
||||
}:
|
||||
|
||||
{
|
||||
# The number of attributes per chunk, see ./README.md for more info.
|
||||
chunkSize ? 5000,
|
||||
# Whether to just evaluate a single chunk for quick testing
|
||||
quickTest ? false,
|
||||
# Don't try to eval packages marked as broken.
|
||||
includeBroken ? false,
|
||||
# Customize the config used to evaluate nixpkgs
|
||||
extraNixpkgsConfig ? { },
|
||||
}:
|
||||
|
||||
let
|
||||
nixpkgs =
|
||||
with lib.fileset;
|
||||
@@ -66,6 +77,7 @@ let
|
||||
"$src/ci/eval/attrpaths.nix" \
|
||||
-A paths \
|
||||
-I "$src" \
|
||||
--argstr extraNixpkgsConfigJson ${lib.escapeShellArg (builtins.toJSON extraNixpkgsConfig)} \
|
||||
--option restrict-eval true \
|
||||
--option allow-import-from-derivation false \
|
||||
--option eval-system "${evalSystem}" > $out/paths.json
|
||||
@@ -79,13 +91,6 @@ let
|
||||
evalSystem ? builtins.currentSystem,
|
||||
# The path to the `paths.json` file from `attrpathsSuperset`
|
||||
attrpathFile ? "${attrpathsSuperset { inherit evalSystem; }}/paths.json",
|
||||
# The number of attributes per chunk, see ./README.md for more info.
|
||||
chunkSize ? 5000,
|
||||
|
||||
# Don't try to eval packages marked as broken.
|
||||
includeBroken ? false,
|
||||
# Whether to just evaluate a single chunk for quick testing
|
||||
quickTest ? false,
|
||||
}:
|
||||
let
|
||||
singleChunk = writeShellScript "single-chunk" ''
|
||||
@@ -111,12 +116,14 @@ let
|
||||
--option allow-import-from-derivation false \
|
||||
--query --available \
|
||||
--out-path --json \
|
||||
--meta \
|
||||
--show-trace \
|
||||
--arg chunkSize "$chunkSize" \
|
||||
--arg myChunk "$myChunk" \
|
||||
--arg attrpathFile "${attrpathFile}" \
|
||||
--arg systems "[ \"$system\" ]" \
|
||||
--arg includeBroken ${lib.boolToString includeBroken} \
|
||||
--argstr extraNixpkgsConfigJson ${lib.escapeShellArg (builtins.toJSON extraNixpkgsConfig)} \
|
||||
-I ${nixpkgs} \
|
||||
-I ${attrpathFile} \
|
||||
> "$outputDir/result/$myChunk" \
|
||||
@@ -204,6 +211,7 @@ let
|
||||
fi
|
||||
|
||||
cat "$chunkOutputDir"/result/* | jq -s 'add | map_values(.outputs)' > $out/${evalSystem}/paths.json
|
||||
cat "$chunkOutputDir"/result/* | jq -s 'add | map_values(.meta)' > $out/${evalSystem}/meta.json
|
||||
'';
|
||||
|
||||
diff = callPackage ./diff.nix { };
|
||||
@@ -232,6 +240,14 @@ let
|
||||
})
|
||||
' > $out/combined-diff.json
|
||||
|
||||
# Combine maintainers from all systems
|
||||
cat ${diffDir}/*/maintainers.json | jq -s '
|
||||
add | group_by(.package) | map({
|
||||
key: .[0].package,
|
||||
value: map(.maintainers) | flatten | unique
|
||||
}) | from_entries
|
||||
' > $out/maintainers.json
|
||||
|
||||
mkdir -p $out/before/stats
|
||||
for d in ${diffDir}/before/*; do
|
||||
cp -r "$d"/stats-by-chunk $out/before/stats/$(basename "$d")
|
||||
@@ -249,16 +265,13 @@ let
|
||||
{
|
||||
# Whether to evaluate on a specific set of systems, by default all are evaluated
|
||||
evalSystems ? if quickTest then [ "x86_64-linux" ] else supportedSystems,
|
||||
# The number of attributes per chunk, see ./README.md for more info.
|
||||
chunkSize ? 5000,
|
||||
quickTest ? false,
|
||||
}:
|
||||
symlinkJoin {
|
||||
name = "nixpkgs-eval-baseline";
|
||||
paths = map (
|
||||
evalSystem:
|
||||
singleSystem {
|
||||
inherit quickTest evalSystem chunkSize;
|
||||
inherit evalSystem;
|
||||
}
|
||||
) evalSystems;
|
||||
};
|
||||
@@ -267,13 +280,7 @@ let
|
||||
{
|
||||
# Whether to evaluate on a specific set of systems, by default all are evaluated
|
||||
evalSystems ? if quickTest then [ "x86_64-linux" ] else supportedSystems,
|
||||
# The number of attributes per chunk, see ./README.md for more info.
|
||||
chunkSize ? 5000,
|
||||
quickTest ? false,
|
||||
baseline,
|
||||
# Which maintainer should be considered the author?
|
||||
# Defaults to nixpkgs-ci which is not a maintainer and skips the check.
|
||||
githubAuthorId ? "nixpkgs-ci",
|
||||
# What files have been touched? Defaults to none; use the expression below to calculate it.
|
||||
# ```
|
||||
# git diff --name-only --merge-base master HEAD \
|
||||
@@ -290,14 +297,14 @@ let
|
||||
inherit evalSystem;
|
||||
beforeDir = baseline;
|
||||
afterDir = singleSystem {
|
||||
inherit quickTest evalSystem chunkSize;
|
||||
inherit evalSystem;
|
||||
};
|
||||
}
|
||||
) evalSystems;
|
||||
};
|
||||
comparisonReport = compare {
|
||||
combinedDir = combine { diffDir = diffs; };
|
||||
inherit touchedFilesJson githubAuthorId;
|
||||
inherit touchedFilesJson;
|
||||
};
|
||||
in
|
||||
comparisonReport;
|
||||
|
||||
+27
-2
@@ -76,11 +76,36 @@ let
|
||||
afterAttrs = getAttrs after;
|
||||
diffAttrs = diff beforeAttrs afterAttrs;
|
||||
diffJson = writeText "diff.json" (builtins.toJSON diffAttrs);
|
||||
|
||||
# The maintainer list is not diffed, but just taken as is, to provide a map
|
||||
# of maintainers on the target branch. A list of GitHub IDs is sufficient for
|
||||
# all our purposes and reduces size massively.
|
||||
meta = lib.importJSON "${after}/${evalSystem}/meta.json";
|
||||
maintainers = lib.pipe meta [
|
||||
(lib.mapAttrsToList (
|
||||
k: v: {
|
||||
# splits off the platform suffix
|
||||
package = lib.pipe k [
|
||||
(lib.splitString ".")
|
||||
lib.init
|
||||
(lib.concatStringsSep ".")
|
||||
];
|
||||
maintainers = map (m: m.githubId) v.maintainers or [ ];
|
||||
}
|
||||
))
|
||||
# Some paths don't have a platform suffix, those will appear with an empty package here.
|
||||
(lib.filter ({ package, maintainers }: package != "" && maintainers != [ ]))
|
||||
];
|
||||
maintainersJson = writeText "maintainers.json" (builtins.toJSON maintainers);
|
||||
in
|
||||
runCommand "diff" { } ''
|
||||
mkdir -p $out/${evalSystem}
|
||||
|
||||
cp -r ${before} $out/before
|
||||
cp -r ${after} $out/after
|
||||
cp -r --no-preserve=mode ${before} $out/before
|
||||
cp -r --no-preserve=mode ${after} $out/after
|
||||
# JSON files will be processed above explicitly, so avoid copying over
|
||||
# the source files to keep the artifacts smaller.
|
||||
find $out/before $out/after -iname '*.json' -delete
|
||||
cp ${diffJson} $out/${evalSystem}/diff.json
|
||||
cp ${maintainersJson} $out/${evalSystem}/maintainers.json
|
||||
''
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
# Set this to `null` to build for builtins.currentSystem only
|
||||
systems ? builtins.fromJSON (builtins.readFile ../supportedSystems.json),
|
||||
|
||||
# Customize the config used to evaluate nixpkgs
|
||||
extraNixpkgsConfig ? { },
|
||||
}:
|
||||
let
|
||||
lib = import (path + "/lib");
|
||||
@@ -55,7 +58,8 @@ let
|
||||
true;
|
||||
|
||||
inHydra = true;
|
||||
};
|
||||
}
|
||||
// extraNixpkgsConfig;
|
||||
|
||||
__allowFileset = false;
|
||||
};
|
||||
|
||||
@@ -3,10 +3,142 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
const { DefaultArtifactClient } = require('@actions/artifact')
|
||||
const { readFile, writeFile } = require('node:fs/promises')
|
||||
const withRateLimit = require('./withRateLimit.js')
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
const { handleMerge } = require('./merge.js')
|
||||
const { handleReviewers } = require('./reviewers.js')
|
||||
|
||||
const artifactClient = new DefaultArtifactClient()
|
||||
|
||||
async function handlePullRequest({ item, stats }) {
|
||||
async function downloadMaintainerMap(branch) {
|
||||
let run
|
||||
|
||||
const commits = (
|
||||
await github.rest.repos.listCommits({
|
||||
...context.repo,
|
||||
sha: branch,
|
||||
// We look at 10 commits to find a maintainer map, but this is an arbitrary number. The
|
||||
// head commit might not have a map, if the queue was bypassed to merge it. This happens
|
||||
// frequently on staging-esque branches. The branch with the highest chance of getting
|
||||
// 10 consecutive bypassing commits is the stable staging-next branch. Luckily, this
|
||||
// also means that the number of PRs open towards that branch is very low, so falling
|
||||
// back to slightly imprecise maintainer data from master only has a marginal effect.
|
||||
per_page: 10,
|
||||
})
|
||||
).data
|
||||
|
||||
for (const commit of commits) {
|
||||
const run = (
|
||||
await github.rest.actions.listWorkflowRuns({
|
||||
...context.repo,
|
||||
workflow_id: 'merge-group.yml',
|
||||
status: 'success',
|
||||
exclude_pull_requests: true,
|
||||
per_page: 1,
|
||||
head_sha: commit.sha,
|
||||
})
|
||||
).data.workflow_runs[0]
|
||||
if (!run) continue
|
||||
|
||||
const artifact = (
|
||||
await github.rest.actions.listWorkflowRunArtifacts({
|
||||
...context.repo,
|
||||
run_id: run.id,
|
||||
name: 'maintainers',
|
||||
})
|
||||
).data.artifacts[0]
|
||||
if (!artifact) continue
|
||||
|
||||
await artifactClient.downloadArtifact(artifact.id, {
|
||||
findBy: {
|
||||
repositoryName: context.repo.repo,
|
||||
repositoryOwner: context.repo.owner,
|
||||
token: core.getInput('github-token'),
|
||||
},
|
||||
path: path.resolve(path.join('branches', branch)),
|
||||
expectedHash: artifact.digest,
|
||||
})
|
||||
|
||||
return JSON.parse(
|
||||
await readFile(
|
||||
path.resolve(path.join('branches', branch, 'maintainers.json')),
|
||||
'utf-8',
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// We get here when none of the 10 commits we looked at contained a maintainer map.
|
||||
// For the master branch, we don't have any fallback options, so we error out.
|
||||
// For other branches, we select a suitable fallback below.
|
||||
if (branch === 'master') throw new Error('No maintainer map found.')
|
||||
|
||||
const { stable, version } = classify(branch)
|
||||
|
||||
const release = `release-${version}`
|
||||
if (stable && branch !== release) {
|
||||
// Only fallback to the release branch from *other* stable branches.
|
||||
// Explicitly avoids infinite recursion.
|
||||
return await getMaintainerMap(release)
|
||||
} else {
|
||||
// Falling back to master as last resort.
|
||||
// This can either be the case for unstable staging-esque or wip branches,
|
||||
// or for the primary stable branch (release-XX.YY).
|
||||
return await getMaintainerMap('master')
|
||||
}
|
||||
}
|
||||
|
||||
// Simple cache for maintainer maps to avoid downloading the same artifacts
|
||||
// over and over again. Ultimately returns a promise, so the result must be
|
||||
// awaited for.
|
||||
const maintainerMaps = {}
|
||||
function getMaintainerMap(branch) {
|
||||
if (!maintainerMaps[branch]) {
|
||||
maintainerMaps[branch] = downloadMaintainerMap(branch)
|
||||
}
|
||||
return maintainerMaps[branch]
|
||||
}
|
||||
|
||||
// Caching the list of team members saves API requests when running the bot on the schedule and
|
||||
// processing many PRs at once.
|
||||
const members = {}
|
||||
function getTeamMembers(team_slug) {
|
||||
if (context.eventName === 'pull_request') {
|
||||
// We have no chance of getting a token in the pull_request context with the right
|
||||
// permissions to access the members endpoint below. Thus, we're pretending to have
|
||||
// no members. This is OK; because this is only for the Test workflow, not for
|
||||
// real use.
|
||||
return []
|
||||
}
|
||||
|
||||
if (!members[team_slug]) {
|
||||
members[team_slug] = github.paginate(github.rest.teams.listMembersInOrg, {
|
||||
org: context.repo.owner,
|
||||
team_slug,
|
||||
per_page: 100,
|
||||
})
|
||||
}
|
||||
|
||||
return members[team_slug]
|
||||
}
|
||||
|
||||
// Caching users saves API requests when running the bot on the schedule and processing
|
||||
// many PRs at once. It also helps to encapsulate the special logic we need, because
|
||||
// actions/github doesn't support that endpoint fully, yet.
|
||||
const users = {}
|
||||
function getUser(id) {
|
||||
if (!users[id]) {
|
||||
users[id] = github
|
||||
.request({
|
||||
method: 'GET',
|
||||
url: '/user/{id}',
|
||||
id,
|
||||
})
|
||||
.then((resp) => resp.data)
|
||||
}
|
||||
|
||||
return users[id]
|
||||
}
|
||||
|
||||
async function handlePullRequest({ item, stats, events }) {
|
||||
const log = (k, v) => core.info(`PR #${item.number} - ${k}: ${v}`)
|
||||
|
||||
const pull_number = item.number
|
||||
@@ -20,6 +152,21 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
})
|
||||
).data
|
||||
|
||||
const maintainers = await getMaintainerMap(pull_request.base.ref)
|
||||
|
||||
const merge_bot_eligible = await handleMerge({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
log,
|
||||
dry,
|
||||
pull_request,
|
||||
events,
|
||||
maintainers,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
})
|
||||
|
||||
// When the same change has already been merged to the target branch, a PR will still be
|
||||
// open and display the same changes - but will not actually have any effect. This causes
|
||||
// strange CI behavior, because the diff of the merge-commit is empty, no rebuilds will
|
||||
@@ -63,10 +210,16 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const reviews = await github.paginate(github.rest.pulls.listReviews, {
|
||||
...context.repo,
|
||||
pull_number,
|
||||
})
|
||||
// Check for any human reviews other than GitHub actions and other GitHub apps.
|
||||
// Accounts could be deleted as well, so don't count them.
|
||||
const reviews = (
|
||||
await github.paginate(github.rest.pulls.listReviews, {
|
||||
...context.repo,
|
||||
pull_number,
|
||||
})
|
||||
).filter(
|
||||
(r) => r.user && !r.user.login.endsWith('[bot]') && r.user.type !== 'Bot',
|
||||
)
|
||||
|
||||
const approvals = new Set(
|
||||
reviews
|
||||
@@ -96,6 +249,7 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
// The second pass will then read the result from the first pass and set the label.
|
||||
'2.status: merge conflict':
|
||||
merge_commit_sha_valid && !pull_request.merge_commit_sha,
|
||||
'2.status: merge-bot eligible': merge_bot_eligible,
|
||||
'12.approvals: 1': approvals.size === 1,
|
||||
'12.approvals: 2': approvals.size === 2,
|
||||
'12.approvals: 3+': approvals.size >= 3,
|
||||
@@ -110,12 +264,24 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
(
|
||||
await github.rest.actions.listWorkflowRuns({
|
||||
...context.repo,
|
||||
workflow_id: 'pull-request-target.yml',
|
||||
event: 'pull_request_target',
|
||||
exclude_pull_requests: true,
|
||||
head_sha: pull_request.head.sha,
|
||||
})
|
||||
).data.workflow_runs[0] ??
|
||||
// TODO: Remove this after 2026-02-01, at which point all pr.yml artifacts will have expired.
|
||||
(
|
||||
await github.rest.actions.listWorkflowRuns({
|
||||
...context.repo,
|
||||
// In older PRs, we need pr.yml instead of pull-request-target.yml.
|
||||
workflow_id: 'pr.yml',
|
||||
event: 'pull_request_target',
|
||||
exclude_pull_requests: true,
|
||||
head_sha: pull_request.head.sha,
|
||||
})
|
||||
).data.workflow_runs[0] ?? {}
|
||||
).data.workflow_runs[0] ??
|
||||
{}
|
||||
|
||||
// Newer PRs might not have run Eval to completion, yet.
|
||||
// Older PRs might not have an eval.yml workflow, yet.
|
||||
@@ -123,13 +289,6 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
log('Last eval run', run_id ?? '<n/a>')
|
||||
|
||||
if (conclusion === 'success') {
|
||||
// Check for any human reviews other than GitHub actions and other GitHub apps.
|
||||
// Accounts could be deleted as well, so don't count them.
|
||||
const humanReviews = reviews.filter(
|
||||
(r) =>
|
||||
r.user && !r.user.login.endsWith('[bot]') && r.user.type !== 'Bot',
|
||||
)
|
||||
|
||||
Object.assign(prLabels, {
|
||||
// We only set this label if the latest eval run was successful, because if it was not, it
|
||||
// *could* have requested reviewers. We will let the PR author fix CI first, before "escalating"
|
||||
@@ -142,7 +301,7 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
'9.needs: reviewer':
|
||||
!pull_request.draft &&
|
||||
pull_request.requested_reviewers.length === 0 &&
|
||||
humanReviews.length === 0,
|
||||
reviews.length === 0,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -177,22 +336,78 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
expectedHash: artifact.digest,
|
||||
})
|
||||
|
||||
const maintainers = new Set(
|
||||
Object.keys(
|
||||
JSON.parse(
|
||||
await readFile(`${pull_number}/maintainers.json`, 'utf-8'),
|
||||
),
|
||||
).map((m) => Number.parseInt(m, 10)),
|
||||
)
|
||||
|
||||
const evalLabels = JSON.parse(
|
||||
await readFile(`${pull_number}/changed-paths.json`, 'utf-8'),
|
||||
).labels
|
||||
|
||||
// TODO: Get "changed packages" information from list of changed by-name files
|
||||
// in addition to just the Eval results, to make this work for these packages
|
||||
// when Eval results have expired as well.
|
||||
let packages
|
||||
try {
|
||||
packages = JSON.parse(
|
||||
await readFile(`${pull_number}/packages.json`, 'utf-8'),
|
||||
)
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') throw e
|
||||
// TODO: Remove this fallback code once all old artifacts without packages.json
|
||||
// have expired. This should be the case in ~ February 2026.
|
||||
packages = Array.from(
|
||||
new Set(
|
||||
Object.values(
|
||||
JSON.parse(
|
||||
await readFile(`${pull_number}/maintainers.json`, 'utf-8'),
|
||||
),
|
||||
).flat(1),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Object.assign(prLabels, evalLabels, {
|
||||
'12.approved-by: package-maintainer':
|
||||
maintainers.intersection(approvals).size > 0,
|
||||
'11.by: package-maintainer':
|
||||
Boolean(packages.length) &&
|
||||
packages.every((pkg) =>
|
||||
maintainers[pkg]?.includes(pull_request.user.id),
|
||||
),
|
||||
'12.approved-by: package-maintainer': packages.some((pkg) =>
|
||||
maintainers[pkg]?.some((m) => approvals.has(m)),
|
||||
),
|
||||
})
|
||||
|
||||
if (!pull_request.draft) {
|
||||
let owners = []
|
||||
try {
|
||||
// TODO: Create owner map similar to maintainer map.
|
||||
owners = (await readFile(`${pull_number}/owners.txt`, 'utf-8')).split(
|
||||
'\n',
|
||||
)
|
||||
} catch (e) {
|
||||
// Older artifacts don't have the owners.txt, yet.
|
||||
if (e.code !== 'ENOENT') throw e
|
||||
}
|
||||
|
||||
// We set this label earlier already, but the current PR state can be very different
|
||||
// after handleReviewers has requested reviews, so update it in this case to prevent
|
||||
// this label from flip-flopping.
|
||||
prLabels['9.needs: reviewer'] = await handleReviewers({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
log,
|
||||
dry,
|
||||
pull_request,
|
||||
reviews,
|
||||
// TODO: Use maintainer map instead of the artifact.
|
||||
maintainers: Object.keys(
|
||||
JSON.parse(
|
||||
await readFile(`${pull_number}/maintainers.json`, 'utf-8'),
|
||||
),
|
||||
).map((id) => parseInt(id)),
|
||||
owners,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return prLabels
|
||||
@@ -253,9 +468,21 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
|
||||
const itemLabels = {}
|
||||
|
||||
const events = await github.paginate(
|
||||
github.rest.issues.listEventsForTimeline,
|
||||
{
|
||||
...context.repo,
|
||||
issue_number,
|
||||
per_page: 100,
|
||||
},
|
||||
)
|
||||
|
||||
if (item.pull_request || context.payload.pull_request) {
|
||||
stats.prs++
|
||||
Object.assign(itemLabels, await handlePullRequest({ item, stats }))
|
||||
Object.assign(
|
||||
itemLabels,
|
||||
await handlePullRequest({ item, stats, events }),
|
||||
)
|
||||
} else {
|
||||
stats.issues++
|
||||
if (item.labels.some(({ name }) => name === '4.workflow: auto-close')) {
|
||||
@@ -267,13 +494,7 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
}
|
||||
|
||||
const latest_event_at = new Date(
|
||||
(
|
||||
await github.paginate(github.rest.issues.listEventsForTimeline, {
|
||||
...context.repo,
|
||||
issue_number,
|
||||
per_page: 100,
|
||||
})
|
||||
)
|
||||
events
|
||||
.filter(({ event }) =>
|
||||
[
|
||||
// These events are hand-picked from:
|
||||
@@ -335,7 +556,7 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
const hasChanges = Object.keys(after).some(
|
||||
(name) => (before[name] ?? false) !== after[name],
|
||||
)
|
||||
if (log('Has changes', hasChanges, !hasChanges)) return
|
||||
if (log('Has label changes', hasChanges, !hasChanges)) return
|
||||
|
||||
// Skipping labeling on a pull_request event, because we have no privileges.
|
||||
const labels = Object.entries(after)
|
||||
@@ -353,14 +574,21 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
}
|
||||
}
|
||||
|
||||
await withRateLimit({ github, core }, async (stats) => {
|
||||
// Controls level of parallelism. Applies to both the number of concurrent requests
|
||||
// as well as the number of concurrent workers going through the list of PRs.
|
||||
// We'll only boost concurrency when we're running many PRs in parallel on a schedule,
|
||||
// but not for single PRs. This avoids things going wild, when we accidentally make
|
||||
// too many API requests on treewides.
|
||||
const maxConcurrent = context.payload.pull_request ? 1 : 20
|
||||
|
||||
await withRateLimit({ github, core, maxConcurrent }, async (stats) => {
|
||||
if (context.payload.pull_request) {
|
||||
await handle({ item: context.payload.pull_request, stats })
|
||||
} else {
|
||||
const lastRun = (
|
||||
await github.rest.actions.listWorkflowRuns({
|
||||
...context.repo,
|
||||
workflow_id: 'labels.yml',
|
||||
workflow_id: 'bot.yml',
|
||||
event: 'schedule',
|
||||
status: 'success',
|
||||
exclude_pull_requests: true,
|
||||
@@ -482,11 +710,23 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
arr.findIndex((firstItem) => firstItem.number === thisItem.number),
|
||||
)
|
||||
|
||||
;(await Promise.allSettled(items.map((item) => handle({ item, stats }))))
|
||||
.filter(({ status }) => status === 'rejected')
|
||||
.map(({ reason }) =>
|
||||
core.setFailed(`${reason.message}\n${reason.cause.stack}`),
|
||||
)
|
||||
// Instead of handling all items in parallel we set up some workers to handle the queue
|
||||
// with more controlled parallelism. This avoids problems with `pull_request` fetched at
|
||||
// the beginning getting out of date towards the end, because it took the whole job 20
|
||||
// minutes or more to go through 100's of PRs.
|
||||
await Promise.all(
|
||||
Array.from({ length: maxConcurrent }, async () => {
|
||||
while (true) {
|
||||
const item = items.pop()
|
||||
if (!item) break
|
||||
try {
|
||||
await handle({ item, stats })
|
||||
} catch (e) {
|
||||
core.setFailed(`${e.message}\n${e.cause.stack}`)
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
const excludeTeams = [
|
||||
/^voters.*$/,
|
||||
/^nixpkgs-maintainers$/,
|
||||
/^nixpkgs-committers$/,
|
||||
]
|
||||
|
||||
module.exports = async ({ github, context, core, outFile }) => {
|
||||
const withRateLimit = require('./withRateLimit.js')
|
||||
const { writeFileSync } = require('node:fs')
|
||||
|
||||
const org = context.repo.owner
|
||||
|
||||
const result = {}
|
||||
|
||||
await withRateLimit({ github, core }, async () => {
|
||||
// Turn an Array of users into an Object, mapping user.login -> user.id
|
||||
function makeUserSet(users) {
|
||||
// Sort in-place and build result by mutation
|
||||
users.sort((a, b) => (a.login > b.login ? 1 : -1))
|
||||
|
||||
return users.reduce((acc, user) => {
|
||||
acc[user.login] = user.id
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
// Process a list of teams and append to the result variable
|
||||
async function processTeams(teams) {
|
||||
for (const team of teams) {
|
||||
core.notice(`Processing team ${team.slug}`)
|
||||
if (!excludeTeams.some((regex) => team.slug.match(regex))) {
|
||||
const members = makeUserSet(
|
||||
await github.paginate(github.rest.teams.listMembersInOrg, {
|
||||
org,
|
||||
team_slug: team.slug,
|
||||
role: 'member',
|
||||
}),
|
||||
)
|
||||
const maintainers = makeUserSet(
|
||||
await github.paginate(github.rest.teams.listMembersInOrg, {
|
||||
org,
|
||||
team_slug: team.slug,
|
||||
role: 'maintainer',
|
||||
}),
|
||||
)
|
||||
result[team.slug] = {
|
||||
description: team.description,
|
||||
id: team.id,
|
||||
maintainers,
|
||||
members,
|
||||
name: team.name,
|
||||
}
|
||||
}
|
||||
await processTeams(
|
||||
await github.paginate(github.rest.teams.listChildInOrg, {
|
||||
org,
|
||||
team_slug: team.slug,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const teams = await github.paginate(github.rest.repos.listTeams, {
|
||||
...context.repo,
|
||||
})
|
||||
|
||||
await processTeams(teams)
|
||||
})
|
||||
|
||||
// Sort the teams by team name
|
||||
const sorted = Object.keys(result)
|
||||
.sort()
|
||||
.reduce((acc, key) => {
|
||||
acc[key] = result[key]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const json = `${JSON.stringify(sorted, null, 2)}\n`
|
||||
|
||||
if (outFile) {
|
||||
writeFileSync(outFile, json)
|
||||
} else {
|
||||
console.log(json)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
|
||||
function runChecklist({
|
||||
committers,
|
||||
events,
|
||||
files,
|
||||
pull_request,
|
||||
log,
|
||||
maintainers,
|
||||
user,
|
||||
userIsMaintainer,
|
||||
}) {
|
||||
const allByName = files.every(
|
||||
({ filename }) =>
|
||||
filename.startsWith('pkgs/by-name/') && filename.split('/').length > 4,
|
||||
)
|
||||
|
||||
const packages = files
|
||||
.filter(({ filename }) => filename.startsWith('pkgs/by-name/'))
|
||||
.map(({ filename }) => filename.split('/')[3])
|
||||
.filter(Boolean)
|
||||
|
||||
const eligible = !packages.length
|
||||
? new Set()
|
||||
: packages
|
||||
.map((pkg) => new Set(maintainers[pkg]))
|
||||
.reduce((acc, cur) => acc?.intersection(cur) ?? cur)
|
||||
|
||||
const approvals = new Set(
|
||||
events
|
||||
.filter(
|
||||
({ event, state, commit_id }) =>
|
||||
event === 'reviewed' &&
|
||||
state === 'approved' &&
|
||||
// Only approvals for the current head SHA count, otherwise authors could push
|
||||
// bad code between the approval and the merge.
|
||||
commit_id === pull_request.head.sha,
|
||||
)
|
||||
.map(({ user }) => user?.id)
|
||||
// Some users have been deleted, so filter these out.
|
||||
.filter(Boolean),
|
||||
)
|
||||
|
||||
const checklist = {
|
||||
'PR targets a [development branch](https://github.com/NixOS/nixpkgs/blob/-/ci/README.md#branch-classification).':
|
||||
classify(pull_request.base.ref).type.includes('development'),
|
||||
'PR touches only files of packages in `pkgs/by-name/`.': allByName,
|
||||
'PR is at least one of:': {
|
||||
'Approved by a committer.': committers.intersection(approvals).size > 0,
|
||||
'Backported via label.':
|
||||
pull_request.user.login === 'nixpkgs-ci[bot]' &&
|
||||
pull_request.head.ref.startsWith('backport-'),
|
||||
'Opened by a committer.': committers.has(pull_request.user.id),
|
||||
'Opened by r-ryantm.': pull_request.user.login === 'r-ryantm',
|
||||
},
|
||||
}
|
||||
|
||||
if (user) {
|
||||
checklist[
|
||||
`${user.login} is a member of [@NixOS/nixpkgs-maintainers](https://github.com/orgs/NixOS/teams/nixpkgs-maintainers).`
|
||||
] = userIsMaintainer
|
||||
if (allByName) {
|
||||
// We can only determine the below, if all packages are in by-name, since
|
||||
// we can't reliably relate changed files to packages outside by-name.
|
||||
checklist[`${user.login} is a maintainer of all touched packages.`] =
|
||||
eligible.has(user.id)
|
||||
}
|
||||
} else {
|
||||
// This is only used when no user is passed, i.e. for labeling.
|
||||
checklist['PR has maintainers eligible to merge.'] = eligible.size > 0
|
||||
}
|
||||
|
||||
const result = Object.values(checklist).every((v) =>
|
||||
typeof v === 'boolean' ? v : Object.values(v).some(Boolean),
|
||||
)
|
||||
|
||||
log('checklist', JSON.stringify(checklist))
|
||||
log('eligible', JSON.stringify(Array.from(eligible)))
|
||||
log('result', result)
|
||||
|
||||
return {
|
||||
checklist,
|
||||
eligible,
|
||||
result,
|
||||
}
|
||||
}
|
||||
|
||||
// The merge command must be on a separate line and not within codeblocks or html comments.
|
||||
// Codeblocks can have any number of ` larger than 3 to open/close. We only look at code
|
||||
// blocks that are not indented, because the later regex wouldn't match those anyway.
|
||||
function hasMergeCommand(body) {
|
||||
return (body ?? '')
|
||||
.replace(/<!--.*?-->/gms, '')
|
||||
.replace(/(^`{3,})[^`].*?\1/gms, '')
|
||||
.match(/^@NixOS\/nixpkgs-merge-bot merge\s*$/m)
|
||||
}
|
||||
|
||||
async function handleMergeComment({ github, body, node_id, reaction }) {
|
||||
if (!hasMergeCommand(body)) return
|
||||
|
||||
await github.graphql(
|
||||
`mutation($node_id: ID!, $reaction: ReactionContent!) {
|
||||
addReaction(input: {
|
||||
content: $reaction,
|
||||
subjectId: $node_id
|
||||
})
|
||||
{ clientMutationId }
|
||||
}`,
|
||||
{ node_id, reaction },
|
||||
)
|
||||
}
|
||||
|
||||
async function handleMerge({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
log,
|
||||
dry,
|
||||
pull_request,
|
||||
events,
|
||||
maintainers,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
}) {
|
||||
const pull_number = pull_request.number
|
||||
|
||||
const committers = new Set(
|
||||
(await getTeamMembers('nixpkgs-committers')).map(({ id }) => id),
|
||||
)
|
||||
|
||||
const files = (
|
||||
await github.rest.pulls.listFiles({
|
||||
...context.repo,
|
||||
pull_number,
|
||||
per_page: 100,
|
||||
})
|
||||
).data
|
||||
|
||||
// Early exit to prevent treewides from using up a lot of API requests (and time!) to list
|
||||
// all the files in the pull request. For now, the merge-bot will not work when 100 or more
|
||||
// files are touched in a PR - which should be more than fine.
|
||||
// TODO: Find a more efficient way of downloading all the *names* of the touched files,
|
||||
// including an early exit when the first non-by-name file is found.
|
||||
if (files.length >= 100) return false
|
||||
|
||||
// Only look through comments *after* the latest (force) push.
|
||||
const lastPush = events.findLastIndex(
|
||||
({ event, sha, commit_id }) =>
|
||||
['committed', 'head_ref_force_pushed'].includes(event) &&
|
||||
(sha ?? commit_id) === pull_request.head.sha,
|
||||
)
|
||||
|
||||
const comments = events.slice(lastPush + 1).filter(
|
||||
({ event, body, user, node_id }) =>
|
||||
['commented', 'reviewed'].includes(event) &&
|
||||
hasMergeCommand(body) &&
|
||||
// Ignore comments where the user has been deleted already.
|
||||
user &&
|
||||
// Ignore comments which had already been responded to by the bot.
|
||||
(dry ||
|
||||
!events.some(
|
||||
({ event, body }) =>
|
||||
['commented'].includes(event) &&
|
||||
// We're only testing this hidden reference, but not the author of the comment.
|
||||
// We'll just assume that nobody creates comments with this marker on purpose.
|
||||
// Additionally checking the author is quite annoying for local debugging.
|
||||
body.match(new RegExp(`^<!-- comment: ${node_id} -->$`, 'm')),
|
||||
)),
|
||||
)
|
||||
|
||||
async function merge() {
|
||||
if (dry) {
|
||||
core.info(`Merging #${pull_number}... (dry)`)
|
||||
return 'Merge completed (dry)'
|
||||
}
|
||||
|
||||
// Using GraphQL mutations instead of the REST /merge endpoint, because the latter
|
||||
// doesn't work with Merge Queues. We now have merge queues enabled on all development
|
||||
// branches, so we don't need a fallback for regular merges.
|
||||
try {
|
||||
const resp = await github.graphql(
|
||||
`mutation($node_id: ID!, $sha: GitObjectID) {
|
||||
enqueuePullRequest(input: {
|
||||
expectedHeadOid: $sha,
|
||||
pullRequestId: $node_id
|
||||
})
|
||||
{
|
||||
clientMutationId,
|
||||
mergeQueueEntry { mergeQueue { url } }
|
||||
}
|
||||
}`,
|
||||
{ node_id: pull_request.node_id, sha: pull_request.head.sha },
|
||||
)
|
||||
return [
|
||||
`:heavy_check_mark: [Queued](${resp.enqueuePullRequest.mergeQueueEntry.mergeQueue.url}) for merge (#306934)`,
|
||||
]
|
||||
} catch (e) {
|
||||
log('Enqueing failed', e.response.errors[0].message)
|
||||
}
|
||||
|
||||
// If required status checks are not satisfied, yet, the above will fail. In this case
|
||||
// we can enable auto-merge. We could also only use auto-merge, but this often gets
|
||||
// stuck for no apparent reason.
|
||||
try {
|
||||
await github.graphql(
|
||||
`mutation($node_id: ID!, $sha: GitObjectID) {
|
||||
enablePullRequestAutoMerge(input: {
|
||||
expectedHeadOid: $sha,
|
||||
pullRequestId: $node_id
|
||||
})
|
||||
{ clientMutationId }
|
||||
}`,
|
||||
{ node_id: pull_request.node_id, sha: pull_request.head.sha },
|
||||
)
|
||||
return [
|
||||
`:heavy_check_mark: Enabled Auto Merge (#306934)`,
|
||||
'',
|
||||
'> [!TIP]',
|
||||
'> Sometimes GitHub gets stuck after enabling Auto Merge. In this case, leaving another approval should trigger the merge.',
|
||||
]
|
||||
} catch (e) {
|
||||
log('Auto Merge failed', e.response.errors[0].message)
|
||||
throw new Error(e.response.errors[0].message)
|
||||
}
|
||||
}
|
||||
|
||||
for (const comment of comments) {
|
||||
log('comment', comment.node_id)
|
||||
|
||||
async function react(reaction) {
|
||||
if (dry) {
|
||||
core.info(`Reaction ${reaction} on ${comment.node_id} (dry)`)
|
||||
return
|
||||
}
|
||||
|
||||
await handleMergeComment({
|
||||
github,
|
||||
body: comment.body,
|
||||
node_id: comment.node_id,
|
||||
reaction,
|
||||
})
|
||||
}
|
||||
|
||||
async function isMaintainer(username) {
|
||||
try {
|
||||
return (
|
||||
(
|
||||
await github.rest.teams.getMembershipForUserInOrg({
|
||||
org: context.repo.owner,
|
||||
team_slug: 'nixpkgs-maintainers',
|
||||
username,
|
||||
})
|
||||
).data.state === 'active'
|
||||
)
|
||||
} catch (e) {
|
||||
if (e.status === 404) return false
|
||||
else throw e
|
||||
}
|
||||
}
|
||||
|
||||
const { result, eligible, checklist } = runChecklist({
|
||||
committers,
|
||||
events,
|
||||
files,
|
||||
pull_request,
|
||||
log,
|
||||
maintainers,
|
||||
user: comment.user,
|
||||
userIsMaintainer: await isMaintainer(comment.user.login),
|
||||
})
|
||||
|
||||
const body = [
|
||||
`<!-- comment: ${comment.node_id} -->`,
|
||||
`@${comment.user.login} wants to merge this PR.`,
|
||||
'',
|
||||
'Requirements to merge this PR with `@NixOS/nixpkgs-merge-bot merge`:',
|
||||
...Object.entries(checklist).flatMap(([msg, res]) =>
|
||||
typeof res === 'boolean'
|
||||
? `- :${res ? 'white_check_mark' : 'x'}: ${msg}`
|
||||
: [
|
||||
`- :${Object.values(res).some(Boolean) ? 'white_check_mark' : 'x'}: ${msg}`,
|
||||
...Object.entries(res).map(
|
||||
([msg, res]) =>
|
||||
` - ${res ? ':white_check_mark:' : ':white_large_square:'} ${msg}`,
|
||||
),
|
||||
],
|
||||
),
|
||||
'',
|
||||
]
|
||||
|
||||
if (eligible.size > 0 && !eligible.has(comment.user.id)) {
|
||||
const users = await Promise.all(
|
||||
Array.from(eligible, async (id) => (await getUser(id)).login),
|
||||
)
|
||||
body.push(
|
||||
'> [!TIP]',
|
||||
'> Maintainers eligible to merge are:',
|
||||
...users.map((login) => `> - ${login}`),
|
||||
'',
|
||||
)
|
||||
}
|
||||
|
||||
if (result) {
|
||||
await react('ROCKET')
|
||||
try {
|
||||
body.push(...(await merge()))
|
||||
} catch (e) {
|
||||
// Remove the HTML comment with node_id reference to allow retrying this merge on the next run.
|
||||
body.shift()
|
||||
body.push(`:x: Merge failed with: ${e} (#371492)`)
|
||||
}
|
||||
} else {
|
||||
await react('THUMBS_DOWN')
|
||||
body.push(':x: Pull Request could not be merged (#305350)')
|
||||
}
|
||||
|
||||
if (dry) {
|
||||
core.info(body.join('\n'))
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
...context.repo,
|
||||
issue_number: pull_number,
|
||||
body: body.join('\n'),
|
||||
})
|
||||
}
|
||||
|
||||
if (result) break
|
||||
}
|
||||
|
||||
const { result } = runChecklist({
|
||||
committers,
|
||||
events,
|
||||
files,
|
||||
pull_request,
|
||||
log,
|
||||
maintainers,
|
||||
})
|
||||
|
||||
// Returns a boolean, which indicates whether the PR is merge-bot eligible in principle.
|
||||
// This is used to set the respective label in bot.js.
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
handleMerge,
|
||||
handleMergeComment,
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
async function handleReviewers({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
log,
|
||||
dry,
|
||||
pull_request,
|
||||
reviews,
|
||||
maintainers,
|
||||
owners,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
}) {
|
||||
const pull_number = pull_request.number
|
||||
|
||||
const requested_reviewers = new Set(
|
||||
pull_request.requested_reviewers.map(({ login }) => login),
|
||||
)
|
||||
log(
|
||||
'reviewers - requested_reviewers',
|
||||
Array.from(requested_reviewers).join(', '),
|
||||
)
|
||||
|
||||
const existing_reviewers = new Set(
|
||||
reviews.map(({ user }) => user?.login).filter(Boolean),
|
||||
)
|
||||
log(
|
||||
'reviewers - existing_reviewers',
|
||||
Array.from(existing_reviewers).join(', '),
|
||||
)
|
||||
|
||||
// Early sanity check, before we start making any API requests. The list of maintainers
|
||||
// does not have duplicates so the only user to filter out from this list would be the
|
||||
// PR author. Therefore, we check for a limit of 15+1, where 15 is the limit we check
|
||||
// further down again.
|
||||
// This is to protect against huge treewides consuming all our API requests for no
|
||||
// reason.
|
||||
if (maintainers.length > 16) {
|
||||
core.warning('Too many potential reviewers, skipping review requests.')
|
||||
// Return a boolean on whether the "needs: reviewers" label should be set.
|
||||
return existing_reviewers.size === 0 && requested_reviewers.size === 0
|
||||
}
|
||||
|
||||
const users = new Set([
|
||||
...(await Promise.all(
|
||||
maintainers.map(async (id) => (await getUser(id)).login),
|
||||
)),
|
||||
...owners.filter((handle) => handle && !handle.includes('/')),
|
||||
])
|
||||
log('reviewers - users', Array.from(users).join(', '))
|
||||
|
||||
const teams = new Set(
|
||||
owners
|
||||
.map((handle) => handle.split('/'))
|
||||
.filter(([org, slug]) => org === context.repo.owner && slug)
|
||||
.map(([, slug]) => slug),
|
||||
)
|
||||
log('reviewers - teams', Array.from(teams).join(', '))
|
||||
|
||||
const team_members = new Set(
|
||||
(await Promise.all(Array.from(teams, getTeamMembers)))
|
||||
.flat(1)
|
||||
.map(({ login }) => login),
|
||||
)
|
||||
log('reviewers - team_members', Array.from(team_members).join(', '))
|
||||
|
||||
const new_reviewers = users
|
||||
.union(team_members)
|
||||
// We can't request a review from the author.
|
||||
.difference(new Set([pull_request.user?.login]))
|
||||
log('reviewers - new_reviewers', Array.from(new_reviewers).join(', '))
|
||||
|
||||
// Filter users to repository collaborators. If they're not, they can't be requested
|
||||
// for review. In that case, they probably missed their invite to the maintainers team.
|
||||
const reviewers = (
|
||||
await Promise.all(
|
||||
Array.from(new_reviewers, async (username) => {
|
||||
// TODO: Restructure this file to only do the collaborator check for those users
|
||||
// who were not already part of a team. Being a member of a team makes them
|
||||
// collaborators by definition.
|
||||
try {
|
||||
await github.rest.repos.checkCollaborator({
|
||||
...context.repo,
|
||||
username,
|
||||
})
|
||||
return username
|
||||
} catch (e) {
|
||||
if (e.status !== 404) throw e
|
||||
core.warning(
|
||||
`PR #${pull_number}: User ${username} cannot be requested for review because they don't exist or are not a repository collaborator, ignoring. They probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>).`,
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
).filter(Boolean)
|
||||
log('reviewers - reviewers', reviewers.join(', '))
|
||||
|
||||
if (reviewers.length > 15) {
|
||||
core.warning(
|
||||
`Too many reviewers (${reviewers.join(', ')}), skipping review requests.`,
|
||||
)
|
||||
// Return a boolean on whether the "needs: reviewers" label should be set.
|
||||
return existing_reviewers.size === 0 && requested_reviewers.size === 0
|
||||
}
|
||||
|
||||
const non_requested_reviewers = new Set(reviewers)
|
||||
.difference(requested_reviewers)
|
||||
// We don't want to rerequest reviews from people who already reviewed.
|
||||
.difference(existing_reviewers)
|
||||
log(
|
||||
'reviewers - non_requested_reviewers',
|
||||
Array.from(non_requested_reviewers).join(', '),
|
||||
)
|
||||
|
||||
if (non_requested_reviewers.size === 0) {
|
||||
log('Has reviewer changes', 'false (skipped)')
|
||||
} else if (dry) {
|
||||
core.info(
|
||||
`Requesting reviewers for #${pull_number}: ${Array.from(non_requested_reviewers).join(', ')} (dry)`,
|
||||
)
|
||||
} else {
|
||||
// We had tried the "request all reviewers at once" thing in the past, but it didn't work out:
|
||||
// https://github.com/NixOS/nixpkgs/commit/034613f860fcd339bd2c20c8f6bc259a2f9dc034
|
||||
// If we're hitting API errors here again, we'll need to investigate - and possibly reverse
|
||||
// course.
|
||||
await github.rest.pulls.requestReviewers({
|
||||
...context.repo,
|
||||
pull_number,
|
||||
reviewers,
|
||||
})
|
||||
}
|
||||
|
||||
// Return a boolean on whether the "needs: reviewers" label should be set.
|
||||
return (
|
||||
non_requested_reviewers.size === 0 &&
|
||||
existing_reviewers.size === 0 &&
|
||||
requested_reviewers.size === 0
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
handleReviewers,
|
||||
}
|
||||
+15
-4
@@ -65,22 +65,33 @@ program
|
||||
})
|
||||
|
||||
program
|
||||
.command('labels')
|
||||
.description('Manage labels on pull requests.')
|
||||
.command('bot')
|
||||
.description('Run automation on pull requests and issues.')
|
||||
.argument('<owner>', 'Owner of the GitHub repository to label (Example: NixOS)')
|
||||
.argument('<repo>', 'Name of the GitHub repository to label (Example: nixpkgs)')
|
||||
.argument('[pr]', 'Number of the Pull Request to label')
|
||||
.option('--no-dry', 'Make actual modifications')
|
||||
.action(async (owner, repo, pr, options) => {
|
||||
const labels = (await import('./labels.js')).default
|
||||
const bot = (await import('./bot.js')).default
|
||||
const tmp = mkdtempSync(join(tmpdir(), 'github-script-'))
|
||||
try {
|
||||
process.env.GITHUB_WORKSPACE = tmp
|
||||
process.chdir(tmp)
|
||||
await run(labels, owner, repo, pr, options)
|
||||
await run(bot, owner, repo, pr, options)
|
||||
} finally {
|
||||
rmSync(tmp, { recursive: true })
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('get-teams')
|
||||
.description('Fetch the list of teams with GitHub and output it to a file')
|
||||
.argument('<owner>', 'Owner of the GitHub repository to label (Example: NixOS)')
|
||||
.argument('<repo>', 'Name of the GitHub repository to label (Example: nixpkgs)')
|
||||
.argument('[outFile]', 'Path to the output file (Example: github-teams.json). If not set, prints to stdout')
|
||||
.action(async (owner, repo, outFile, options) => {
|
||||
const getTeams = (await import('./get-teams.js')).default
|
||||
await run(getTeams, owner, repo, undefined, { ...options, outFile })
|
||||
})
|
||||
|
||||
await program.parse()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = async ({ github, core }, callback) => {
|
||||
module.exports = async ({ github, core, maxConcurrent = 1 }, callback) => {
|
||||
const Bottleneck = require('bottleneck')
|
||||
|
||||
const stats = {
|
||||
@@ -13,7 +13,7 @@ module.exports = async ({ github, core }, callback) => {
|
||||
// https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api
|
||||
const allLimits = new Bottleneck({
|
||||
// Avoid concurrent requests
|
||||
maxConcurrent: 1,
|
||||
maxConcurrent,
|
||||
// Will be updated with first `updateReservoir()` call below.
|
||||
reservoir: 0,
|
||||
})
|
||||
|
||||
+6
-6
@@ -9,9 +9,9 @@
|
||||
},
|
||||
"branch": "nixpkgs-unstable",
|
||||
"submodules": false,
|
||||
"revision": "e57b3b16ad8758fd681511a078f35c416a8cc939",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/e57b3b16ad8758fd681511a078f35c416a8cc939.tar.gz",
|
||||
"hash": "04zp6jjd4xr6jfps84p8yh5ym5962mii4825fn75lqk14sz4rq56"
|
||||
"revision": "12c1f0253aa9a54fdf8ec8aecaafada64a111e24",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/12c1f0253aa9a54fdf8ec8aecaafada64a111e24.tar.gz",
|
||||
"hash": "0zr033ybqjc5spwh7xnzkhbqgc6gh8waw6z76rpvadxckyqlfgiq"
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"type": "Git",
|
||||
@@ -22,9 +22,9 @@
|
||||
},
|
||||
"branch": "main",
|
||||
"submodules": false,
|
||||
"revision": "5eda4ee8121f97b218f7cc73f5172098d458f1d1",
|
||||
"url": "https://github.com/numtide/treefmt-nix/archive/5eda4ee8121f97b218f7cc73f5172098d458f1d1.tar.gz",
|
||||
"hash": "1vqns9hjhmbnhdq2xvcmdxng11jrmcn9lpk2ncfh1f969z9lj8y9"
|
||||
"revision": "4ef3dfdbb5ddfb9e39999a2f2b0c2637277859d4",
|
||||
"url": "https://github.com/numtide/treefmt-nix/archive/4ef3dfdbb5ddfb9e39999a2f2b0c2637277859d4.tar.gz",
|
||||
"hash": "0dhvpzcknsr2ybi3zz9mjggs93aqkfr24radvlw74y9620dziqw4"
|
||||
}
|
||||
},
|
||||
"version": 5
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
makeWrapper,
|
||||
coreutils,
|
||||
codeowners,
|
||||
jq,
|
||||
curl,
|
||||
github-cli,
|
||||
gitMinimal,
|
||||
}:
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "request-reviews";
|
||||
src = lib.fileset.toSource {
|
||||
root = ./.;
|
||||
fileset = lib.fileset.unions [
|
||||
./get-code-owners.sh
|
||||
./request-reviewers.sh
|
||||
./request-code-owner-reviews.sh
|
||||
];
|
||||
};
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
dontBuild = true;
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
for bin in *.sh; do
|
||||
mv "$bin" "$out/bin"
|
||||
wrapProgram "$out/bin/$bin" \
|
||||
--set PATH ${
|
||||
lib.makeBinPath [
|
||||
coreutils
|
||||
codeowners
|
||||
jq
|
||||
curl
|
||||
github-cli
|
||||
gitMinimal
|
||||
]
|
||||
}
|
||||
done
|
||||
'';
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Get the code owners of the files changed by a PR, returning one username per line
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
if (( "$#" < 4 )); then
|
||||
log "Usage: $0 GIT_REPO OWNERS_FILE BASE_REF HEAD_REF"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gitRepo=$1
|
||||
ownersFile=$2
|
||||
baseRef=$3
|
||||
headRef=$4
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' exit
|
||||
|
||||
git -C "$gitRepo" diff --name-only --merge-base "$baseRef" "$headRef" > "$tmp/touched-files"
|
||||
readarray -t touchedFiles < "$tmp/touched-files"
|
||||
log "This PR touches ${#touchedFiles[@]} files"
|
||||
|
||||
# Get the owners file from the base, because we don't want to allow PRs to
|
||||
# remove code owners to avoid pinging them
|
||||
git -C "$gitRepo" show "$baseRef":"$ownersFile" > "$tmp"/codeowners
|
||||
|
||||
# Associative array with the user as the key for easy de-duplication
|
||||
# Make sure to always lowercase keys to avoid duplicates with different casings
|
||||
declare -A users=()
|
||||
|
||||
for file in "${touchedFiles[@]}"; do
|
||||
result=$(codeowners --file "$tmp"/codeowners "$file")
|
||||
|
||||
# Remove the file prefix and trim the surrounding spaces
|
||||
read -r owners <<< "${result#"$file"}"
|
||||
if [[ "$owners" == "(unowned)" ]]; then
|
||||
log "File $file is unowned"
|
||||
continue
|
||||
fi
|
||||
log "File $file is owned by $owners"
|
||||
|
||||
# Split up multiple owners, separated by arbitrary amounts of spaces
|
||||
IFS=" " read -r -a entries <<< "$owners"
|
||||
|
||||
for entry in "${entries[@]}"; do
|
||||
# GitHub technically also supports Emails as code owners,
|
||||
# but we can't easily support that, so let's not
|
||||
if [[ ! "$entry" =~ @(.*) ]]; then
|
||||
warn -e "\e[33mCodeowner \"$entry\" for file $file is not valid: Must start with \"@\"\e[0m" >&2
|
||||
# Don't fail, because the PR for which this script runs can't fix it,
|
||||
# it has to be fixed in the base branch
|
||||
continue
|
||||
fi
|
||||
# The first regex match is everything after the @
|
||||
entry=${BASH_REMATCH[1]}
|
||||
|
||||
if [[ "$entry" =~ (.*)/(.*) ]]; then
|
||||
# Teams look like $org/$team
|
||||
org=${BASH_REMATCH[1]}
|
||||
team=${BASH_REMATCH[2]}
|
||||
|
||||
# Instead of requesting a review from the team itself,
|
||||
# we request reviews from the individual users.
|
||||
# This is because once somebody from a team reviewed the PR,
|
||||
# the API doesn't expose that the team was already requested for a review,
|
||||
# so we wouldn't be able to avoid rerequesting reviews
|
||||
# without saving some some extra state somewhere
|
||||
|
||||
# We could also consider implementing a more advanced heuristic
|
||||
# in the future that e.g. only pings one team member,
|
||||
# but escalates to somebody else if that member doesn't respond in time.
|
||||
gh api \
|
||||
--cache=1h \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/orgs/$org/teams/$team/members" \
|
||||
--jq '.[].login' > "$tmp/team-members"
|
||||
readarray -t members < "$tmp/team-members"
|
||||
log "Team $entry has these members: ${members[*]}"
|
||||
|
||||
for user in "${members[@]}"; do
|
||||
users[${user,,}]=
|
||||
done
|
||||
else
|
||||
# Everything else is a user
|
||||
users[${entry,,}]=
|
||||
fi
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
printf "%s\n" "${!users[@]}"
|
||||
@@ -1,60 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Requests reviews for a PR
|
||||
|
||||
set -euo pipefail
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' exit
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
|
||||
log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
if (( $# < 3 )); then
|
||||
log "Usage: $0 GITHUB_REPO PR_NUMBER OWNERS_FILE"
|
||||
exit 1
|
||||
fi
|
||||
baseRepo=$1
|
||||
prNumber=$2
|
||||
ownersFile=$3
|
||||
|
||||
log "Fetching PR info"
|
||||
prInfo=$(gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/$baseRepo/pulls/$prNumber")
|
||||
|
||||
baseBranch=$(jq -r .base.ref <<< "$prInfo")
|
||||
log "Base branch: $baseBranch"
|
||||
prRepo=$(jq -r .head.repo.full_name <<< "$prInfo")
|
||||
log "PR repo: $prRepo"
|
||||
prBranch=$(jq -r .head.ref <<< "$prInfo")
|
||||
log "PR branch: $prBranch"
|
||||
prAuthor=$(jq -r .user.login <<< "$prInfo")
|
||||
log "PR author: $prAuthor"
|
||||
|
||||
extraArgs=()
|
||||
if pwdRepo=$(git rev-parse --show-toplevel 2>/dev/null); then
|
||||
# Speedup for local runs
|
||||
extraArgs+=(--reference-if-able "$pwdRepo")
|
||||
fi
|
||||
|
||||
log "Fetching Nixpkgs commit history"
|
||||
# We only need the commit history, not the contents, so we can do a tree-less clone using tree:0
|
||||
# https://github.blog/open-source/git/get-up-to-speed-with-partial-clone-and-shallow-clone/#user-content-quick-summary
|
||||
git clone --bare --filter=tree:0 --no-tags --origin upstream "${extraArgs[@]}" https://github.com/"$baseRepo".git "$tmp"/nixpkgs.git
|
||||
|
||||
log "Fetching the PR commit history"
|
||||
# Fetch the PR
|
||||
git -C "$tmp/nixpkgs.git" remote add fork https://github.com/"$prRepo".git
|
||||
# This remote config is the same as --filter=tree:0 when cloning
|
||||
git -C "$tmp/nixpkgs.git" config remote.fork.partialclonefilter tree:0
|
||||
git -C "$tmp/nixpkgs.git" config remote.fork.promisor true
|
||||
|
||||
git -C "$tmp/nixpkgs.git" fetch --no-tags fork "$prBranch"
|
||||
headRef=$(git -C "$tmp/nixpkgs.git" rev-parse refs/remotes/fork/"$prBranch")
|
||||
|
||||
log "Requesting reviews from code owners"
|
||||
"$SCRIPT_DIR"/get-code-owners.sh "$tmp/nixpkgs.git" "$ownersFile" "$baseBranch" "$headRef" | \
|
||||
"$SCRIPT_DIR"/request-reviewers.sh "$baseRepo" "$prNumber" "$prAuthor"
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Request reviewers for a PR, reading line-separated usernames on stdin,
|
||||
# filtering for valid reviewers before using the API endpoint to request reviews:
|
||||
# https://docs.github.com/en/rest/pulls/review-requests?apiVersion=2022-11-28#request-reviewers-for-a-pull-request
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' exit
|
||||
|
||||
log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
effect() {
|
||||
if [[ -n "${DRY_MODE:-}" ]]; then
|
||||
log "Skipping in dry mode:" "${@@Q}"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
if (( "$#" < 3 )); then
|
||||
log "Usage: $0 BASE_REPO PR_NUMBER PR_AUTHOR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
baseRepo=$1
|
||||
prNumber=$2
|
||||
prAuthor=$3
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' exit
|
||||
|
||||
declare -A users=()
|
||||
while read -r handle && [[ -n "$handle" ]]; do
|
||||
users[${handle,,}]=
|
||||
done
|
||||
|
||||
# Cannot request a review from the author
|
||||
if [[ -v users[${prAuthor,,}] ]]; then
|
||||
log "One or more files are owned by the PR author, ignoring"
|
||||
unset 'users[${prAuthor,,}]'
|
||||
fi
|
||||
|
||||
gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/$baseRepo/pulls/$prNumber/reviews" \
|
||||
--jq '.[].user.login' > "$tmp/already-reviewed-by"
|
||||
|
||||
# And we don't want to rerequest reviews from people who already reviewed
|
||||
while read -r user; do
|
||||
if [[ -v users[${user,,}] ]]; then
|
||||
log "User $user is a potential reviewer, but has already left a review, ignoring"
|
||||
unset 'users[${user,,}]'
|
||||
fi
|
||||
done < "$tmp/already-reviewed-by"
|
||||
|
||||
for user in "${!users[@]}"; do
|
||||
if ! gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/$baseRepo/collaborators/$user" >&2; then
|
||||
log "User $user is not a repository collaborator, probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>), ignoring"
|
||||
unset 'users[$user]'
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${#users[@]}" -gt 10 ]]; then
|
||||
log "Too many reviewers (${!users[*]}), skipping review requests"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for user in "${!users[@]}"; do
|
||||
log "Requesting review from: $user"
|
||||
|
||||
if ! response=$(jq -n --arg user "$user" '{ reviewers: [ $user ] }' | \
|
||||
effect gh api \
|
||||
--method POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/$baseRepo/pulls/$prNumber/requested_reviewers" \
|
||||
--input -); then
|
||||
log "Failed to request review from $user: $response"
|
||||
fi
|
||||
done
|
||||
+1
-1
@@ -9,7 +9,7 @@ if missingFeatures != [ ] then
|
||||
This version of Nixpkgs requires an implementation of Nix with the following features:
|
||||
- ${builtins.concatStringsSep "\n- " missingFeatures}
|
||||
|
||||
Your are evaluating with Nix ${builtins.nixVersion or "(too old to know)"}, please upgrade:
|
||||
You are evaluating with Nix ${builtins.nixVersion or "(too old to know)"}, please upgrade:
|
||||
|
||||
- If you are running NixOS, `nixos-rebuild' can be used to upgrade your system.
|
||||
|
||||
|
||||
@@ -202,6 +202,10 @@ Similarly, if you encounter errors similar to `Error_Protocol ("certificate has
|
||||
|
||||
_Default value:_ `false`.
|
||||
|
||||
`meta` (Attribute Set)
|
||||
|
||||
: The `meta` attribute of the resulting derivation, as in `stdenv.mkDerivation`. Accepts `description`, `maintainers` and any other `meta` attributes.
|
||||
|
||||
`contents` **DEPRECATED**
|
||||
|
||||
: This attribute is deprecated, and users are encouraged to use `copyToRoot` instead.
|
||||
@@ -635,6 +639,10 @@ This allows the function to produce reproducible images.
|
||||
|
||||
_Default value:_ `false`.
|
||||
|
||||
`meta` (Attribute Set)
|
||||
|
||||
: The `meta` attribute of the resulting derivation, as in `stdenv.mkDerivation`. Accepts `description`, `maintainers` and any other `meta` attributes.
|
||||
|
||||
`passthru` (Attribute Set; _optional_)
|
||||
|
||||
: Use this to pass any attributes as [`passthru`](#chap-passthru) for the resulting derivation.
|
||||
|
||||
@@ -20,6 +20,7 @@ ghc.section.md
|
||||
gnome.section.md
|
||||
haredo.section.md
|
||||
installShellFiles.section.md
|
||||
julec.section.md
|
||||
just.section.md
|
||||
libiconv.section.md
|
||||
libxml2.section.md
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# julec.hook {#julec-hook}
|
||||
|
||||
[Jule](https://jule.dev) is an effective programming language designed to build efficient, fast, reliable and safe software while maintaining simplicity.
|
||||
|
||||
In Nixpkgs, `jule.hook` overrides the default build, check and install phases.
|
||||
|
||||
## Example code snippet {#julec-hook-example-code-snippet}
|
||||
|
||||
```nix
|
||||
{
|
||||
julec,
|
||||
clangStdenv,
|
||||
}:
|
||||
|
||||
clangStdenv.mkDerivation (finalAttrs: {
|
||||
# ...
|
||||
|
||||
nativeBuildInputs = [ julec.hook ];
|
||||
|
||||
# Customize filenames if needed
|
||||
JULE_SRC_DIR = "./src";
|
||||
JULE_OUT_DIR = "./bin";
|
||||
JULE_OUT_NAME = "hello-jule";
|
||||
JULE_TEST_DIR = "./tests";
|
||||
JULE_TEST_OUT_DIR = "./test-bin";
|
||||
JULE_TEST_OUT_NAME = "hello-jule-test";
|
||||
|
||||
# ...
|
||||
})
|
||||
```
|
||||
|
||||
## Variables controlling julec.hook {#julec-hook-variables}
|
||||
|
||||
### `JULE_SRC_DIR` {#julec-hook-variable-jule-src-dir}
|
||||
|
||||
Specifies the source directory containing `main.jule`.
|
||||
Default is `./src`.
|
||||
|
||||
### `JULE_OUT_DIR` {#julec-hook-variable-jule-out-dir}
|
||||
|
||||
Specifies the output directory for the compiled binary.
|
||||
Default is `./bin`.
|
||||
|
||||
### `JULE_OUT_NAME` {#julec-hook-variable-jule-out-name}
|
||||
|
||||
Specifies the name of the compiled binary.
|
||||
Default is `output`.
|
||||
|
||||
### `JULE_TEST_DIR` {#julec-hook-variable-jule-test-dir}
|
||||
|
||||
Specifies the directory containing test files.
|
||||
Default is the value of [`JULE_SRC_DIR`](#julec-hook-variable-jule-src-dir).
|
||||
|
||||
### `JULE_TEST_OUT_DIR` {#julec-hook-variable-jule-test-out-dir}
|
||||
|
||||
Specifies the output directory for compiled test binaries.
|
||||
Default is the value of [`JULE_OUT_DIR`](#julec-hook-variable-jule-out-dir).
|
||||
|
||||
### `JULE_TEST_OUT_NAME` {#julec-hook-variable-jule-test-out-name}
|
||||
|
||||
Specifies the name of the compiled test binary.
|
||||
Default is the value of [`JULE_OUT_NAME`](#julec-hook-variable-jule-out-name) with `-test` suffix.
|
||||
|
||||
### `dontUseJulecBuild` {#julec-hook-variable-dontusejulecbuild}
|
||||
|
||||
When set to true, doesn't use the predefined `julecBuildHook`.
|
||||
Default is false.
|
||||
|
||||
### `dontUseJulecCheck` {#julec-hook-variable-dontusejuleccheck}
|
||||
|
||||
When set to true, doesn't use the predefined `julecCheckHook`.
|
||||
Default is false.
|
||||
|
||||
### `dontUseJulecInstall` {#julec-hook-variable-dontusejulecinstall}
|
||||
|
||||
When set to true, doesn't use the predefined `julecInstallHook`.
|
||||
Default is false.
|
||||
@@ -26,23 +26,9 @@ All CUDA package sets include common CUDA packages like `libcublas`, `cudnn`, `t
|
||||
CUDA support is not enabled by default in Nixpkgs. To enable CUDA support, make sure Nixpkgs is imported with a configuration similar to the following:
|
||||
|
||||
```nix
|
||||
{ pkgs }:
|
||||
{
|
||||
allowUnfreePredicate =
|
||||
let
|
||||
ensureList = x: if builtins.isList x then x else [ x ];
|
||||
in
|
||||
package:
|
||||
builtins.all (
|
||||
license:
|
||||
license.free
|
||||
|| builtins.elem license.shortName [
|
||||
"CUDA EULA"
|
||||
"cuDNN EULA"
|
||||
"cuSPARSELt EULA"
|
||||
"cuTENSOR EULA"
|
||||
"NVidia OptiX EULA"
|
||||
]
|
||||
) (ensureList package.meta.license);
|
||||
allowUnfreePredicate = pkgs._cuda.lib.allowUnfreeCudaPredicate;
|
||||
cudaCapabilities = [ <target-architectures> ];
|
||||
cudaForwardCompat = true;
|
||||
cudaSupport = true;
|
||||
@@ -63,45 +49,23 @@ The `cudaForwardCompat` boolean configuration option determines whether PTX supp
|
||||
|
||||
### Modifying CUDA package sets {#cuda-modifying-cuda-package-sets}
|
||||
|
||||
CUDA package sets are created by using `callPackage` on `pkgs/top-level/cuda-packages.nix` with an explicit argument for `cudaMajorMinorVersion`, a string of the form `"<major>.<minor>"` (e.g., `"12.2"`), which informs the CUDA package set tooling which version of CUDA to use. The majority of the CUDA package set tooling is available through the top-level attribute set `_cuda`, a fixed-point defined outside the CUDA package sets.
|
||||
CUDA package sets are defined in `pkgs/top-level/cuda-packages.nix`. A CUDA package set is created by `callPackage`-ing `pkgs/development/cuda-modules/default.nix` with an attribute set `manifests`, containing NVIDIA manifests for each redistributable. The manifests for supported redistributables are available through `_cuda.manifests` and live in `pkgs/development/cuda-modules/_cuda/manifests`.
|
||||
|
||||
::: {.caution}
|
||||
The `cudaMajorMinorVersion` and `_cuda` attributes are not part of the CUDA package set fixed-point, but are instead provided by `callPackage` from the top-level in the construction of the package set. As such, they must be modified via the package set's `override` attribute.
|
||||
:::
|
||||
The majority of the CUDA package set tooling is available through the top-level attribute set `_cuda`, a fixed-point defined outside the CUDA package sets. As a fixed-point, `_cuda` should be modified through its `extend` attribute.
|
||||
|
||||
::: {.caution}
|
||||
As indicated by the underscore prefix, `_cuda` is an implementation detail and no guarantees are provided with respect to its stability or API. The `_cuda` attribute set is exposed only to ease creation or modification of CUDA package sets by expert, out-of-tree users.
|
||||
:::
|
||||
|
||||
Out-of-tree modifications of packages should use `overrideAttrs` to make any necessary modifications to the package expression.
|
||||
|
||||
::: {.note}
|
||||
The `_cuda` attribute set fixed-point should be modified through its `extend` attribute.
|
||||
The `_cuda` attribute set previously exposed `fixups`, an attribute set mapping from package name (`pname`) to a `callPackage`-compatible expression which provided to `overrideAttrs` on the result of a generic redistributable builder. This functionality has been removed in favor of including full package expressions for each redistributable package to ensure consistent attribute set membership across supported CUDA releases, platforms, and configurations.
|
||||
:::
|
||||
|
||||
The `_cuda.fixups` attribute set is a mapping from package name (`pname`) to a `callPackage`-compatible expression which will be provided to `overrideAttrs` on the result of our generic builder.
|
||||
|
||||
::: {.caution}
|
||||
Fixups are chosen from `_cuda.fixups` by `pname`. As a result, packages with multiple versions (e.g., `cudnn`, `cudnn_8_9`, etc.) all share a single fixup function (i.e., `_cuda.fixups.cudnn`, which is `pkgs/development/cuda-modules/fixups/cudnn.nix`).
|
||||
:::
|
||||
|
||||
As an example, you can change the fixup function used for cuDNN for only the default CUDA package set with this overlay:
|
||||
|
||||
```nix
|
||||
final: prev: {
|
||||
cudaPackages = prev.cudaPackages.override (prevArgs: {
|
||||
_cuda = prevArgs._cuda.extend (
|
||||
_: prevAttrs: {
|
||||
fixups = prevAttrs.fixups // {
|
||||
cudnn = <your-fixup-function>;
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Extending CUDA package sets {#cuda-extending-cuda-package-sets}
|
||||
|
||||
CUDA package sets are scopes and provide the usual `overrideScope` attribute for overriding package attributes (see the note about `cudaMajorMinorVersion` and `_cuda` in [Configuring CUDA package sets](#cuda-modifying-cuda-package-sets)).
|
||||
CUDA package sets are scopes and provide the usual `overrideScope` attribute for overriding package attributes (see the note about `_cuda` in [Configuring CUDA package sets](#cuda-modifying-cuda-package-sets)).
|
||||
|
||||
Inspired by `pythonPackagesExtensions`, the `_cuda.extensions` attribute is a list of extensions applied to every version of the CUDA package set, allowing modification of all versions of the CUDA package set without needing to know their names or explicitly enumerate and modify them. As an example, disabling `cuda_compat` across all CUDA package sets can be accomplished with this overlay:
|
||||
|
||||
@@ -115,6 +79,8 @@ final: prev: {
|
||||
}
|
||||
```
|
||||
|
||||
Redistributable packages are constructed by the `buildRedist` helper; see `pkgs/development/cuda-modules/buildRedist/default.nix` for the implementation.
|
||||
|
||||
### Using `cudaPackages` {#cuda-using-cudapackages}
|
||||
|
||||
::: {.caution}
|
||||
@@ -194,7 +160,7 @@ In `pkgsForCudaArch`, the `cudaForwardCompat` option is set to `false` because e
|
||||
::: {.caution}
|
||||
Not every version of CUDA supports every architecture!
|
||||
|
||||
To illustrate: support for Blackwell (e.g., `sm_100`) was added in CUDA 12.8. Assume our Nixpkgs' default CUDA package set is to CUDA 12.6. Then the Nixpkgs variant available through `pkgsForCudaArch.sm_100` is useless, since packages like `pkgsForCudaArch.sm_100.opencv` and `pkgsForCudaArch.sm_100.python3Packages.torch` will try to generate code for `sm_100`, an architecture unknown to CUDA 12.6. In that case, you should use `pkgsForCudaArch.sm_100.cudaPackages_12_8.pkgs` instead (see [Using cudaPackages.pkgs](#cuda-using-cudapackages-pkgs) for more details).
|
||||
To illustrate: support for Blackwell (e.g., `sm_100`) was added in CUDA 12.8. Assume our Nixpkgs' default CUDA package set is to CUDA 12.6. Then the Nixpkgs variant available through `pkgsForCudaArch.sm_100` is useless, since packages like `pkgsForCudaArch.sm_100.opencv` and `pkgsForCudaArch.sm_100.python3Packages.torch` will try to generate code for `sm_100`, an architecture unknown to CUDA 12.6. In that case, you should use `pkgsForCudaArch.sm_100.cudaPackages_12_8.pkgs` instead (see [Using `cudaPackages.pkgs`](#cuda-using-cudapackages-pkgs) for more details).
|
||||
:::
|
||||
|
||||
The `pkgsForCudaArch` attribute set makes it possible to access packages built for a specific architecture without needing to manually call `pkgs.extend` and supply a new `config`. As an example, `pkgsForCudaArch.sm_89.python3Packages.torch` provides PyTorch built for Ada Lovelace GPUs.
|
||||
@@ -306,82 +272,41 @@ This section of the docs is still very much in progress. Feedback is welcome in
|
||||
|
||||
### Package set maintenance {#cuda-package-set-maintenance}
|
||||
|
||||
The CUDA Toolkit is a suite of CUDA libraries and software meant to provide a development environment for CUDA-accelerated applications. Until the release of CUDA 11.4, NVIDIA had only made the CUDA Toolkit available as a multi-gigabyte runfile installer, which we provide through the [`cudaPackages.cudatoolkit`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages.cudatoolkit) attribute. From CUDA 11.4 and onwards, NVIDIA has also provided CUDA redistributables (“CUDA-redist”): individually packaged CUDA Toolkit components meant to facilitate redistribution and inclusion in downstream projects. These packages are available in the [`cudaPackages`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages) package set.
|
||||
The CUDA Toolkit is a suite of CUDA libraries and software meant to provide a development environment for CUDA-accelerated applications. Until the release of CUDA 11.4, NVIDIA had only made the CUDA Toolkit available as a multi-gigabyte runfile installer. From CUDA 11.4 and onwards, NVIDIA has also provided CUDA redistributables (“CUDA-redist”): individually packaged CUDA Toolkit components meant to facilitate redistribution and inclusion in downstream projects. These packages are available in the [`cudaPackages`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages) package set.
|
||||
|
||||
All new projects should use the CUDA redistributables available in [`cudaPackages`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages) in place of [`cudaPackages.cudatoolkit`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages.cudatoolkit), as they are much easier to maintain and update.
|
||||
While the monolithic CUDA Toolkit runfile installer is no longer provided, [`cudaPackages.cudatoolkit`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages.cudatoolkit) provides a `symlinkJoin`-ed approximation which common libraries. The use of [`cudaPackages.cudatoolkit`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages.cudatoolkit) is discouraged: all new projects should use the CUDA redistributables available in [`cudaPackages`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages) instead, as they are much easier to maintain and update.
|
||||
|
||||
#### Updating redistributables {#cuda-updating-redistributables}
|
||||
|
||||
1. Go to NVIDIA's index of CUDA redistributables: <https://developer.download.nvidia.com/compute/cuda/redist/>
|
||||
2. Make a note of the new version of CUDA available.
|
||||
3. Run
|
||||
Whenever a new version of a redistributable manifest is made available:
|
||||
|
||||
```bash
|
||||
nix run github:connorbaker/cuda-redist-find-features -- \
|
||||
download-manifests \
|
||||
--log-level DEBUG \
|
||||
--version <newest CUDA version> \
|
||||
https://developer.download.nvidia.com/compute/cuda/redist \
|
||||
./pkgs/development/cuda-modules/cuda/manifests
|
||||
```
|
||||
1. Check the corresponding README.md in `pkgs/development/cuda-modules/_cuda/manifests` for the URL to use when vendoring manifests.
|
||||
2. Update the manifest version used in construction of each CUDA package set in `pkgs/top-level/cuda-packages.nix`.
|
||||
3. Update package expressions in `pkgs/development/cuda-modules/packages`.
|
||||
|
||||
This will download a copy of the manifest for the new version of CUDA.
|
||||
4. Run
|
||||
Updating package expressions amounts to:
|
||||
|
||||
```bash
|
||||
nix run github:connorbaker/cuda-redist-find-features -- \
|
||||
process-manifests \
|
||||
--log-level DEBUG \
|
||||
--version <newest CUDA version> \
|
||||
https://developer.download.nvidia.com/compute/cuda/redist \
|
||||
./pkgs/development/cuda-modules/cuda/manifests
|
||||
```
|
||||
|
||||
This will generate a `redistrib_features_<newest CUDA version>.json` file in the same directory as the manifest.
|
||||
5. Update the `cudaVersionMap` attribute set in `pkgs/development/cuda-modules/cuda/extension.nix`.
|
||||
|
||||
#### Updating cuTensor {#cuda-updating-cutensor}
|
||||
|
||||
1. Repeat the steps present in [Updating CUDA redistributables](#cuda-updating-redistributables) with the following changes:
|
||||
- Use the index of cuTensor redistributables: <https://developer.download.nvidia.com/compute/cutensor/redist>
|
||||
- Use the newest version of cuTensor available instead of the newest version of CUDA.
|
||||
- Use `pkgs/development/cuda-modules/cutensor/manifests` instead of `pkgs/development/cuda-modules/cuda/manifests`.
|
||||
- Skip the step of updating `cudaVersionMap` in `pkgs/development/cuda-modules/cuda/extension.nix`.
|
||||
- adding fixes conditioned on newer releases, like added or removed dependencies
|
||||
- adding package expressions for new packages
|
||||
- updating `passthru.brokenConditions` and `passthru.badPlatformsConditions` with various constraints, (e.g., new releases removing support for various architectures)
|
||||
|
||||
#### Updating supported compilers and GPUs {#cuda-updating-supported-compilers-and-gpus}
|
||||
|
||||
1. Update `nvccCompatibilities` in `pkgs/development/cuda-modules/_cuda/data/nvcc.nix` to include the newest release of NVCC, as well as any newly supported host compilers.
|
||||
2. Update `cudaCapabilityToInfo` in `pkgs/development/cuda-modules/_cuda/data/cuda.nix` to include any new GPUs supported by the new release of CUDA.
|
||||
|
||||
#### Updating the CUDA Toolkit runfile installer {#cuda-updating-the-cuda-toolkit}
|
||||
|
||||
::: {.warning}
|
||||
While the CUDA Toolkit runfile installer is still available in Nixpkgs as the [`cudaPackages.cudatoolkit`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages.cudatoolkit) attribute, its use is not recommended, and it should be considered deprecated. Please migrate to the CUDA redistributables provided by the [`cudaPackages`](https://search.nixos.org/packages?channel=unstable&type=packages&query=cudaPackages) package set.
|
||||
|
||||
To ensure packages relying on the CUDA Toolkit runfile installer continue to build, it will continue to be updated until a migration path is available.
|
||||
:::
|
||||
|
||||
1. Go to NVIDIA's CUDA Toolkit runfile installer download page: <https://developer.nvidia.com/cuda-downloads>
|
||||
2. Select the appropriate OS, architecture, distribution, and version, and installer type.
|
||||
|
||||
- For example: Linux, x86_64, Ubuntu, 22.04, runfile (local)
|
||||
- NOTE: Typically, we use the Ubuntu runfile. It is unclear if the runfile for other distributions will work.
|
||||
|
||||
3. Take the link provided by the installer instructions on the webpage after selecting the installer type and get its hash by running:
|
||||
|
||||
```bash
|
||||
nix store prefetch-file --hash-type sha256 <link>
|
||||
```
|
||||
|
||||
4. Update `pkgs/development/cuda-modules/cudatoolkit/releases.nix` to include the release.
|
||||
1. Update `nvccCompatibilities` in `pkgs/development/cuda-modules/_cuda/db/bootstrap/nvcc.nix` to include the newest release of NVCC, as well as any newly supported host compilers.
|
||||
2. Update `cudaCapabilityToInfo` in `pkgs/development/cuda-modules/_cuda/db/bootstrap/cuda.nix` to include any new GPUs supported by the new release of CUDA.
|
||||
|
||||
#### Updating the CUDA package set {#cuda-updating-the-cuda-package-set}
|
||||
|
||||
1. Include a new `cudaPackages_<major>_<minor>` package set in `pkgs/top-level/all-packages.nix`.
|
||||
::: {.note}
|
||||
Changing the default CUDA package set should occur in a separate PR, allowing time for additional testing.
|
||||
:::
|
||||
|
||||
- NOTE: Changing the default CUDA package set should occur in a separate PR, allowing time for additional testing.
|
||||
::: {.warning}
|
||||
As described in [Using `cudaPackages.pkgs`](#cuda-using-cudapackages-pkgs), the current implementation fix for package set leakage involves creating a new instance for each non-default CUDA package sets. As such, We should limit the number of CUDA package sets which have `recurseForDerivations` set to true: `lib.recurseIntoAttrs` should only be applied to the default CUDA package set.
|
||||
:::
|
||||
|
||||
2. Successfully build the closure of the new package set, updating `pkgs/development/cuda-modules/cuda/overrides.nix` as needed. Below are some common failures:
|
||||
1. Include a new `cudaPackages_<major>_<minor>` package set in `pkgs/top-level/cuda-packages.nix` and inherit it in `pkgs/top-level/all-packages.nix`.
|
||||
2. Successfully build the closure of the new package set, updating expressions in `pkgs/development/cuda-modules/packages` as needed. Below are some common failures:
|
||||
|
||||
| Unable to ... | During ... | Reason | Solution | Note |
|
||||
| -------------- | -------------------------------- | ------------------------------------------------ | -------------------------- | ------------------------------------------------------------ |
|
||||
@@ -389,6 +314,13 @@ To ensure packages relying on the CUDA Toolkit runfile installer continue to bui
|
||||
| Find libraries | `configurePhase` | Missing dependency on a `dev` output | Add the missing dependency | The `dev` output typically contains CMake configuration files |
|
||||
| Find libraries | `buildPhase` or `patchelf` | Missing dependency on a `lib` or `static` output | Add the missing dependency | The `lib` or `static` output typically contains the libraries |
|
||||
|
||||
::: {.note}
|
||||
Two utility derivations ease testing updates to the package set:
|
||||
|
||||
- `cudaPackages.tests.redists-unpacked`: the `src` of each redistributable package unpacked and `symlinkJoin`-ed
|
||||
- `cudaPackages.tests.redists-installed`: each output of each redistributable package `symlinkJoin`-ed
|
||||
:::
|
||||
|
||||
Failure to run the resulting binary is typically the most challenging to diagnose, as it may involve a combination of the aforementioned issues. This type of failure typically occurs when a library attempts to load or open a library it depends on that it does not declare in its `DT_NEEDED` section. Try the following debugging steps:
|
||||
|
||||
1. First ensure that dependencies are patched with [`autoAddDriverRunpath`](https://search.nixos.org/packages?channel=unstable&type=packages&query=autoAddDriverRunpath).
|
||||
|
||||
@@ -129,7 +129,7 @@ The update script does the following:
|
||||
`fetchDeps` takes the following arguments:
|
||||
|
||||
- `attrPath` - the path to the package in nixpkgs (for example,
|
||||
`"javaPackages.openjfx22"`). Used for update script metadata.
|
||||
`"javaPackages.openjfx25"`). Used for update script metadata.
|
||||
- `pname` - an alias for `attrPath` for convenience. This is what you
|
||||
will generally use instead of `pkg` or `attrPath`.
|
||||
- `pkg` - the package to be used for fetching the dependencies. Defaults
|
||||
|
||||
@@ -1,5 +1,57 @@
|
||||
# Idris2 {#sec-idris2}
|
||||
|
||||
When developing using Idris2, by default the Idris compiler only has the minimal support libraries in its environment. This means that it will not attempt to read any libraries installed
|
||||
globally, for example in the `$HOME` directory. The recommended way to use Idris2 is to wrap the compiler in an environment that provides these packages per-project, for example in a
|
||||
devShell.
|
||||
|
||||
```nix
|
||||
{
|
||||
pkgs ? import <nixpkgs> { },
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
packages = [ (idris2.withPackages (p: [ p.idris2Api ])) ];
|
||||
}
|
||||
```
|
||||
or, alternatively if Nix is used to build the Idris2 project:
|
||||
|
||||
```nix
|
||||
{
|
||||
pkgs ? import <nixpkgs> { },
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
inputsFrom = [ (pkgs.callPackage ./package.nix { }) ];
|
||||
}
|
||||
```
|
||||
|
||||
By default, the Idris2 compiler provided by Nixpkgs does not read globally installed packages, nor can install them. Running `idris2 --install` will fail because the Nix store is
|
||||
a read-only file-system. If globally-installed packages are desired rather than the above strategy, one can set `IDRIS2_PREFIX`, or additional `IDRIS2_PACKAGE_PATH` entries
|
||||
for the compiler to read from. The following snippet will append `$HOME/.idris2` to `$IDRIS2_PACKAGE_PATH`, and if such a variable does not exist, create it. The Nixpkg's Idris2
|
||||
compiler append a few required libraries to this path variable, but any paths in the user's environment will be prefixed to those libraries.
|
||||
|
||||
```nix
|
||||
{
|
||||
pkgs ? import <nixpkgs> { },
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
packages = [ (idris2.withPackages (p: [ p.idris2Api ])) ];
|
||||
shellHook = ''
|
||||
IDRIS2_PACKAGE_PATH="''${IDRIS2_PACKAGE_PATH:+$IDRIS2_PACKAGE_PATH}$HOME/.idris2"
|
||||
'';
|
||||
}
|
||||
```
|
||||
The following snippet will allow the Idris2 to run `idris2 --install` successfully:
|
||||
```nix
|
||||
{
|
||||
pkgs ? import <nixpkgs> { },
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
packages = [ (idris2.withPackages (p: [ p.idris2Api ])) ];
|
||||
shellHook = ''
|
||||
IDRIS2_PREFIX="$HOME/.idris2"
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
In addition to exposing the Idris2 compiler itself, Nixpkgs exposes an `idris2Packages.buildIdris` helper to make it a bit more ergonomic to build Idris2 executables or libraries.
|
||||
|
||||
The `buildIdris` function takes an attribute set that defines at a minimum the `src` and `ipkgName` of the package to be built and any `idrisLibraries` required to build it. The `src` is the same source you're familiar with and the `ipkgName` must be the name of the `ipkg` file for the project (omitting the `.ipkg` extension). The `idrisLibraries` is a list of other library derivations created with `buildIdris`. You can optionally specify other derivation properties as needed but sensible defaults for `configurePhase`, `buildPhase`, and `installPhase` are provided.
|
||||
@@ -56,3 +108,20 @@ lspPkg.executable
|
||||
```
|
||||
|
||||
The above uses the default value of `withSource = false` for the `idris2Api` but could be modified to include that library's source by passing `(idris2Api { withSource = true; })` to `idrisLibraries` instead. `idris2Api` in the above derivation comes built in with `idris2Packages`. This library exposes many of the otherwise internal APIs of the Idris2 compiler.
|
||||
|
||||
The compiler package can be instantiated with packages on its `IDRIS2_PACKAGES` path from the `idris2Packages` set.
|
||||
|
||||
```nix
|
||||
{
|
||||
idris2,
|
||||
devShell,
|
||||
}:
|
||||
let
|
||||
myIdris = idris2.withPackages (p: [ p.idris2Api ]);
|
||||
in
|
||||
devShell {
|
||||
packages = [ myIdris ];
|
||||
}
|
||||
```
|
||||
|
||||
This search path is extended from the path already in the user's environment.
|
||||
|
||||
@@ -20,7 +20,7 @@ Each supported language or software ecosystem has its own package set named `<la
|
||||
$ nix repl '<nixpkgs>' -I nixpkgs=channel:nixpkgs-unstable
|
||||
nix-repl> javaPackages.<tab>
|
||||
javaPackages.compiler javaPackages.openjfx15 javaPackages.openjfx21 javaPackages.recurseForDerivations
|
||||
javaPackages.jogl_2_4_0 javaPackages.openjfx17 javaPackages.openjfx22
|
||||
javaPackages.jogl_2_4_0 javaPackages.openjfx17 javaPackages.openjfx25
|
||||
javaPackages.mavenfod javaPackages.openjfx19 javaPackages.override
|
||||
javaPackages.openjfx11 javaPackages.openjfx20 javaPackages.overrideDerivation
|
||||
```
|
||||
|
||||
@@ -557,6 +557,19 @@ are used in [`buildPythonPackage`](#buildpythonpackage-function).
|
||||
with the `pipInstallHook`.
|
||||
- `unittestCheckHook` will run tests with `python -m unittest discover`. See [example usage](#using-unittestcheckhook).
|
||||
|
||||
#### Overriding build helpers {#overriding-python-build-helpers}
|
||||
|
||||
Like many of the build helpers provided by Nixpkgs, Python build helpers typically provide a `<function>.override` attribute.
|
||||
It works like [`<pkg>.override`](#sec-pkg-override), and can be used to override the dependencies of each build helper.
|
||||
|
||||
This allows specifying the stdenv to be used by `buildPythonPackage` or `buildPythonApplication`. The default (`python.stdenv`) can be overridden as follows:
|
||||
|
||||
```nix
|
||||
buildPythonPackage.override { stdenv = customStdenv; } {
|
||||
# package attrs...
|
||||
}
|
||||
```
|
||||
|
||||
## User Guide {#user-guide}
|
||||
|
||||
### Using Python {#using-python}
|
||||
|
||||
@@ -273,6 +273,8 @@ To test that it works, you can then try using the gem with:
|
||||
NIX_PATH=nixpkgs=$PWD nix-shell -p "ruby.withPackages (ps: with ps; [ name-of-your-gem ])"
|
||||
```
|
||||
|
||||
To check the gems for any security vulnerabilities, run `./maintainers/scripts/audit-ruby-packages/audit-ruby-packages.bash`.
|
||||
|
||||
### Packaging applications {#packaging-applications}
|
||||
|
||||
A common task is to add a Ruby executable to Nixpkgs; popular examples would be `chef`, `jekyll`, or `sass`. A good way to do that is to use the `bundlerApp` function, that allows you to make a package that only exposes the listed executables. Otherwise, the package may cause conflicts through common paths like `bin/rake` or `bin/bundler` that aren't meant to be used.
|
||||
|
||||
@@ -235,7 +235,7 @@ runCommand "test.pdf" { nativeBuildInputs = [ latex_with_foiltex ]; } ''
|
||||
The font cache for LuaLaTeX is written to `$HOME`.
|
||||
Therefore, it is necessary to set `$HOME` to a writable path, e.g. [before using LuaLaTeX in nix derivations](https://github.com/NixOS/nixpkgs/issues/180639):
|
||||
```nix
|
||||
runCommandNoCC "lualatex-hello-world" { buildInputs = [ texliveFull ]; } ''
|
||||
runCommand "lualatex-hello-world" { buildInputs = [ texliveFull ]; } ''
|
||||
mkdir $out
|
||||
echo '\documentclass{article} \begin{document} Hello world \end{document}' > main.tex
|
||||
env HOME=$(mktemp -d) lualatex -interaction=nonstopmode -output-format=pdf -output-directory=$out ./main.tex
|
||||
|
||||
@@ -1,329 +0,0 @@
|
||||
Setting up a cross compiler with Nix
|
||||
|
||||
"Cross compilation" means compiling a program on one machine for another
|
||||
type of machine. A typical use of cross compilation is to compile programs
|
||||
for embedded devices. These devices often don't have the computing power
|
||||
and memory to compile programs natively.
|
||||
|
||||
For a fully working cross compiler the following are needed:
|
||||
|
||||
* cross binutils: assembler, archiver, linker, etcetera that understand
|
||||
the format of the target system
|
||||
|
||||
* cross compiler: a compiler that can generate binary code and object files
|
||||
for the target platform
|
||||
|
||||
* cross C library: a library to link object files with to create fully
|
||||
functional programs
|
||||
|
||||
Cross compilers are difficult to set up. A lot of people report that they
|
||||
cannot succeed in building a cross toolchain successfully. The answers
|
||||
usually consist of "download this pre-built toolchain", which is equally
|
||||
unhelpful.
|
||||
|
||||
A toolchain is set up in five steps:
|
||||
|
||||
1. build binutils to that can run on the host platform, but generate code
|
||||
for the target platform
|
||||
|
||||
2. build Linux kernel headers for the target platform
|
||||
|
||||
3. build a minimal C only version of GCC, that can run on the host platform
|
||||
and generate code for the target platform
|
||||
|
||||
4. build a C library for the target platform. This includes the dynamic
|
||||
linker, C library, etc.
|
||||
|
||||
5. build a full GCC
|
||||
|
||||
****
|
||||
NB:
|
||||
|
||||
Keep in mind that many programs are not very well suited for cross
|
||||
compilation. Either they are not intended to run on other platforms,
|
||||
because the code is highly platform specific, or the configuration process
|
||||
is not written with cross compilation in mind.
|
||||
|
||||
Nix will not solve these problems for you!
|
||||
***
|
||||
|
||||
This document describes to set up a cross compiler to generate code for
|
||||
arm-linux with uClibc and runs on i686-linux. The "stdenv" used is the
|
||||
default from the standard Nix packages collection.
|
||||
|
||||
Step 1: build binutils for arm-linux in the stdenv for i686-linux
|
||||
|
||||
---
|
||||
{stdenv, fetchurl, noSysDirs}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "binutils-2.16.1-arm";
|
||||
builder = ./builder.sh;
|
||||
src = fetchurl {
|
||||
url = "http://ftp.nluug.nl/gnu/binutils/binutils-2.16.1.tar.bz2";
|
||||
hash = "sha256-14pv+YKrL3NyFwbnv9MoWsZHgEZk5+pHhuZtAfkcVsU=";
|
||||
};
|
||||
inherit noSysDirs;
|
||||
configureFlags = [ "--target=arm-linux" ];
|
||||
}
|
||||
---
|
||||
|
||||
This will compile binutils that will run on i686-linux, but knows the
|
||||
format used by arm-linux.
|
||||
|
||||
Step 2: build kernel headers for the target architecture
|
||||
|
||||
default.nix for kernel-headers-arm:
|
||||
|
||||
---
|
||||
{stdenv, fetchurl}:
|
||||
|
||||
assert stdenv.buildPlatform.system == "i686-linux";
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "linux-headers-2.6.13.1-arm";
|
||||
builder = ./builder.sh;
|
||||
src = fetchurl {
|
||||
url = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.13.1.tar.bz2";
|
||||
hash = "sha256-qtICDjfiA1HxWBrHqtB5DCv9s9/HyznKV1C6IxCrHYs=";
|
||||
};
|
||||
}
|
||||
---
|
||||
|
||||
builder.sh for kernel-headers-arm:
|
||||
|
||||
---
|
||||
source $stdenv/setup
|
||||
|
||||
|
||||
buildPhase() {
|
||||
make include/linux/version.h
|
||||
}
|
||||
|
||||
buildPhase=buildPhase
|
||||
|
||||
|
||||
installPhase() {
|
||||
mkdir $out
|
||||
mkdir $out/include
|
||||
#cd $out/include
|
||||
#ln -s asm-arm asm
|
||||
make include/asm ARCH=arm
|
||||
cp -prvd include/linux include/asm include/asm-arm include/asm-generic $out/include
|
||||
echo -n > $out/include/linux/autoconf.h
|
||||
}
|
||||
|
||||
installPhase=installPhase
|
||||
|
||||
|
||||
genericBuild
|
||||
---
|
||||
|
||||
Step 3: build a minimal GCC
|
||||
|
||||
Extra/different parameters include the target platform and the kernel
|
||||
headers argument (this needs a major cleanup, as well as the name, it
|
||||
needs to be different!). Profiled compilers are disabled. The tarball
|
||||
used here is just gcc-core. For some reason it doesn't install nicely
|
||||
if the whole tarball is used (or is this some braino on my side? -- AH).
|
||||
|
||||
Only C is used, because for other languages (such as C++) extra libraries
|
||||
need to be compiled, for which libraries compiled for the target system
|
||||
are needed.
|
||||
|
||||
There is a bit of evilness going on. The cross compiled utilities need
|
||||
to be either copied to or be linked from the output tree of the compiler.
|
||||
(Is this really true? Back this up with arguments! -- AH)
|
||||
|
||||
Symbolic links are not something we want inside the Nix store.
|
||||
|
||||
---
|
||||
{ stdenv, fetchurl, noSysDirs
|
||||
, langC ? true, langCC ? true, langF77 ? false
|
||||
, profiledCompiler ? false
|
||||
, binutilsArm
|
||||
, kernelHeadersArm
|
||||
}:
|
||||
|
||||
assert langC;
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "gcc-4.0.2-arm";
|
||||
builder = ./builder.sh;
|
||||
src = fetchurl {
|
||||
url = "ftp://ftp.nluug.nl/pub/gnu/gcc/gcc-4.0.2/gcc-core-4.0.2.tar.bz2";
|
||||
hash = "sha256-LANmXRS7/fN2zF5JUJVd8OjNA5aCDsGLQKhSpxWA3Qk=";
|
||||
};
|
||||
# !!! apply only if noSysDirs is set
|
||||
patches = [./no-sys-dirs.patch ./gcc-inhibit.patch];
|
||||
inherit noSysDirs langC langCC langF77 profiledCompiler;
|
||||
buildInputs = [binutilsArm];
|
||||
inherit kernelHeadersArm binutilsArm;
|
||||
platform = "arm-linux";
|
||||
}
|
||||
---
|
||||
|
||||
The builder.sh for a cross-compiler. Note that the binutils are prefixed
|
||||
with the architecture name, so arm-linux-ld instead of ld, etc. This is
|
||||
necessary because when we cross-compile a lot of programs look for these
|
||||
tools with these specific names. The standard gcc-wrapper does not take this
|
||||
into account yet.
|
||||
|
||||
---
|
||||
source $stdenv/setup
|
||||
|
||||
|
||||
export NIX_FIXINC_DUMMY=$NIX_BUILD_TOP/dummy
|
||||
mkdir $NIX_FIXINC_DUMMY
|
||||
|
||||
|
||||
if test "$noSysDirs" = "1"; then
|
||||
|
||||
if test "$noSysDirs" = "1"; then
|
||||
# Figure out what extra flags to pass to the gcc compilers
|
||||
# being generated to make sure that they use our glibc.
|
||||
if test -e $NIX_CC/nix-support/orig-glibc; then
|
||||
glibc=$(cat $NIX_CC/nix-support/orig-glibc)
|
||||
# Ugh. Copied from gcc-wrapper/builder.sh. We can't just
|
||||
# source in $NIX_CC/nix-support/add-flags, since that
|
||||
# would cause *this* GCC to be linked against the
|
||||
# *previous* GCC. Need some more modularity there.
|
||||
extraCFlags="-B$glibc/lib -isystem $glibc/include"
|
||||
extraLDFlags="-B$glibc/lib -L$glibc/lib -Wl,-s \
|
||||
-Wl,-dynamic-linker,$glibc/lib/ld-linux.so.2"
|
||||
|
||||
# Oh, what a hack. I should be shot for this.
|
||||
# In stage 1, we should link against the previous GCC, but
|
||||
# not afterwards. Otherwise we retain a dependency.
|
||||
# However, ld-wrapper, which adds the linker flags for the
|
||||
# previous GCC, is also used in stage 2/3. We can prevent
|
||||
# it from adding them by NIX_GLIBC_FLAGS_SET, but then
|
||||
# gcc-wrapper will also not add them, thereby causing
|
||||
# stage 1 to fail. So we use a trick to only set the
|
||||
# flags in gcc-wrapper.
|
||||
hook=$(pwd)/ld-wrapper-hook
|
||||
echo "NIX_GLIBC_FLAGS_SET=1" > $hook
|
||||
export NIX_LD_WRAPPER_START_HOOK=$hook
|
||||
fi
|
||||
|
||||
export NIX_EXTRA_CFLAGS=$extraCFlags
|
||||
export NIX_EXTRA_LDFLAGS=$extraLDFlags
|
||||
export CFLAGS=$extraCFlags
|
||||
export CXXFLAGS=$extraCFlags
|
||||
export LDFLAGS=$extraLDFlags
|
||||
fi
|
||||
|
||||
else
|
||||
patches=""
|
||||
fi
|
||||
|
||||
|
||||
preConfigure=preConfigure
|
||||
preConfigure() {
|
||||
|
||||
# Determine the frontends to build.
|
||||
langs="c"
|
||||
if test -n "$langCC"; then
|
||||
langs="$langs,c++"
|
||||
fi
|
||||
if test -n "$langF77"; then
|
||||
langs="$langs,f77"
|
||||
fi
|
||||
|
||||
# Cross compiler evilness
|
||||
mkdir -p $out
|
||||
mkdir -p $out/arm-linux
|
||||
mkdir -p $out/arm-linux/bin
|
||||
ln -s $binutilsArm/arm-linux/bin/as $out/arm-linux/bin/as
|
||||
ln -s $binutilsArm/arm-linux/bin/ld $out/arm-linux/bin/ld
|
||||
ln -s $binutilsArm/arm-linux/bin/ar $out/arm-linux/bin/ar
|
||||
ln -s $binutilsArm/arm-linux/bin/ranlib $out/arm-linux/bin/ranlib
|
||||
|
||||
# Perform the build in a different directory.
|
||||
mkdir ../build
|
||||
cd ../build
|
||||
|
||||
configureScript=../$sourceRoot/configure
|
||||
configureFlags="--enable-languages=$langs --target=$platform --disable-threads --disable-libmudflap --disable-shared --with-headers=$kernelHeadersArm/include --disable-multilib"
|
||||
}
|
||||
|
||||
|
||||
postInstall=postInstall
|
||||
postInstall() {
|
||||
# Remove precompiled headers for now. They are very big and
|
||||
# probably not very useful yet.
|
||||
find $out/include -name "*.gch" -exec rm -rf {} \; -prune
|
||||
|
||||
# Remove `fixincl' to prevent a retained dependency on the
|
||||
# previous gcc.
|
||||
rm -rf $out/libexec/gcc/*/*/install-tools
|
||||
}
|
||||
|
||||
|
||||
#if test -z "$profiledCompiler"; then
|
||||
#makeFlags="bootstrap"
|
||||
#else
|
||||
#makeFlags="profiledbootstrap"
|
||||
#fi
|
||||
|
||||
genericBuild
|
||||
---
|
||||
|
||||
Step 4: build a C library for the target platform.
|
||||
|
||||
The previous steps are enough to compile a C library. In our case we take
|
||||
uClibc. It's intended to be a small sized replacement for glibc. It is widely
|
||||
used in embedded environments.
|
||||
|
||||
...
|
||||
|
||||
Step 5: Build a compiler to link with the newly built C library.
|
||||
|
||||
...
|
||||
|
||||
If we restrict the compiler to just C programs it is relatively easy,
|
||||
since we only need to wrap the GCC we built in the previous step with all
|
||||
the right tools and the right C library. Successfully compiled programs with
|
||||
this compiler and verified to be working on a HP Jornada 820 running Linux
|
||||
are "patch", "make" and "wget".
|
||||
|
||||
If we want to build C++ programs it gets a lot more difficult. GCC has a
|
||||
three step compilation process. In the first step a simple compiler, called
|
||||
xgcc, that can compile only C programs is built. With that compiler it
|
||||
compiles itself two more times: one time to build a full compiler, and another
|
||||
time to build a full compiler once again with the freshly built compiler from
|
||||
step 2. In the second and third step support for C++ is compiled, if this
|
||||
is configured.
|
||||
|
||||
One of the libraries that has to be built for C++ support step is libstdc++.
|
||||
This library uses xgcc, even when cross compiling, since libstdc++ has to be
|
||||
compiled for arm-linux.
|
||||
|
||||
One of the compiler flags that GCC uses for this compiler is called X_CFLAGS.
|
||||
This is used by the Nix build process to set the dynamic linker, glibc
|
||||
in the case of i686-linux using the default Nix packages collection.
|
||||
|
||||
Obviously, since we need to compile libstc++ for arm-linux with uClibc linking
|
||||
will not be done correctly: you can't link object files built for arm-linux
|
||||
with a glibc built for i686-linux.
|
||||
|
||||
Setting X_CFLAGS to use the uClibc libraries and dynamic linker will fail
|
||||
too. Earlier on in the build process these flags are used to compile important
|
||||
files like libgcc.a by the host system gcc, which does need to be linked
|
||||
to glibc. To make this work correctly you will need to carefully juggle
|
||||
with compilation flags. This is still work in progress for Nix.
|
||||
|
||||
|
||||
---
|
||||
|
||||
After successfully completing the whole toolchain you can start building
|
||||
packages with the newly built tools. To make everything build correctly
|
||||
you will need a stdenv for your target platform. Setting up this platform
|
||||
will take some effort. Right now there is a very experimental setup for
|
||||
arm-linux, which needs to be cleaned up before it is production ready.
|
||||
|
||||
Please note that many packages are not well suited for cross-compilation.
|
||||
Even though the package itself might be very well portable often the
|
||||
buildscripts are not. One thing that we have seen that causes frequent
|
||||
build failures is the use of the LD variable. This is often set to 'ld'
|
||||
and not $(CROSS)-ld.
|
||||
@@ -64,13 +64,15 @@ builders = ssh-ng://builder@linux-builder ${ARCH}-linux /etc/nix/builder_ed25519
|
||||
builders-use-substitutes = true
|
||||
```
|
||||
|
||||
To allow Nix to connect to a remote builder not running on port 22, you will also need to create a new file at `/etc/ssh/ssh_config.d/100-linux-builder.conf`:
|
||||
To allow Nix to connect to the default remote builder, which does not run on port 22, you will also need to create a new file at `/etc/ssh/ssh_config.d/100-linux-builder.conf`:
|
||||
|
||||
```
|
||||
Host linux-builder
|
||||
Hostname localhost
|
||||
HostKeyAlias linux-builder
|
||||
Port 31022
|
||||
User builder
|
||||
IdentityFile /etc/nix/builder_ed25519
|
||||
```
|
||||
|
||||
… and then restart your Nix daemon to apply the change:
|
||||
@@ -79,6 +81,8 @@ Host linux-builder
|
||||
$ sudo launchctl kickstart -k system/org.nixos.nix-daemon
|
||||
```
|
||||
|
||||
Note that if the builder is running and you have created the above ssh conf file, you can ssh into the builder with `sudo ssh builder@linux-builder`.
|
||||
|
||||
## Example flake usage {#sec-darwin-builder-example-flake}
|
||||
|
||||
```nix
|
||||
|
||||
@@ -5,7 +5,7 @@ The Nix expressions to build the Linux kernel are in [`pkgs/os-specific/linux/ke
|
||||
The function [`pkgs.buildLinux`](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/generic.nix) builds a kernel with [common configuration values](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/common-config.nix).
|
||||
This is the preferred option unless you have a very specific use case.
|
||||
Most kernels packaged in Nixpkgs are built that way, and it will also generate kernels suitable for NixOS.
|
||||
[`pkgs.linuxManualConfig`](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/manual-config.nix) requires a complete configuration to be passed.
|
||||
[`pkgs.linuxManualConfig`](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/build.nix) requires a complete configuration to be passed.
|
||||
It has fewer additional features than `pkgs.buildLinux`, which provides common configuration values and exposes the `features` attribute, as explained below.
|
||||
|
||||
Both functions have an argument `kernelPatches` which should be a list of `{name, patch, extraConfig}` attribute sets, where `name` is the name of the patch (which is included in the kernel’s `meta.description` attribute), `patch` is the patch itself (possibly compressed), and `extraConfig` (optional) is a string specifying extra options to be concatenated to the kernel configuration file (`.config`).
|
||||
@@ -75,7 +75,7 @@ pkgs.linuxPackages_custom {
|
||||
|
||||
:::
|
||||
|
||||
Additional attributes can be used with `linuxManualConfig` for further customisation instead of `linuxPackages_custom`. You're encouraged to read [the `pkgs.linuxManualConfig` source code](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/manual-config.nix) to understand how to use them.
|
||||
Additional attributes can be used with `linuxManualConfig` for further customisation instead of `linuxPackages_custom`. You're encouraged to read [the `pkgs.linuxManualConfig` source code](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/build.nix) to understand how to use them.
|
||||
|
||||
To edit the `.config` file for Linux X.Y from within Nix, proceed as follows:
|
||||
|
||||
|
||||
+59
-7
@@ -58,9 +58,8 @@
|
||||
],
|
||||
"cuda-updating-redistributables": [
|
||||
"index.html#cuda-updating-redistributables",
|
||||
"index.html#updating-cuda-redistributables"
|
||||
],
|
||||
"cuda-updating-cutensor": [
|
||||
"index.html#updating-cuda-redistributables",
|
||||
"index.html#updating-the-cuda-toolkit",
|
||||
"index.html#cuda-updating-cutensor",
|
||||
"index.html#updating-cutensor"
|
||||
],
|
||||
@@ -72,10 +71,6 @@
|
||||
"index.html#cuda-updating-the-cuda-package-set",
|
||||
"index.html#updating-the-cuda-package-set"
|
||||
],
|
||||
"cuda-updating-the-cuda-toolkit": [
|
||||
"index.html#cuda-updating-the-cuda-toolkit",
|
||||
"index.html#updating-the-cuda-toolkit"
|
||||
],
|
||||
"cuda-user-guide": [
|
||||
"index.html#cuda-user-guide"
|
||||
],
|
||||
@@ -124,6 +119,42 @@
|
||||
"inkscape-plugins": [
|
||||
"index.html#inkscape-plugins"
|
||||
],
|
||||
"julec-hook": [
|
||||
"index.html#julec-hook"
|
||||
],
|
||||
"julec-hook-example-code-snippet": [
|
||||
"index.html#julec-hook-example-code-snippet"
|
||||
],
|
||||
"julec-hook-variable-dontusejulecbuild": [
|
||||
"index.html#julec-hook-variable-dontusejulecbuild"
|
||||
],
|
||||
"julec-hook-variable-dontusejuleccheck": [
|
||||
"index.html#julec-hook-variable-dontusejuleccheck"
|
||||
],
|
||||
"julec-hook-variable-dontusejulecinstall": [
|
||||
"index.html#julec-hook-variable-dontusejulecinstall"
|
||||
],
|
||||
"julec-hook-variable-jule-out-dir": [
|
||||
"index.html#julec-hook-variable-jule-out-dir"
|
||||
],
|
||||
"julec-hook-variable-jule-out-name": [
|
||||
"index.html#julec-hook-variable-jule-out-name"
|
||||
],
|
||||
"julec-hook-variable-jule-src-dir": [
|
||||
"index.html#julec-hook-variable-jule-src-dir"
|
||||
],
|
||||
"julec-hook-variable-jule-test-dir": [
|
||||
"index.html#julec-hook-variable-jule-test-dir"
|
||||
],
|
||||
"julec-hook-variable-jule-test-out-dir": [
|
||||
"index.html#julec-hook-variable-jule-test-out-dir"
|
||||
],
|
||||
"julec-hook-variable-jule-test-out-name": [
|
||||
"index.html#julec-hook-variable-jule-test-out-name"
|
||||
],
|
||||
"julec-hook-variables": [
|
||||
"index.html#julec-hook-variables"
|
||||
],
|
||||
"major-ghc-deprecation": [
|
||||
"index.html#major-ghc-deprecation"
|
||||
],
|
||||
@@ -358,6 +389,24 @@
|
||||
"sec-pkg-overrideDerivation": [
|
||||
"index.html#sec-pkg-overrideDerivation"
|
||||
],
|
||||
"sec-platform-breakdown": [
|
||||
"index.html#sec-platform-breakdown"
|
||||
],
|
||||
"sec-platform-tier1": [
|
||||
"index.html#sec-platform-tier1"
|
||||
],
|
||||
"sec-platform-tier2": [
|
||||
"index.html#sec-platform-tier2"
|
||||
],
|
||||
"sec-platform-tier3": [
|
||||
"index.html#sec-platform-tier3"
|
||||
],
|
||||
"sec-platform-tier4-7": [
|
||||
"index.html#sec-platform-tier4-7"
|
||||
],
|
||||
"sec-platform-tiers": [
|
||||
"index.html#sec-platform-tiers"
|
||||
],
|
||||
"sec-lib-makeOverridable": [
|
||||
"index.html#sec-lib-makeOverridable"
|
||||
],
|
||||
@@ -3771,6 +3820,9 @@
|
||||
"buildpythonpackage-parameters": [
|
||||
"index.html#buildpythonpackage-parameters"
|
||||
],
|
||||
"overriding-python-build-helpers": [
|
||||
"index.html#overriding-python-build-helpers"
|
||||
],
|
||||
"overriding-python-packages": [
|
||||
"index.html#overriding-python-packages"
|
||||
],
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
|
||||
- Everything related to `bower` was removed, as it is deprecated and not used by anything in nixpkgs.
|
||||
|
||||
- `reaction` has been updated to version 2, which includes some breaking changes.
|
||||
For more information, [check the release article](https://blog.ppom.me/en-reaction-v2).
|
||||
|
||||
- `mealie` has been updated to 3.0.2: This update introduces breaking changes in some API endpoints (see the [release changelog](https://github.com/mealie-recipes/mealie/releases/tag/v3.0.0)).
|
||||
|
||||
- The `offrss` package was removed due to lack of upstream maintenance since 2012. It's recommended for users to migrate to another RSS reader
|
||||
|
||||
- `installShellFiles`: Allow installManPage to take a piped input, add the `--name` flag for renaming the file when installed. Can also append `--` to opt-out of all subsequent parsing.
|
||||
@@ -38,6 +43,8 @@
|
||||
|
||||
- LLVM 12, 13, 14, 15, 16, and 17 have been removed, as they have reached end‐of‐life upstream and are no longer supported.
|
||||
|
||||
- The `vlock` output from kbd has been removed. Instead a new package `kbdVlock` has been introduced. Use this package now instead of the output.
|
||||
|
||||
- GHCJS 8.10, exposed via `haskell.compiler.ghcjs` and `haskell.compiler.ghcjs810`, has been removed. Downstream users should migrate their projects to the new JavaScript backend of GHC proper which can be used via `pkgsCross.ghcjs` from Nixpkgs. Haskell packaging code, like `haskellPackages.mkDerivation`, `ghcWithPackages` and `hoogleWithPackages`, also no longer supports GHCJS.
|
||||
|
||||
- GHC 8.6, 8.10, 9.0, 9.2, and their package sets have been removed.
|
||||
@@ -61,6 +68,9 @@
|
||||
|
||||
- `base16-builder` node package has been removed due to lack of upstream maintenance.
|
||||
|
||||
- The default glibc ELF ABI for the powerpc64-linux platform has been changed from ELFv2 back to ELFv1, due to the latter having less remaining issues when bootstrapping & building Nixpkgs packages on hardware.
|
||||
If glibc ELFv2 is desired, use a fuller target triplet like `powerpc64-unknown-linux-gnuabielfv2` or the provided `ppc64-elfv2` platform example.
|
||||
|
||||
- `python3Packages.bjoern` has been removed, as the upstream is unmaintained and it depends on a 14-year-old version of http-parser with numerous vulnerabilities.
|
||||
|
||||
- `buildGoModule` removes the compatibility layer of `CGO_ENABLED` not specified via `env`.
|
||||
@@ -178,6 +188,8 @@
|
||||
|
||||
- `proton-caller` has been removed due to lack of upstream maintenance.
|
||||
|
||||
- `android-udev-rules` has been removed, as it is effectively superseded by built-in uaccess rules in systemd.
|
||||
|
||||
- `lima` package now only includes the guest agent for the host's architecture by default. If your guest VM's architecture differs from your Lima host's, you'll need to enable the `lima-additional-guestagents` package by setting `withAdditionalGuestAgents = true` when overriding lima with this input.
|
||||
|
||||
- `mongodb-6_0` was removed as it is end of life as of 2025-07-31.
|
||||
@@ -198,6 +210,8 @@
|
||||
|
||||
- `sail-riscv` 0.8 follows [upstream](https://github.com/riscv/sail-riscv/blob/7cc4620eb1a57bfe04832baccdcf5727e9459bd4/doc/ChangeLog.md) and provides only a single binary, `sail_riscv_sim`.
|
||||
|
||||
- `moar` has been updated from `1.33.0` to `2.0.0`, and renamed to `moor` following an upstream decision. See the [release notes](https://github.com/walles/moor/releases/tag/v2.0.0) for more.
|
||||
|
||||
- `podofo` has been updated from `0.9.8` to `1.0.0`. These releases are by nature very incompatible due to major API changes. The legacy versions can be found under `podofo_0_10` and `podofo_0_9`.
|
||||
Changelog: https://github.com/podofo/podofo/blob/1.0.0/CHANGELOG.md, API-Migration-Guide: https://github.com/podofo/podofo/blob/1.0.0/API-MIGRATION.md.
|
||||
|
||||
@@ -240,6 +254,12 @@
|
||||
|
||||
- `mariadb` now defaults to `mariadb_114` instead of `mariadb_1011`, meaning the default version was upgraded from 10.11.x to 11.4.x. See the [upgrade notes](https://mariadb.com/kb/en/upgrading-from-mariadb-10-11-to-mariadb-11-4/) for potential issues.
|
||||
|
||||
- `qt5.full` and `qt6.full` aliases have been removed. Their use has always been discouraged, and downstream projects should use `qtN.env` with the right set of packages.
|
||||
|
||||
- `python3Packages.duckduckgo-search` has been updated to v9+ and therefore has been renamed to ddgs.
|
||||
Use `python3Packages.ddgs` instead.
|
||||
See [release note for v9.0.0](https://github.com/deedy5/ddgs/releases/tag/v9.0.0)
|
||||
|
||||
## Other Notable Changes {#sec-nixpkgs-release-25.11-notable-changes}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
@@ -253,12 +273,22 @@
|
||||
|
||||
- The systemd initrd will now respect `x-systemd.wants` and `x-systemd.requires` for reliably unlocking multi-disk bcachefs volumes.
|
||||
|
||||
- `neovim`: Added support for the `vim.o.exrc` option, the `VIMINIT` environment variable, and sourcing of `sysinit.vim`.
|
||||
|
||||
See the neovim help page [`:help startup`](https://neovim.io/doc/user/starting.html#startup) for more information, as well as [the nixpkgs neovim wrapper documentation](#neovim-custom-configuration).
|
||||
|
||||
- `cloudflare-ddns`: Added package cloudflare-ddns.
|
||||
|
||||
- `clickhouse`: Added `serverConfig`, `usersConfig` configuration options accepting Nix attribute sets. Also added `extraServerConfig` and `extraUsersConfig` options accepting plain text (expecting XML configuration).
|
||||
|
||||
- [`homebox` 0.20.0](https://github.com/sysadminsmedia/homebox/releases/tag/v0.20.0) changed how assets are stored and hashed. It is recommended to back up your database before this update. In particular, `--storage-data` was replaced with `--storage-conn-string` and `--storage-prefix-path`. If your configuration set `HBOX_STORAGE_DATA` manually, you must migrate it to `HBOX_STORAGE_CONN_STRING` and `HBOX_STORAGE_PREFIX_PATH`.
|
||||
|
||||
- GIMP now defaults to version 3. Use `gimp2` for the old version.
|
||||
|
||||
- `installShellCompletion`: now supports Nushell completion files
|
||||
|
||||
- `idris2` supports being instantiated with a package environment with `idris.withPackages (p: [ ])`
|
||||
|
||||
- New hardening flags, `strictflexarrays1` and `strictflexarrays3` were made available, corresponding to the gcc/clang options `-fstrict-flex-arrays=1` and `-fstrict-flex-arrays=3` respectively.
|
||||
|
||||
- `gramps` has been updated to 6.0.0
|
||||
@@ -268,6 +298,8 @@
|
||||
|
||||
- `forgejo-runner`: The upgrade to version 11 brings a license change from MIT to GPLv3-or-later.
|
||||
|
||||
- `waydroid-nftables`: New variant of `waydroid` that supports nftables instead of iptables.
|
||||
|
||||
- `lisp-modules` were brought in sync with the [June 2025 Quicklisp release](http://blog.quicklisp.org/2025/07/june-2025-quicklisp-dist-now-available.html).
|
||||
|
||||
- `ffmpeg_8`, `ffmpeg_8-headless`, and `ffmpeg_8-full` have been added. The default version of FFmpeg remains ffmpeg_7 for now, though this may change before release.
|
||||
@@ -275,6 +307,13 @@
|
||||
- `searx` was updated to use `envsubst` instead of `sed` for parsing secrets from environment variables.
|
||||
If your previous configuration included a secret reference like `server.secret_key = "@SEARX_SECRET_KEY@"`, you must migrate to the new envsubst syntax: `server.secret_key = "$SEARX_SECRET_KEY"`.
|
||||
|
||||
- `jellyfin` was updated to `10.11.x`, which includes heavy backend changes.
|
||||
Make sure to backup your data and configuration directories
|
||||
and read the [Jellyfin 10.11.0 release announcement](https://jellyfin.org/posts/jellyfin-release-10.11.0/).
|
||||
**Important:** make sure you're running Jellyfin version `10.10.7` before upgrading,
|
||||
and beware that the migration may take several hours depending on your library size and state.
|
||||
The process must not be interrupted.
|
||||
|
||||
- A new hardening flag, `glibcxxassertions` was made available, corresponding to the glibc `_GLIBCXX_ASSERTIONS` option.
|
||||
|
||||
- `versionCheckHook`: Packages that previously relied solely on `pname` to locate the program used to version check, but have a differing `meta.mainProgram` entry, might now fail.
|
||||
@@ -302,39 +341,55 @@
|
||||
|
||||
- `emacs` now disables the GC mark trace buffer by default. This improves GC performance by 5%, but can make GC issues harder to debug. This is configurable with `withGcMarkTrace`.
|
||||
|
||||
- Passing `stdenv` to `buildPythonPackage` or `buildPythonApplication` has been deprecated and will trigger an error in a future release.
|
||||
Instead, you should _override_ the python build helper, e.g., `(buildPythonPackage.override { stdenv = customStdenv; })`.
|
||||
See [](#overriding-python-build-helpers).
|
||||
|
||||
- `buildPythonPackage` and `buildPythonApplication` now default to `nix-update-script` as their default `updateScript`. This should improve automated updates, since nix-update is better maintained than the in-tree update script and has more robust fetcher support.
|
||||
|
||||
- `plasma6`: Fixed the `ksycoca` cache not being re-built when `$XDG_CACHE_HOME` is set to something that isn't `$HOME/.cache`.
|
||||
|
||||
## Nixpkgs Library {#sec-nixpkgs-release-25.11-lib}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- `mealie` has been updated to 3.0.2: This update introduces breaking changes in some API endpoints (see the [release changelog](https://github.com/mealie-recipes/mealie/releases/tag/v3.0.0)).
|
||||
|
||||
### Breaking changes {#sec-nixpkgs-release-25.11-lib-breaking}
|
||||
|
||||
- `reaction` has been updated to version 2, which includes some breaking changes.
|
||||
For more information, [check the release article](https://blog.ppom.me/en-reaction-v2).
|
||||
- `lib.literalExample` has been removed, use `lib.literalExpression` instead, or use `lib.literalMD` for a non-Nix description.
|
||||
|
||||
- `lib.replaceChars` has been removed, it was a deprecated alias of `lib.replaceStrings`.
|
||||
|
||||
- `lib.readPathsFromFile` has been removed, use a list instead
|
||||
|
||||
- `lib.mapAttrsFlatten` has been removed, following its deprecation in NixOS 24.11. Use `lib.attrsets.mapAttrsToList` instead.
|
||||
|
||||
- `lib.strings.isCoercibleToString` has been in favor of either `lib.strings.isStringLike` or `lib.strings.isConvertibleWithToString`. Only use the latter if it needs to return true for null, numbers, booleans, or a list of those.
|
||||
|
||||
- `lib.types.string` has been removed. See [this pull request](https://github.com/NixOS/nixpkgs/pull/66346) for better alternative types like `lib.types.str`.
|
||||
|
||||
- `lib.modules.defaultPriority` has been removed, please use `lib.modules.defaultOverridePriority` instead.
|
||||
|
||||
- `lib.attrsets.cartesianProductOfSets` has been removed, following its deprecation in NixOS 24.11. Use `lib.attrsets.cartesianProduct` instead.
|
||||
|
||||
- `lib.sources.pathType`, `lib.sources.pathIsDirectory` and `lib.sources.pathIsRegularFile` have been replaced by `lib.filesystem.pathType`, `lib.filesystem.pathIsDirectory` and `lib.filesystem.pathIsRegularFile` respectively.
|
||||
|
||||
- `lib.attrsets.zip` has been removed, following its deprecation in 2013. Use `lib.attrsets.zipAttrsWith` instead.
|
||||
|
||||
- `lib.attrsets.zipWithNames` has been removed, following its deprecation in 2009. Use `lib.attrsets.zipAttrsWithNames` instead.
|
||||
|
||||
- `lib.options.mkPackageOptionMD` has been removed, following its deprecation in NixOS 24.11. Use `lib.options.mkPackageOption` instead.
|
||||
|
||||
- `haskell.lib.addOptparseApplicativeCompletionScripts` has been removed, use `haskellPackages.generateOptparseApplicativeCompletions` instead.
|
||||
|
||||
- The `buildPythonPackage` and `buildPythonApplication` functions now require
|
||||
an explicit `format` attribute. Previously the default format used setuptools
|
||||
and called `setup.py` from the source tree, which is deprecated.
|
||||
The modern alternative is to configure `pyproject = true` with `build-system = [ setuptools ]`.
|
||||
|
||||
- `boot.enableContainers` is only turned on when a declarative NixOS container is defined in `containers`.
|
||||
If you use the `nixos-container` tool for imperative container management, set `boot.enableContainers = true;` explicitly.
|
||||
|
||||
### Deprecations {#sec-nixpkgs-release-25.11-lib-deprecations}
|
||||
|
||||
- `lib.options.mkAliasOptionModuleMD` is now obsolete; use the identical [`lib.options.mkAliasOptionModule`] instead.
|
||||
|
||||
- `types.either` silently accepted mismatching types when used in `freeformType`. Module maintainers should fix the used type
|
||||
In most cases wrapping `either` with `attrsOf` should be sufficient.
|
||||
|
||||
@@ -343,10 +398,13 @@
|
||||
- `number`
|
||||
- `numbers.*`
|
||||
|
||||
- `lib.cli.toGNUCommandLine` and `lib.cli.toGNUCommandLineShell` have been deprecated in favor of `lib.cli.toCommandLine`, `lib.cli.toCommandLineShell`, `lib.cli.toCommandLineGNU` and `lib.cli.toCommandLineShellGNU`.
|
||||
|
||||
### Additions and Improvements {#sec-nixpkgs-release-25.11-lib-additions-improvements}
|
||||
|
||||
- `neovim`: Added support for the `vim.o.exrc` option, the `VIMINIT` environment variable, and sourcing of `sysinit.vim`.
|
||||
- `lib.cli.toCommandLine`, `lib.cli.toCommandLineShell`, `lib.cli.toCommandLineGNU` and `lib.cli.toCommandLineShellGNU` have been added to address multiple issues in `lib.cli.toGNUCommandLine` and `lib.cli.toGNUCommandLineShell`.
|
||||
|
||||
See the neovim help page [`:help startup`](https://neovim.io/doc/user/starting.html#startup) for more information, as well as [the nixpkgs neovim wrapper documentation](#neovim-custom-configuration).
|
||||
- `ugrep`: Added `wrapWithFilterUtils` package flag for optionally wrapping `ugrep+` and `ug+` with filter utilities for grepping other file types.
|
||||
|
||||
- `ugrep`: Added `createGrepReplacementLinks` package flag for optionally creating drop-in replacement symlinks for `gnugrep`.
|
||||
|
||||
- `cloudflare-ddns`: Added package cloudflare-ddns.
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
{
|
||||
lib,
|
||||
runCommand,
|
||||
invalidateFetcherByDrvHash,
|
||||
testers,
|
||||
cacert,
|
||||
python3,
|
||||
}:
|
||||
|
||||
invalidateFetcherByDrvHash (
|
||||
testers.invalidateFetcherByDrvHash (
|
||||
{
|
||||
name ? "manual_check-manpage-urls",
|
||||
script ? ./manpage-urls.py,
|
||||
|
||||
@@ -1,18 +1,49 @@
|
||||
# Platform Support {#chap-platform-support}
|
||||
|
||||
Packages receive varying degrees of support, both in terms of maintainer attention and available computation resources for continuous integration (CI).
|
||||
Packages receive varying degrees of support, both in terms of maintainer attention and available computation resources for continuous integration (CI). We have 7 defined tiers denoting how well supported each platform is.
|
||||
|
||||
Below is the list of the best supported platforms:
|
||||
## Tiers {#sec-platform-tiers}
|
||||
|
||||
- `x86_64-linux`: Highest level of support.
|
||||
- `aarch64-linux`: Well supported, with most packages building successfully in CI.
|
||||
- `aarch64-darwin`: Receives better support than `x86_64-darwin`.
|
||||
- `x86_64-darwin`: Receives some support.
|
||||
### Tier 1 {#sec-platform-tier1}
|
||||
|
||||
There are many other platforms with varying levels of support.
|
||||
The provisional platform list in [Appendix A] of [RFC046], while not up to date, can be used as guidance.
|
||||
[Tier 1](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-1) platforms receive the highest level of support where problems can block updates, platform-specific patches are freely applied, and most packages are expected to work.
|
||||
|
||||
A more formal definition of the platform support tiers is provided in [RFC046], but has not been fully implemented yet.
|
||||
### Tier 2 {#sec-platform-tier2}
|
||||
|
||||
[RFC046]: https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md
|
||||
[Appendix A]: https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#appendix-a-non-normative-description-of-platforms-in-november-2019
|
||||
[Tier 2](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-2) platforms are expected to remain functional with updates, receive platform-specific patches as needed, and have many packages built by Hydra with full ofBorg support.
|
||||
|
||||
### Tier 3 {#sec-platform-tier3}
|
||||
|
||||
[Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) platforms may receive non-intrusive platform-specific fixes, have native bootstrap tools available with cross-build toolchains in binary cache, but updates might break builds on these platforms.
|
||||
|
||||
### Tier 4-7 {#sec-platform-tier4-7}
|
||||
|
||||
Platform Tiers [4 through 7](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-4) indicate varying levels of minimal support going from receiving only limited fixes to platforms with no support, but a path to support.
|
||||
|
||||
## Breakdown {#sec-platform-breakdown}
|
||||
|
||||
| Triple | Support Tier | Channel Blockers | Hydra Support | Ofborg Support | Bootstrap Tarballs | Cross Compiling Support |
|
||||
| ------------------------------------- | ------------ | ---------------- | ------------- | -------------- | ------------------ | ----------------------- |
|
||||
| `x86_64-unknown-linux-gnu` | [Tier 1](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-1) | Many | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| `aarch64-unknown-linux-gnu` | [Tier 2](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-2) | Some | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| `x86_64-unknown-linux-musl` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | Limited | ❌ | ✔️ | ✔️ |
|
||||
| `aarch64-unknown-linux-musl` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | Limited | ❌ | ✔️ | ✔️ |
|
||||
| `x86_64-unknown-unknown-freebsd` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `arm64-apple-darwin` | [Tier 2](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-2) | Some | ✔️ | ✔️ | ✔️ | ❌\* |
|
||||
| `x86_64-apple-darwin` | [Tier 2](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-2) | Some | ✔️ | ✔️ | ✔️ | ❌\* |
|
||||
| `i686-unknown-linux-gnu` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | Limited | ❌ | ✔️ | ✔️ |
|
||||
| `riscv32-unknown-linux-gnu` | [Tier 4](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-4) | None | ❌ | ❌ | ❌ | ✔️ |
|
||||
| `riscv64-unknown-linux-gnu` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `loongarch64-unknown-linux-gnu` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `armv6l-unknown-linux-gnueabihf` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `armv6l-unknown-linux-musleabihf` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `armv7l-unknown-linux-gnueabihf` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `armv5tel-unknown-linux-gnueabi` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `mips64el-unknown-linux-gnuabi64` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `mips64el-unknown-linux-gnuabin32` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `mipsel-unknown-linux-gnu` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `powerpc64-unknown-linux-gnuabielfv2` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `powerpc64le-unknown-linux-gnu` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
| `s390x-unknown-linux-gnu` | [Tier 3](https://github.com/NixOS/rfcs/blob/master/rfcs/0046-platform-support-tiers.md#tier-3) | None | ❌ | ❌ | ✔️ | ✔️ |
|
||||
|
||||
\* - Cross compiling is only supported on Darwin hosts.
|
||||
|
||||
+224
-33
@@ -1,6 +1,6 @@
|
||||
{ lib }:
|
||||
|
||||
rec {
|
||||
{
|
||||
/**
|
||||
Automatically convert an attribute set to command-line options.
|
||||
|
||||
@@ -20,6 +20,7 @@ rec {
|
||||
: The attributes to transform into arguments.
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.cli.toGNUCommandLineShell` usage example
|
||||
|
||||
@@ -38,7 +39,10 @@ rec {
|
||||
|
||||
:::
|
||||
*/
|
||||
toGNUCommandLineShell = options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
|
||||
toGNUCommandLineShell =
|
||||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2511)
|
||||
"lib.cli.toGNUCommandLineShell is deprecated, please use lib.cli.toCommandLineShell or lib.cli.toCommandLineShellGNU instead."
|
||||
(options: attrs: lib.escapeShellArgs (lib.cli.toGNUCommandLine options attrs));
|
||||
|
||||
/**
|
||||
Automatically convert an attribute set to a list of command-line options.
|
||||
@@ -55,7 +59,7 @@ rec {
|
||||
|
||||
: The attributes to transform into arguments.
|
||||
|
||||
# Options
|
||||
## Options
|
||||
|
||||
`mkOptionName`
|
||||
|
||||
@@ -85,6 +89,7 @@ rec {
|
||||
This is useful if the command requires equals, for example, `-c=5`.
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.cli.toGNUCommandLine` usage example
|
||||
|
||||
@@ -111,38 +116,224 @@ rec {
|
||||
:::
|
||||
*/
|
||||
toGNUCommandLine =
|
||||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2511)
|
||||
"lib.cli.toGNUCommandLine is deprecated, please use lib.cli.toCommandLine or lib.cli.toCommandLineShellGNU instead."
|
||||
(
|
||||
{
|
||||
mkOptionName ? k: if builtins.stringLength k == 1 then "-${k}" else "--${k}",
|
||||
|
||||
mkBool ? k: v: lib.optional v (mkOptionName k),
|
||||
|
||||
mkList ? k: v: lib.concatMap (mkOption k) v,
|
||||
|
||||
mkOption ?
|
||||
k: v:
|
||||
if v == null then
|
||||
[ ]
|
||||
else if optionValueSeparator == null then
|
||||
[
|
||||
(mkOptionName k)
|
||||
(lib.generators.mkValueStringDefault { } v)
|
||||
]
|
||||
else
|
||||
[ "${mkOptionName k}${optionValueSeparator}${lib.generators.mkValueStringDefault { } v}" ],
|
||||
|
||||
optionValueSeparator ? null,
|
||||
}:
|
||||
options:
|
||||
let
|
||||
render =
|
||||
k: v:
|
||||
if builtins.isBool v then
|
||||
mkBool k v
|
||||
else if builtins.isList v then
|
||||
mkList k v
|
||||
else
|
||||
mkOption k v;
|
||||
|
||||
in
|
||||
builtins.concatLists (lib.mapAttrsToList render options)
|
||||
);
|
||||
|
||||
/**
|
||||
Converts the given attributes into a single shell-escaped command-line string.
|
||||
Similar to `toCommandLineGNU`, but returns a single escaped string instead of an array of arguments.
|
||||
For further reference see: [`lib.cli.toCommandLineGNU`](#function-library-lib.cli.toCommandLineGNU)
|
||||
*/
|
||||
toCommandLineShellGNU =
|
||||
options: attrs: lib.escapeShellArgs (lib.cli.toCommandLineGNU options attrs);
|
||||
|
||||
/**
|
||||
Converts an attribute set into a list of GNU-style command line options.
|
||||
|
||||
`toCommandLineGNU` returns a list of string arguments.
|
||||
|
||||
# Inputs
|
||||
|
||||
`options`
|
||||
|
||||
: Options, see below.
|
||||
|
||||
`attrs`
|
||||
|
||||
: The attributes to transform into arguments.
|
||||
|
||||
## Options
|
||||
|
||||
`isLong`
|
||||
|
||||
: A function that determines whether an option is long or short.
|
||||
|
||||
`explicitBool`
|
||||
|
||||
: Whether or not boolean option arguments should be formatted explicitly.
|
||||
|
||||
`formatArg`
|
||||
|
||||
: A function that turns the option argument into a string.
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.cli.toCommandLineGNU` usage example
|
||||
|
||||
```nix
|
||||
lib.cli.toCommandLineGNU {} {
|
||||
v = true;
|
||||
verbose = [true true false null];
|
||||
i = ".bak";
|
||||
testsuite = ["unit" "integration"];
|
||||
e = ["s/a/b/" "s/b/c/"];
|
||||
n = false;
|
||||
data = builtins.toJSON {id = 0;};
|
||||
}
|
||||
=> [
|
||||
"--data={\"id\":0}"
|
||||
"-es/a/b/"
|
||||
"-es/b/c/"
|
||||
"-i.bak"
|
||||
"--testsuite=unit"
|
||||
"--testsuite=integration"
|
||||
"-v"
|
||||
"--verbose"
|
||||
"--verbose"
|
||||
]
|
||||
```
|
||||
|
||||
:::
|
||||
*/
|
||||
toCommandLineGNU =
|
||||
{
|
||||
mkOptionName ? k: if builtins.stringLength k == 1 then "-${k}" else "--${k}",
|
||||
|
||||
mkBool ? k: v: lib.optional v (mkOptionName k),
|
||||
|
||||
mkList ? k: v: lib.concatMap (mkOption k) v,
|
||||
|
||||
mkOption ?
|
||||
k: v:
|
||||
if v == null then
|
||||
[ ]
|
||||
else if optionValueSeparator == null then
|
||||
[
|
||||
(mkOptionName k)
|
||||
(lib.generators.mkValueStringDefault { } v)
|
||||
]
|
||||
else
|
||||
[ "${mkOptionName k}${optionValueSeparator}${lib.generators.mkValueStringDefault { } v}" ],
|
||||
|
||||
optionValueSeparator ? null,
|
||||
isLong ? optionName: builtins.stringLength optionName > 1,
|
||||
explicitBool ? false,
|
||||
formatArg ? lib.generators.mkValueStringDefault { },
|
||||
}:
|
||||
options:
|
||||
let
|
||||
render =
|
||||
k: v:
|
||||
if builtins.isBool v then
|
||||
mkBool k v
|
||||
else if builtins.isList v then
|
||||
mkList k v
|
||||
else
|
||||
mkOption k v;
|
||||
|
||||
optionFormat = optionName: {
|
||||
option = if isLong optionName then "--${optionName}" else "-${optionName}";
|
||||
sep = if isLong optionName then "=" else "";
|
||||
inherit explicitBool formatArg;
|
||||
};
|
||||
in
|
||||
builtins.concatLists (lib.mapAttrsToList render options);
|
||||
lib.cli.toCommandLine optionFormat;
|
||||
|
||||
/**
|
||||
Converts the given attributes into a single shell-escaped command-line string.
|
||||
Similar to `toCommandLine`, but returns a single escaped string instead of an array of arguments.
|
||||
For further reference see: [`lib.cli.toCommandLine`](#function-library-lib.cli.toCommandLine)
|
||||
*/
|
||||
toCommandLineShell =
|
||||
optionFormat: attrs: lib.escapeShellArgs (lib.cli.toCommandLine optionFormat attrs);
|
||||
|
||||
/**
|
||||
Converts an attribute set into a list of command line options.
|
||||
|
||||
`toCommandLine` returns a list of string arguments.
|
||||
|
||||
# Inputs
|
||||
|
||||
`optionFormat`
|
||||
|
||||
: The option format that describes how options and their arguments should be formatted.
|
||||
|
||||
`attrs`
|
||||
|
||||
: The attributes to transform into arguments.
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `lib.cli.toCommandLine` usage example
|
||||
|
||||
```nix
|
||||
let
|
||||
optionFormat = optionName: {
|
||||
option = "-${optionName}";
|
||||
sep = "=";
|
||||
explicitBool = true;
|
||||
};
|
||||
in lib.cli.toCommandLine optionFormat {
|
||||
v = true;
|
||||
verbose = [true true false null];
|
||||
i = ".bak";
|
||||
testsuite = ["unit" "integration"];
|
||||
e = ["s/a/b/" "s/b/c/"];
|
||||
n = false;
|
||||
data = builtins.toJSON {id = 0;};
|
||||
}
|
||||
=> [
|
||||
"-data={\"id\":0}"
|
||||
"-e=s/a/b/"
|
||||
"-e=s/b/c/"
|
||||
"-i=.bak"
|
||||
"-n=false"
|
||||
"-testsuite=unit"
|
||||
"-testsuite=integration"
|
||||
"-v=true"
|
||||
"-verbose=true"
|
||||
"-verbose=true"
|
||||
"-verbose=false"
|
||||
]
|
||||
```
|
||||
|
||||
:::
|
||||
*/
|
||||
toCommandLine =
|
||||
optionFormat: attrs:
|
||||
let
|
||||
handlePair =
|
||||
k: v:
|
||||
if k == "" then
|
||||
lib.throw "lib.cli.toCommandLine only accepts non-empty option names."
|
||||
else if builtins.isList v then
|
||||
builtins.concatMap (handleOption k) v
|
||||
else
|
||||
handleOption k v;
|
||||
|
||||
handleOption = k: renderOption (optionFormat k) k;
|
||||
|
||||
renderOption =
|
||||
{
|
||||
option,
|
||||
sep,
|
||||
explicitBool,
|
||||
formatArg ? lib.generators.mkValueStringDefault { },
|
||||
}:
|
||||
k: v:
|
||||
if v == null || (!explicitBool && v == false) then
|
||||
[ ]
|
||||
else if !explicitBool && v == true then
|
||||
[ option ]
|
||||
else
|
||||
let
|
||||
arg = formatArg v;
|
||||
in
|
||||
if sep != null then
|
||||
[ "${option}${sep}${arg}" ]
|
||||
else
|
||||
[
|
||||
option
|
||||
arg
|
||||
];
|
||||
in
|
||||
builtins.concatLists (lib.mapAttrsToList handlePair attrs);
|
||||
}
|
||||
|
||||
+165
-11
@@ -22,7 +22,6 @@ let
|
||||
filterAttrs
|
||||
optionalString
|
||||
flip
|
||||
pathIsDirectory
|
||||
head
|
||||
pipe
|
||||
isDerivation
|
||||
@@ -305,9 +304,10 @@ rec {
|
||||
arg:
|
||||
let
|
||||
loc = unsafeGetAttrPos arg fargs;
|
||||
loc' = if loc != null then loc.file + ":" + toString loc.line else "<unknown location>";
|
||||
in
|
||||
"Function called without required argument \"${arg}\" at "
|
||||
+ "${loc.file}:${toString loc.line}${prettySuggestions (getSuggestions arg)}";
|
||||
+ "${loc'}${prettySuggestions (getSuggestions arg)}";
|
||||
|
||||
# Only show the error for the first missing argument
|
||||
error = errorForArg (head (attrNames missingArgs));
|
||||
@@ -763,11 +763,26 @@ rec {
|
||||
# Inputs
|
||||
|
||||
`extendMkDerivation`-specific configurations
|
||||
: `constructDrv`: Base build helper, the `mkDerivation`-like build helper to extend.
|
||||
: `excludeDrvArgNames`: Argument names not to pass from the input fixed-point arguments to `constructDrv`. Note: It doesn't apply to the updating arguments returned by `extendDrvArgs`.
|
||||
: `extendDrvArgs` : An extension (overlay) of the argument set, like the one taken by [overrideAttrs](#sec-pkg-overrideAttrs) but applied before passing to `constructDrv`.
|
||||
: `inheritFunctionArgs`: Whether to inherit `__functionArgs` from the base build helper (default to `true`).
|
||||
: `transformDrv`: Function to apply to the result derivation (default to `lib.id`).
|
||||
: `constructDrv` (required)
|
||||
: Base build helper, the `mkDerivation`-like build helper to extend.
|
||||
|
||||
`excludeDrvArgNames` (default to `[ ]`)
|
||||
: Argument names not to pass from the input fixed-point arguments to `constructDrv`.
|
||||
It doesn't apply to the updating arguments returned by `extendDrvArgs`.
|
||||
|
||||
`excludeFunctionArgNames` (default to `[ ]`)
|
||||
: `__functionArgs` attribute names to remove from the result build helper.
|
||||
`excludeFunctionArgNames` is useful for argument deprecation while avoiding ellipses.
|
||||
|
||||
`extendDrvArgs` (required)
|
||||
: An extension (overlay) of the argument set, like the one taken by [overrideAttrs](#sec-pkg-overrideAttrs) but applied before passing to `constructDrv`.
|
||||
|
||||
`inheritFunctionArgs` (default to `true`)
|
||||
: Whether to inherit `__functionArgs` from the base build helper.
|
||||
Set `inheritFunctionArgs` to `false` when `extendDrvArgs`'s `args` set pattern does not contain an ellipsis.
|
||||
|
||||
`transformDrv` (default to `lib.id`)
|
||||
: Function to apply to the result derivation.
|
||||
|
||||
# Type
|
||||
|
||||
@@ -776,6 +791,7 @@ rec {
|
||||
{
|
||||
constructDrv :: ((FixedPointArgs | AttrSet) -> a)
|
||||
excludeDrvArgNames :: [ String ],
|
||||
excludeFunctionArgNames :: [ String ]
|
||||
extendDrvArgs :: (AttrSet -> AttrSet -> AttrSet)
|
||||
inheritFunctionArgs :: Bool,
|
||||
transformDrv :: a -> a,
|
||||
@@ -836,6 +852,7 @@ rec {
|
||||
{
|
||||
constructDrv,
|
||||
excludeDrvArgNames ? [ ],
|
||||
excludeFunctionArgNames ? [ ],
|
||||
extendDrvArgs,
|
||||
inheritFunctionArgs ? true,
|
||||
transformDrv ? id,
|
||||
@@ -850,10 +867,12 @@ rec {
|
||||
)
|
||||
# Add __functionArgs
|
||||
(
|
||||
# Inherit the __functionArgs from the base build helper
|
||||
optionalAttrs inheritFunctionArgs (removeAttrs (functionArgs constructDrv) excludeDrvArgNames)
|
||||
# Recover the __functionArgs from the derived build helper
|
||||
// functionArgs (extendDrvArgs { })
|
||||
removeAttrs (
|
||||
# Inherit the __functionArgs from the base build helper
|
||||
optionalAttrs inheritFunctionArgs (removeAttrs (functionArgs constructDrv) excludeDrvArgNames)
|
||||
# Recover the __functionArgs from the derived build helper
|
||||
// functionArgs (extendDrvArgs { })
|
||||
) excludeFunctionArgNames
|
||||
)
|
||||
// {
|
||||
inherit
|
||||
@@ -864,4 +883,139 @@ rec {
|
||||
transformDrv
|
||||
;
|
||||
};
|
||||
|
||||
/**
|
||||
Removes a prefix from the attribute names of a cross index.
|
||||
|
||||
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
|
||||
organizing values by cross-compilation platform relationships.
|
||||
|
||||
# Inputs
|
||||
|
||||
`prefix`
|
||||
: The prefix to remove from cross index attribute names
|
||||
|
||||
`crossIndex`
|
||||
: A cross index with prefixed names
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
renameCrossIndexFrom :: String -> AttrSet -> AttrSet
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.customisation.renameCrossIndexFrom` usage example
|
||||
|
||||
```nix
|
||||
renameCrossIndexFrom "pkgs" { pkgsBuildBuild = ...; pkgsBuildHost = ...; ... }
|
||||
=> { buildBuild = ...; buildHost = ...; ... }
|
||||
```
|
||||
:::
|
||||
*/
|
||||
renameCrossIndexFrom = prefix: x: {
|
||||
buildBuild = x."${prefix}BuildBuild";
|
||||
buildHost = x."${prefix}BuildHost";
|
||||
buildTarget = x."${prefix}BuildTarget";
|
||||
hostHost = x."${prefix}HostHost";
|
||||
hostTarget = x."${prefix}HostTarget";
|
||||
targetTarget = x."${prefix}TargetTarget";
|
||||
};
|
||||
|
||||
/**
|
||||
Adds a prefix to the attribute names of a cross index.
|
||||
|
||||
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
|
||||
organizing values by cross-compilation platform relationships.
|
||||
|
||||
# Inputs
|
||||
|
||||
`prefix`
|
||||
: The prefix to add to cross index attribute names
|
||||
|
||||
`crossIndex`
|
||||
: A cross index to be prefixed
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
renameCrossIndexTo :: String -> AttrSet -> AttrSet
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.customisation.renameCrossIndexTo` usage example
|
||||
|
||||
```nix
|
||||
renameCrossIndexTo "self" { buildBuild = ...; buildHost = ...; ... }
|
||||
=> { selfBuildBuild = ...; selfBuildHost = ...; ... }
|
||||
```
|
||||
:::
|
||||
*/
|
||||
renameCrossIndexTo = prefix: x: {
|
||||
"${prefix}BuildBuild" = x.buildBuild;
|
||||
"${prefix}BuildHost" = x.buildHost;
|
||||
"${prefix}BuildTarget" = x.buildTarget;
|
||||
"${prefix}HostHost" = x.hostHost;
|
||||
"${prefix}HostTarget" = x.hostTarget;
|
||||
"${prefix}TargetTarget" = x.targetTarget;
|
||||
};
|
||||
|
||||
/**
|
||||
Takes a function and applies it pointwise to each field of a cross index.
|
||||
|
||||
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
|
||||
organizing values by cross-compilation platform relationships.
|
||||
|
||||
# Inputs
|
||||
|
||||
`f`
|
||||
: Function to apply to each cross index value
|
||||
|
||||
`crossIndex`
|
||||
: A cross index to transform
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
mapCrossIndex :: (a -> b) -> AttrSet -> AttrSet
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.customisation.mapCrossIndex` usage example
|
||||
|
||||
```nix
|
||||
mapCrossIndex (x: x * 10) { buildBuild = 1; buildHost = 2; ... }
|
||||
=> { buildBuild = 10; buildHost = 20; ... }
|
||||
```
|
||||
|
||||
```nix
|
||||
# Extract a package from package sets
|
||||
mapCrossIndex (pkgs: pkgs.hello) crossIndexedPackageSets
|
||||
```
|
||||
:::
|
||||
*/
|
||||
mapCrossIndex =
|
||||
f:
|
||||
{
|
||||
buildBuild,
|
||||
buildHost,
|
||||
buildTarget,
|
||||
hostHost,
|
||||
hostTarget,
|
||||
targetTarget,
|
||||
}:
|
||||
{
|
||||
buildBuild = f buildBuild;
|
||||
buildHost = f buildHost;
|
||||
buildTarget = f buildTarget;
|
||||
hostHost = f hostHost;
|
||||
hostTarget = f hostTarget;
|
||||
targetTarget = f targetTarget;
|
||||
};
|
||||
}
|
||||
|
||||
+4
-4
@@ -63,7 +63,7 @@ let
|
||||
customisation = callLibs ./customisation.nix;
|
||||
derivations = callLibs ./derivations.nix;
|
||||
maintainers = import ../maintainers/maintainer-list.nix;
|
||||
teams = callLibs ../maintainers/team-list.nix;
|
||||
teams = callLibs ../maintainers/computed-team-list.nix;
|
||||
meta = callLibs ./meta.nix;
|
||||
versions = callLibs ./versions.nix;
|
||||
|
||||
@@ -344,7 +344,6 @@ let
|
||||
escapeRegex
|
||||
escapeURL
|
||||
escapeXML
|
||||
replaceChars
|
||||
lowerChars
|
||||
upperChars
|
||||
toLower
|
||||
@@ -377,7 +376,6 @@ let
|
||||
fixedWidthNumber
|
||||
toInt
|
||||
toIntBase10
|
||||
readPathsFromFile
|
||||
fileContents
|
||||
;
|
||||
inherit (self.stringsWithDeps)
|
||||
@@ -399,6 +397,9 @@ let
|
||||
makeScopeWithSplicing
|
||||
makeScopeWithSplicing'
|
||||
extendMkDerivation
|
||||
renameCrossIndexFrom
|
||||
renameCrossIndexTo
|
||||
mapCrossIndex
|
||||
;
|
||||
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
|
||||
inherit (self.generators) mkLuaInline;
|
||||
@@ -495,7 +496,6 @@ let
|
||||
optionAttrSetToDocList'
|
||||
scrubOptionValue
|
||||
literalExpression
|
||||
literalExample
|
||||
showOption
|
||||
showOptionWithDefLocs
|
||||
showFiles
|
||||
|
||||
@@ -101,6 +101,7 @@ let
|
||||
|
||||
inherit (import ./internal.nix { inherit lib; })
|
||||
_coerce
|
||||
_coerceResult
|
||||
_singleton
|
||||
_coerceMany
|
||||
_toSourceFilter
|
||||
@@ -1005,4 +1006,49 @@ in
|
||||
{
|
||||
submodules = recurseSubmodules;
|
||||
};
|
||||
|
||||
/**
|
||||
The empty fileset. It can be useful as a default value or as starting accumulator for a folding operation.
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
empty :: FileSet
|
||||
```
|
||||
*/
|
||||
empty = _emptyWithoutBase;
|
||||
|
||||
/**
|
||||
Tests whether a given value is a fileset, or can be used in place of a fileset.
|
||||
|
||||
# Inputs
|
||||
|
||||
`value`
|
||||
|
||||
: The value to test
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
isFileset :: Any -> Bool
|
||||
```
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `lib.fileset.isFileset` usage example
|
||||
|
||||
```nix
|
||||
isFileset ./.
|
||||
=> true
|
||||
|
||||
isFileset (unions [ ])
|
||||
=> true
|
||||
|
||||
isFileset 1
|
||||
=> false
|
||||
```
|
||||
|
||||
:::
|
||||
*/
|
||||
isFileset = x: (_coerceResult "" x).success;
|
||||
}
|
||||
|
||||
+35
-12
@@ -165,14 +165,27 @@ rec {
|
||||
_noEval = throw _noEvalMessage;
|
||||
};
|
||||
|
||||
# Coerce a value to a fileset, erroring when the value cannot be coerced.
|
||||
# The string gives the context for error messages.
|
||||
# Type: String -> (fileset | Path) -> fileset
|
||||
_coerce =
|
||||
# Coerce a value to a fileset. Return a set containing the attribute `success`
|
||||
# indicating whether coercing succeeded, and either `value` when `success ==
|
||||
# true`, or an error `message` when `success == false`. The string gives the
|
||||
# context for error messages.
|
||||
#
|
||||
# Type: String -> (fileset | Path) -> { success :: Bool, value :: fileset } ] -> { success :: Bool, message :: String }
|
||||
_coerceResult =
|
||||
let
|
||||
ok = value: {
|
||||
success = true;
|
||||
inherit value;
|
||||
};
|
||||
error = message: {
|
||||
success = false;
|
||||
inherit message;
|
||||
};
|
||||
in
|
||||
context: value:
|
||||
if value._type or "" == "fileset" then
|
||||
if value._internalVersion > _currentVersion then
|
||||
throw ''
|
||||
error ''
|
||||
${context} is a file set created from a future version of the file set library with a different internal representation:
|
||||
- Internal version of the file set: ${toString value._internalVersion}
|
||||
- Internal version of the library: ${toString _currentVersion}
|
||||
@@ -184,27 +197,37 @@ rec {
|
||||
_currentVersion - value._internalVersion
|
||||
) migrations;
|
||||
in
|
||||
foldl' (value: migration: migration value) value migrationsToApply
|
||||
ok (foldl' (value: migration: migration value) value migrationsToApply)
|
||||
else
|
||||
value
|
||||
ok value
|
||||
else if !isPath value then
|
||||
if value ? _isLibCleanSourceWith then
|
||||
throw ''
|
||||
error ''
|
||||
${context} is a `lib.sources`-based value, but it should be a file set or a path instead.
|
||||
To convert a `lib.sources`-based value to a file set you can use `lib.fileset.fromSource`.
|
||||
Note that this only works for sources created from paths.''
|
||||
else if isStringLike value then
|
||||
throw ''
|
||||
error ''
|
||||
${context} ("${toString value}") is a string-like value, but it should be a file set or a path instead.
|
||||
Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.''
|
||||
else
|
||||
throw ''${context} is of type ${typeOf value}, but it should be a file set or a path instead.''
|
||||
error ''${context} is of type ${typeOf value}, but it should be a file set or a path instead.''
|
||||
else if !pathExists value then
|
||||
throw ''
|
||||
error ''
|
||||
${context} (${toString value}) is a path that does not exist.
|
||||
To create a file set from a path that may not exist, use `lib.fileset.maybeMissing`.''
|
||||
else
|
||||
_singleton value;
|
||||
ok (_singleton value);
|
||||
|
||||
# Coerce a value to a fileset, erroring when the value cannot be coerced.
|
||||
# The string gives the context for error messages.
|
||||
# Type: String -> (fileset | Path) -> fileset
|
||||
_coerce =
|
||||
context: value:
|
||||
let
|
||||
result = _coerceResult context value;
|
||||
in
|
||||
if result.success then result.value else throw result.message;
|
||||
|
||||
# Coerce many values to filesets, erroring when any value cannot be coerced,
|
||||
# or if the filesystem root of the values doesn't match.
|
||||
|
||||
+15
-5
@@ -172,6 +172,11 @@ lib.mapAttrs mkLicense (
|
||||
fullName = "Baekmuk License";
|
||||
};
|
||||
|
||||
bitstreamCharter = {
|
||||
spdxId = "Bitstream-Charter";
|
||||
fullName = "Bitstream Charter Font License";
|
||||
};
|
||||
|
||||
bitstreamVera = {
|
||||
spdxId = "Bitstream-Vera";
|
||||
fullName = "Bitstream Vera Font License";
|
||||
@@ -615,11 +620,6 @@ lib.mapAttrs mkLicense (
|
||||
fullName = "Unspecified free software license";
|
||||
};
|
||||
|
||||
freeimage = {
|
||||
spdxId = "FreeImage";
|
||||
fullName = "FreeImage Public License v1.0";
|
||||
};
|
||||
|
||||
fsl11Mit = {
|
||||
fullName = "Functional Source License, Version 1.1, MIT Future License";
|
||||
spdxId = "FSL-1.1-MIT";
|
||||
@@ -665,6 +665,11 @@ lib.mapAttrs mkLicense (
|
||||
url = "https://www.gust.org.pl/projects/e-foundry/licenses/GUST-FONT-SOURCE-LICENSE.txt";
|
||||
};
|
||||
|
||||
gnuplot = {
|
||||
spdxId = "gnuplot";
|
||||
fullName = "gnuplot License";
|
||||
};
|
||||
|
||||
gpl1Only = {
|
||||
spdxId = "GPL-1.0-only";
|
||||
fullName = "GNU General Public License v1.0 only";
|
||||
@@ -988,6 +993,11 @@ lib.mapAttrs mkLicense (
|
||||
fullName = "CMU License";
|
||||
};
|
||||
|
||||
mit-enna = {
|
||||
spdxId = "MIT-enna";
|
||||
fullName = "enna License";
|
||||
};
|
||||
|
||||
mit-feh = {
|
||||
spdxId = "MIT-feh";
|
||||
fullName = "feh License";
|
||||
|
||||
+33
-14
@@ -1126,6 +1126,29 @@ let
|
||||
__toString = _: showOption loc;
|
||||
};
|
||||
|
||||
# Check that a type with v2 merge has a coherent check attribute.
|
||||
# Throws an error if the type uses an ad-hoc `type // { check }` override.
|
||||
# Returns the last argument like `seq`, allowing usage: checkV2MergeCoherence loc type expr
|
||||
checkV2MergeCoherence =
|
||||
loc: type: result:
|
||||
if type.check.isV2MergeCoherent or false then
|
||||
result
|
||||
else
|
||||
throw ''
|
||||
The option `${showOption loc}' has a type `${type.description}' that uses
|
||||
an ad-hoc `type // { check = ...; }' override, which is incompatible with
|
||||
the v2 merge mechanism.
|
||||
|
||||
Please use `lib.types.addCheck` instead of `type // { check }' to add
|
||||
custom validation. For example:
|
||||
|
||||
lib.types.addCheck baseType (value: /* your check */)
|
||||
|
||||
instead of:
|
||||
|
||||
baseType // { check = value: /* your check */; }
|
||||
'';
|
||||
|
||||
# Merge definitions of a value of a given type.
|
||||
mergeDefinitions = loc: type: defs: rec {
|
||||
defsFinal' =
|
||||
@@ -1201,10 +1224,13 @@ let
|
||||
(
|
||||
if type.merge ? v2 then
|
||||
let
|
||||
r = type.merge.v2 {
|
||||
inherit loc;
|
||||
defs = defsFinal;
|
||||
};
|
||||
# Check for v2 merge coherence
|
||||
r = checkV2MergeCoherence loc type (
|
||||
type.merge.v2 {
|
||||
inherit loc;
|
||||
defs = defsFinal;
|
||||
}
|
||||
);
|
||||
in
|
||||
r
|
||||
// {
|
||||
@@ -1468,11 +1494,6 @@ let
|
||||
mkForce = mkOverride 50;
|
||||
mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
|
||||
|
||||
defaultPriority =
|
||||
warnIf (oldestSupportedReleaseIsAtLeast 2305)
|
||||
"lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead."
|
||||
defaultOverridePriority;
|
||||
|
||||
mkFixStrictness = warn "lib.mkFixStrictness has no effect and will be removed. It returns its argument unmodified, so you can just remove any calls." id;
|
||||
|
||||
mkOrder = priority: content: {
|
||||
@@ -1787,11 +1808,10 @@ let
|
||||
};
|
||||
|
||||
/**
|
||||
Transitional version of mkAliasOptionModule that uses MD docs.
|
||||
|
||||
This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
|
||||
Deprecated alias of mkAliasOptionModule that uses MD docs.
|
||||
This function is no longer necessary will be removed in 26.05`.
|
||||
*/
|
||||
mkAliasOptionModuleMD = mkAliasOptionModule;
|
||||
mkAliasOptionModuleMD = lib.warn "mkAliasOptionModuleMD is deprecated and will be removed in 26.05; please use mkAliasOptionModule." mkAliasOptionModule;
|
||||
|
||||
/**
|
||||
mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
|
||||
@@ -2163,7 +2183,6 @@ private
|
||||
inherit
|
||||
defaultOrderPriority
|
||||
defaultOverridePriority
|
||||
defaultPriority
|
||||
doRename
|
||||
evalModules
|
||||
evalOptionValue # for use by lib.types
|
||||
|
||||
@@ -684,8 +684,6 @@ rec {
|
||||
inherit text;
|
||||
};
|
||||
|
||||
literalExample = lib.warn "lib.literalExample is deprecated, use lib.literalExpression instead, or use lib.literalMD for a non-Nix description." literalExpression;
|
||||
|
||||
/**
|
||||
For use in the `defaultText` and `example` option attributes. Causes the
|
||||
given MD text to be inserted verbatim in the documentation, for when
|
||||
|
||||
@@ -509,22 +509,6 @@ let
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
pathType =
|
||||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305)
|
||||
"lib.sources.pathType has been moved to lib.filesystem.pathType."
|
||||
lib.filesystem.pathType;
|
||||
|
||||
pathIsDirectory =
|
||||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305)
|
||||
"lib.sources.pathIsDirectory has been moved to lib.filesystem.pathIsDirectory."
|
||||
lib.filesystem.pathIsDirectory;
|
||||
|
||||
pathIsRegularFile =
|
||||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305)
|
||||
"lib.sources.pathIsRegularFile has been moved to lib.filesystem.pathIsRegularFile."
|
||||
lib.filesystem.pathIsRegularFile;
|
||||
|
||||
inherit
|
||||
pathIsGitRepo
|
||||
commitIdFromGitRepo
|
||||
|
||||
@@ -1467,9 +1467,6 @@ rec {
|
||||
[ "\"" "'" "<" ">" "&" ]
|
||||
[ """ "'" "<" ">" "&" ];
|
||||
|
||||
# warning added 12-12-2022
|
||||
replaceChars = lib.warn "lib.replaceChars is a deprecated alias of lib.replaceStrings." builtins.replaceStrings;
|
||||
|
||||
# Case conversion utilities.
|
||||
lowerChars = stringToCharacters "abcdefghijklmnopqrstuvwxyz";
|
||||
upperChars = stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
@@ -2578,30 +2575,6 @@ rec {
|
||||
in
|
||||
lib.warnIf (!precise) "Imprecise conversion from float to string ${result}" result;
|
||||
|
||||
/**
|
||||
Check whether a value `val` can be coerced to a string.
|
||||
|
||||
:::{.warning}
|
||||
Soft-deprecated function. While the original implementation is available as
|
||||
`isConvertibleWithToString`, consider using `isStringLike` instead, if suitable.
|
||||
:::
|
||||
|
||||
# Inputs
|
||||
|
||||
`val`
|
||||
: 1\. Function argument
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
isCoercibleToString :: a -> bool
|
||||
```
|
||||
*/
|
||||
isCoercibleToString =
|
||||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305)
|
||||
"lib.strings.isCoercibleToString is deprecated in favor of either isStringLike or isConvertibleWithToString. Only use the latter if it needs to return true for null, numbers, booleans and list of similarly coercibles."
|
||||
isConvertibleWithToString;
|
||||
|
||||
/**
|
||||
Check whether a list or other value `x` can be passed to toString.
|
||||
|
||||
@@ -2842,60 +2815,6 @@ rec {
|
||||
else
|
||||
parsedInput;
|
||||
|
||||
/**
|
||||
Read a list of paths from `file`, relative to the `rootPath`.
|
||||
Lines beginning with `#` are treated as comments and ignored.
|
||||
Whitespace is significant.
|
||||
|
||||
:::{.warning}
|
||||
This function is deprecated and should be avoided.
|
||||
:::
|
||||
|
||||
:::{.note}
|
||||
This function is not performant and should be avoided.
|
||||
:::
|
||||
|
||||
# Inputs
|
||||
|
||||
`rootPath`
|
||||
: 1\. Function argument
|
||||
|
||||
`file`
|
||||
: 2\. Function argument
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
readPathsFromFile :: string -> string -> [string]
|
||||
```
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `lib.strings.readPathsFromFile` usage example
|
||||
|
||||
```nix
|
||||
readPathsFromFile /prefix
|
||||
./pkgs/development/libraries/qt-5/5.4/qtbase/series
|
||||
=> [ "/prefix/dlopen-resolv.patch" "/prefix/tzdir.patch"
|
||||
"/prefix/dlopen-libXcursor.patch" "/prefix/dlopen-openssl.patch"
|
||||
"/prefix/dlopen-dbus.patch" "/prefix/xdg-config-dirs.patch"
|
||||
"/prefix/nix-profiles-library-paths.patch"
|
||||
"/prefix/compose-search-path.patch" ]
|
||||
```
|
||||
|
||||
:::
|
||||
*/
|
||||
readPathsFromFile = lib.warn "lib.readPathsFromFile is deprecated, use a list instead." (
|
||||
rootPath: file:
|
||||
let
|
||||
lines = lib.splitString "\n" (readFile file);
|
||||
removeComments = lib.filter (line: line != "" && !(lib.hasPrefix "#" line));
|
||||
relativePaths = removeComments lines;
|
||||
absolutePaths = map (path: rootPath + "/${path}") relativePaths;
|
||||
in
|
||||
absolutePaths
|
||||
);
|
||||
|
||||
/**
|
||||
Read the contents of a file removing the trailing \n
|
||||
|
||||
|
||||
@@ -491,6 +491,13 @@ let
|
||||
}
|
||||
.${cpu.name} or cpu.name;
|
||||
vendor_ = final.rust.platform.vendor;
|
||||
abi_ =
|
||||
# We're very explicit about the POWER ELF ABI w/ glibc in our parsing, while Rust is not.
|
||||
# TODO: Somehow ensure that Rust actually *uses* the correct ABI, and not just a libc-based default.
|
||||
if (lib.strings.hasPrefix "powerpc" cpu.name) && (lib.strings.hasPrefix "gnuabielfv" abi.name) then
|
||||
"gnu"
|
||||
else
|
||||
abi.name;
|
||||
in
|
||||
# TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL.
|
||||
args.rust.rustcTarget or args.rustc.config or (
|
||||
@@ -501,7 +508,7 @@ let
|
||||
if final.isWasi then
|
||||
"${cpu_}-wasip1"
|
||||
else
|
||||
"${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi.name}"}"
|
||||
"${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi_}"}"
|
||||
);
|
||||
|
||||
# The name of the rust target if it is standard, or the json file
|
||||
|
||||
@@ -23,7 +23,6 @@ rec {
|
||||
|
||||
ppc64-elfv1 = {
|
||||
config = "powerpc64-unknown-linux-gnuabielfv1";
|
||||
rust.rustcTarget = "powerpc64-unknown-linux-gnu";
|
||||
};
|
||||
ppc64-elfv2 = {
|
||||
config = "powerpc64-unknown-linux-gnuabielfv2";
|
||||
@@ -303,15 +302,6 @@ rec {
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
#
|
||||
# Redox
|
||||
#
|
||||
|
||||
x86_64-unknown-redox = {
|
||||
config = "x86_64-unknown-redox";
|
||||
libc = "relibc";
|
||||
};
|
||||
|
||||
#
|
||||
# Darwin
|
||||
#
|
||||
|
||||
@@ -919,9 +919,9 @@ rec {
|
||||
else if isLinux parsed || isWindows parsed then
|
||||
if isAarch32 parsed then
|
||||
if versionAtLeast (parsed.cpu.version or "0") "6" then abis.gnueabihf else abis.gnueabi
|
||||
# Default ppc64 BE to ELFv2
|
||||
# Default ppc64 BE to ELFv1
|
||||
else if isPower64 parsed && isBigEndian parsed then
|
||||
abis.gnuabielfv2
|
||||
abis.gnuabielfv1
|
||||
else
|
||||
abis.gnu
|
||||
else
|
||||
|
||||
@@ -3106,6 +3106,86 @@ runTests {
|
||||
expected = "-X PUT --data '{\"id\":0}' --retry 3 --url https://example.com/foo --url https://example.com/bar --verbose";
|
||||
};
|
||||
|
||||
testToCommandLine = {
|
||||
expr =
|
||||
let
|
||||
optionFormat = optionName: {
|
||||
option = "-${optionName}";
|
||||
sep = "=";
|
||||
explicitBool = true;
|
||||
};
|
||||
in
|
||||
cli.toCommandLine optionFormat {
|
||||
v = true;
|
||||
verbose = [
|
||||
true
|
||||
true
|
||||
false
|
||||
null
|
||||
];
|
||||
i = ".bak";
|
||||
testsuite = [
|
||||
"unit"
|
||||
"integration"
|
||||
];
|
||||
e = [
|
||||
"s/a/b/"
|
||||
"s/b/c/"
|
||||
];
|
||||
n = false;
|
||||
data = builtins.toJSON { id = 0; };
|
||||
};
|
||||
|
||||
expected = [
|
||||
"-data={\"id\":0}"
|
||||
"-e=s/a/b/"
|
||||
"-e=s/b/c/"
|
||||
"-i=.bak"
|
||||
"-n=false"
|
||||
"-testsuite=unit"
|
||||
"-testsuite=integration"
|
||||
"-v=true"
|
||||
"-verbose=true"
|
||||
"-verbose=true"
|
||||
"-verbose=false"
|
||||
];
|
||||
};
|
||||
|
||||
testToCommandLineGNU = {
|
||||
expr = cli.toCommandLineGNU { } {
|
||||
v = true;
|
||||
verbose = [
|
||||
true
|
||||
true
|
||||
false
|
||||
null
|
||||
];
|
||||
i = ".bak";
|
||||
testsuite = [
|
||||
"unit"
|
||||
"integration"
|
||||
];
|
||||
e = [
|
||||
"s/a/b/"
|
||||
"s/b/c/"
|
||||
];
|
||||
n = false;
|
||||
data = builtins.toJSON { id = 0; };
|
||||
};
|
||||
|
||||
expected = [
|
||||
"--data={\"id\":0}"
|
||||
"-es/a/b/"
|
||||
"-es/b/c/"
|
||||
"-i.bak"
|
||||
"--testsuite=unit"
|
||||
"--testsuite=integration"
|
||||
"-v"
|
||||
"--verbose"
|
||||
"--verbose"
|
||||
];
|
||||
};
|
||||
|
||||
testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
|
||||
name = "..foo";
|
||||
expected = "foo";
|
||||
@@ -4661,4 +4741,82 @@ runTests {
|
||||
expected = "/non-existent/this/does/not/exist/for/real/please-dont-mess-with-your-local-fs/default.nix";
|
||||
};
|
||||
|
||||
# Tests for cross index utilities
|
||||
|
||||
testRenameCrossIndexFrom = {
|
||||
expr = lib.renameCrossIndexFrom "pkgs" {
|
||||
pkgsBuildBuild = "dummy-build-build";
|
||||
pkgsBuildHost = "dummy-build-host";
|
||||
pkgsBuildTarget = "dummy-build-target";
|
||||
pkgsHostHost = "dummy-host-host";
|
||||
pkgsHostTarget = "dummy-host-target";
|
||||
pkgsTargetTarget = "dummy-target-target";
|
||||
};
|
||||
expected = {
|
||||
buildBuild = "dummy-build-build";
|
||||
buildHost = "dummy-build-host";
|
||||
buildTarget = "dummy-build-target";
|
||||
hostHost = "dummy-host-host";
|
||||
hostTarget = "dummy-host-target";
|
||||
targetTarget = "dummy-target-target";
|
||||
};
|
||||
};
|
||||
|
||||
testRenameCrossIndexTo = {
|
||||
expr = lib.renameCrossIndexTo "self" {
|
||||
buildBuild = "dummy-build-build";
|
||||
buildHost = "dummy-build-host";
|
||||
buildTarget = "dummy-build-target";
|
||||
hostHost = "dummy-host-host";
|
||||
hostTarget = "dummy-host-target";
|
||||
targetTarget = "dummy-target-target";
|
||||
};
|
||||
expected = {
|
||||
selfBuildBuild = "dummy-build-build";
|
||||
selfBuildHost = "dummy-build-host";
|
||||
selfBuildTarget = "dummy-build-target";
|
||||
selfHostHost = "dummy-host-host";
|
||||
selfHostTarget = "dummy-host-target";
|
||||
selfTargetTarget = "dummy-target-target";
|
||||
};
|
||||
};
|
||||
|
||||
testMapCrossIndex = {
|
||||
expr = lib.mapCrossIndex (x: x * 10) {
|
||||
buildBuild = 1;
|
||||
buildHost = 2;
|
||||
buildTarget = 3;
|
||||
hostHost = 4;
|
||||
hostTarget = 5;
|
||||
targetTarget = 6;
|
||||
};
|
||||
expected = {
|
||||
buildBuild = 10;
|
||||
buildHost = 20;
|
||||
buildTarget = 30;
|
||||
hostHost = 40;
|
||||
hostTarget = 50;
|
||||
targetTarget = 60;
|
||||
};
|
||||
};
|
||||
|
||||
testMapCrossIndexString = {
|
||||
expr = lib.mapCrossIndex (x: "prefix-${x}") {
|
||||
buildBuild = "bb";
|
||||
buildHost = "bh";
|
||||
buildTarget = "bt";
|
||||
hostHost = "hh";
|
||||
hostTarget = "ht";
|
||||
targetTarget = "tt";
|
||||
};
|
||||
expected = {
|
||||
buildBuild = "prefix-bb";
|
||||
buildHost = "prefix-bh";
|
||||
buildTarget = "prefix-bt";
|
||||
hostHost = "prefix-hh";
|
||||
hostTarget = "prefix-ht";
|
||||
targetTarget = "prefix-tt";
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -223,6 +223,26 @@ checkConfigError 'A definition for option .* is not of type .path in the Nix sto
|
||||
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: ".*/store/.links"' config.pathInStore.bad4 ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: "/foo/bar"' config.pathInStore.bad5 ./types.nix
|
||||
|
||||
# types.externalPath
|
||||
checkConfigOutput '".*/foo/bar"' config.externalPath.ok1 ./types.nix
|
||||
checkConfigOutput '".*/"' config.externalPath.ok2 ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad1 ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad2 ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad3 ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad4 ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .absolute path not in the Nix store.' config.externalPath.bad5 ./types.nix
|
||||
|
||||
# types.fileset
|
||||
checkConfigOutput '^0$' config.filesetCardinal.ok1 ./fileset.nix
|
||||
checkConfigOutput '^1$' config.filesetCardinal.ok2 ./fileset.nix
|
||||
checkConfigOutput '^1$' config.filesetCardinal.ok3 ./fileset.nix
|
||||
checkConfigOutput '^1$' config.filesetCardinal.ok4 ./fileset.nix
|
||||
checkConfigOutput '^0$' config.filesetCardinal.ok5 ./fileset.nix
|
||||
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err1 ./fileset.nix
|
||||
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err2 ./fileset.nix
|
||||
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err3 ./fileset.nix
|
||||
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err4 ./fileset.nix
|
||||
|
||||
# Check boolean option.
|
||||
checkConfigOutput '^false$' config.enable ./declare-enable.nix
|
||||
checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*: true' config.enable ./define-enable.nix
|
||||
@@ -806,6 +826,25 @@ checkConfigError 'A definition for option .* is not of type .signed integer.*' c
|
||||
checkConfigOutput '^true$' config.v2checkedPass ./add-check.nix
|
||||
checkConfigError 'A definition for option .* is not of type .attribute set of signed integer.*' config.v2checkedFail ./add-check.nix
|
||||
|
||||
# v2 merge check coherence
|
||||
# Tests checkV2MergeCoherence call in modules.nix (mergeDefinitions for lazyAttrsOf)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.adhocFail.foo ./v2-check-coherence.nix
|
||||
# Tests checkV2MergeCoherence call in modules.nix (mergeDefinitions for lazyAttrsOf)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.adhocOuterFail.bar ./v2-check-coherence.nix
|
||||
# Tests checkV2MergeCoherence call in types.nix (either t1)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.eitherLeftFail ./v2-check-coherence.nix
|
||||
# Tests checkV2MergeCoherence call in types.nix (either t2)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.eitherRightFail ./v2-check-coherence.nix
|
||||
# Tests checkV2MergeCoherence call in types.nix (coercedTo coercedType)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.coercedFromFail.bar ./v2-check-coherence.nix
|
||||
# Tests checkV2MergeCoherence call in types.nix (coercedTo finalType)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.coercedToFail.foo ./v2-check-coherence.nix
|
||||
# Tests checkV2MergeCoherence call in types.nix (addCheck elemType)
|
||||
checkConfigError 'ad-hoc.*override.*incompatible' config.addCheckNested.foo ./v2-check-coherence.nix
|
||||
checkConfigError 'Please use.*lib.types.addCheck.*instead' config.adhocFail.foo ./v2-check-coherence.nix
|
||||
checkConfigError 'A definition for option .* is not of type .*' config.addCheckFail.bar.baz ./v2-check-coherence.nix
|
||||
checkConfigOutput '^true$' config.result ./v2-check-coherence.nix
|
||||
|
||||
|
||||
cat <<EOF
|
||||
====== module tests ======
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
mkIf
|
||||
types
|
||||
mapAttrs
|
||||
length
|
||||
;
|
||||
inherit (lib.fileset)
|
||||
empty
|
||||
unions
|
||||
toList
|
||||
;
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
fileset = mkOption { type = with types; lazyAttrsOf fileset; };
|
||||
|
||||
## The following option is only here as a proxy to test `fileset` that does
|
||||
## not work so well with `modules.sh` because it is not JSONable. It exposes
|
||||
## the number of elements in the fileset.
|
||||
filesetCardinal = mkOption { default = mapAttrs (_: fs: length (toList fs)) config.fileset; };
|
||||
};
|
||||
|
||||
config = {
|
||||
fileset.ok1 = empty;
|
||||
fileset.ok2 = ./fileset;
|
||||
fileset.ok3 = unions [
|
||||
empty
|
||||
./fileset
|
||||
];
|
||||
# fileset.ok4: see imports below
|
||||
fileset.ok5 = mkIf false ./fileset;
|
||||
|
||||
fileset.err1 = 1;
|
||||
fileset.err2 = "foo";
|
||||
fileset.err3 = "./.";
|
||||
fileset.err4 = [ empty ];
|
||||
|
||||
};
|
||||
|
||||
imports = [
|
||||
{ fileset.ok4 = ./fileset; }
|
||||
{ fileset.ok4 = empty; }
|
||||
{ fileset.ok4 = ./fileset; }
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Do not remove. This file is used by the tests in `../fileset.nix`.
|
||||
@@ -15,6 +15,7 @@ in
|
||||
{
|
||||
options = {
|
||||
pathInStore = mkOption { type = types.lazyAttrsOf types.pathInStore; };
|
||||
externalPath = mkOption { type = types.lazyAttrsOf types.externalPath; };
|
||||
assertions = mkOption { };
|
||||
};
|
||||
config = {
|
||||
@@ -26,6 +27,13 @@ in
|
||||
pathInStore.bad3 = "${storeDir}/";
|
||||
pathInStore.bad4 = "${storeDir}/.links"; # technically true, but not reasonable
|
||||
pathInStore.bad5 = "/foo/bar";
|
||||
externalPath.bad1 = "${storeDir}/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv";
|
||||
externalPath.bad2 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15";
|
||||
externalPath.bad3 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash";
|
||||
externalPath.bad4 = "";
|
||||
externalPath.bad5 = "./foo/bar";
|
||||
externalPath.ok1 = "/foo/bar";
|
||||
externalPath.ok2 = "/";
|
||||
|
||||
assertions =
|
||||
with lib.types;
|
||||
@@ -380,7 +388,7 @@ in
|
||||
assert (pathWith { absolute = null; }).description == "path";
|
||||
assert (pathWith { inStore = false; }).description == "path not in the Nix store";
|
||||
assert (pathWith { inStore = null; }).description == "path";
|
||||
assert (separatedString "").description == "Concatenated string";
|
||||
assert (separatedString "").description == "strings concatenated with \"\"";
|
||||
assert (separatedString ",").description == "strings concatenated with \",\"";
|
||||
assert (separatedString "\n").description == ''strings concatenated with "\n"'';
|
||||
assert (separatedString ":").description == "strings concatenated with \":\"";
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# Tests for v2 merge check coherence
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib) types mkOption;
|
||||
|
||||
# The problematic pattern: overriding check with //
|
||||
# This inner type should reject everything (check always returns false)
|
||||
adhocOverrideType = (types.lazyAttrsOf types.raw) // {
|
||||
check = _: false;
|
||||
};
|
||||
|
||||
# Using addCheck is the correct way to add custom checks
|
||||
properlyCheckedType = types.addCheck (types.lazyAttrsOf types.raw) (v: v ? foo);
|
||||
|
||||
# Using addCheck with a check that will fail
|
||||
failingCheckedType = types.addCheck (types.lazyAttrsOf types.raw) (v: v ? foo);
|
||||
|
||||
# Ad-hoc override on outer type
|
||||
adhocOuterType = types.lazyAttrsOf types.int // {
|
||||
check = _: false;
|
||||
};
|
||||
|
||||
# Ad-hoc override on left side of either
|
||||
adhocEitherLeft = types.lazyAttrsOf types.raw // {
|
||||
check = _: false;
|
||||
};
|
||||
|
||||
# Ad-hoc override on coercedType in coercedTo
|
||||
adhocCoercedFrom = types.lazyAttrsOf types.raw // {
|
||||
check = _: false;
|
||||
};
|
||||
|
||||
# Ad-hoc override on finalType in coercedTo
|
||||
adhocCoercedTo = types.lazyAttrsOf types.raw // {
|
||||
check = _: false;
|
||||
};
|
||||
|
||||
# Ad-hoc override wrapped in addCheck
|
||||
adhocAddCheck = types.addCheck (types.lazyAttrsOf types.raw // { check = _: false; }) (v: true);
|
||||
in
|
||||
{
|
||||
# Test 1: Ad-hoc check override in nested type should be detected
|
||||
options.adhocFail = mkOption {
|
||||
type = types.lazyAttrsOf adhocOverrideType;
|
||||
default = { };
|
||||
};
|
||||
config.adhocFail = {
|
||||
foo = { };
|
||||
};
|
||||
|
||||
# Test 1b: Ad-hoc check override in outer type should be detected
|
||||
options.adhocOuterFail = mkOption {
|
||||
type = adhocOuterType;
|
||||
default = { };
|
||||
};
|
||||
config.adhocOuterFail.bar = 42;
|
||||
|
||||
# Test 1c: Ad-hoc check override on left side of either type
|
||||
options.eitherLeftFail = mkOption {
|
||||
type = types.either adhocEitherLeft types.int;
|
||||
};
|
||||
config.eitherLeftFail.foo = { };
|
||||
|
||||
# Test 1d: Ad-hoc check override on right side of either type
|
||||
options.eitherRightFail = mkOption {
|
||||
type = types.either types.int (types.lazyAttrsOf types.raw // { check = _: false; });
|
||||
};
|
||||
config.eitherRightFail.foo = { };
|
||||
|
||||
# Test 1e: Ad-hoc check override on coercedType in coercedTo
|
||||
options.coercedFromFail = mkOption {
|
||||
type = types.coercedTo adhocCoercedFrom (x: { bar = 1; }) (types.lazyAttrsOf types.int);
|
||||
};
|
||||
config.coercedFromFail = {
|
||||
foo = { };
|
||||
};
|
||||
|
||||
# Test 1f: Ad-hoc check override on finalType in coercedTo
|
||||
options.coercedToFail = mkOption {
|
||||
type = types.coercedTo types.str (x: { }) adhocCoercedTo;
|
||||
};
|
||||
config.coercedToFail.foo = { };
|
||||
|
||||
# Test 1g: Ad-hoc check override wrapped in addCheck
|
||||
options.addCheckNested = mkOption {
|
||||
type = adhocAddCheck;
|
||||
};
|
||||
config.addCheckNested.foo = { };
|
||||
|
||||
# Test 2: Using addCheck should work correctly
|
||||
options.addCheckPass = mkOption {
|
||||
type = types.lazyAttrsOf properlyCheckedType;
|
||||
default = { };
|
||||
};
|
||||
config.addCheckPass.bar.foo = "value";
|
||||
|
||||
# Test 3: addCheck should validate values properly
|
||||
options.addCheckFail = mkOption {
|
||||
type = types.lazyAttrsOf failingCheckedType;
|
||||
default = { };
|
||||
};
|
||||
config.addCheckFail.bar.baz = "value"; # Missing required 'foo' attribute
|
||||
|
||||
# Test 4: Normal v2 types should work without coherence errors
|
||||
options.normalPass = mkOption {
|
||||
type = types.lazyAttrsOf (types.attrsOf types.int);
|
||||
default = { };
|
||||
};
|
||||
config.normalPass.foo.bar = 42;
|
||||
|
||||
# Success assertion - only checks things that should succeed
|
||||
options.result = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
config.result = true;
|
||||
}
|
||||
+9
-1
@@ -24,13 +24,21 @@ let
|
||||
default = false;
|
||||
};
|
||||
members = lib.mkOption {
|
||||
type = types.listOf (types.submodule (import ./maintainer-module.nix { inherit lib; }));
|
||||
type = types.listOf (types.submodule ./maintainer-module.nix);
|
||||
default = [ ];
|
||||
};
|
||||
github = lib.mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
githubId = lib.mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
};
|
||||
githubMaintainers = lib.mkOption {
|
||||
type = types.listOf (types.submodule ./maintainer-module.nix);
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+87
-36
@@ -66,6 +66,11 @@ let
|
||||
fixupOptionType
|
||||
mergeOptionDecls
|
||||
;
|
||||
inherit (lib.fileset)
|
||||
isFileset
|
||||
unions
|
||||
empty
|
||||
;
|
||||
|
||||
inAttrPosSuffix =
|
||||
v: name:
|
||||
@@ -106,6 +111,29 @@ let
|
||||
in
|
||||
if invalidDefs != [ ] then { message = "Definition values: ${showDefs invalidDefs}"; } else null;
|
||||
|
||||
# Check that a type with v2 merge has a coherent check attribute.
|
||||
# Throws an error if the type uses an ad-hoc `type // { check }` override.
|
||||
# Returns the last argument like `seq`, allowing usage: checkV2MergeCoherence loc type expr
|
||||
checkV2MergeCoherence =
|
||||
loc: type: result:
|
||||
if type.check.isV2MergeCoherent or false then
|
||||
result
|
||||
else
|
||||
throw ''
|
||||
The option `${showOption loc}' has a type `${type.description}' that uses
|
||||
an ad-hoc `type // { check = ...; }' override, which is incompatible with
|
||||
the v2 merge mechanism.
|
||||
|
||||
Please use `lib.types.addCheck` instead of `type // { check }' to add
|
||||
custom validation. For example:
|
||||
|
||||
lib.types.addCheck baseType (value: /* your check */)
|
||||
|
||||
instead of:
|
||||
|
||||
baseType // { check = value: /* your check */; }
|
||||
'';
|
||||
|
||||
outer_types = rec {
|
||||
isType = type: x: (x._type or "") == type;
|
||||
|
||||
@@ -559,11 +587,7 @@ let
|
||||
sep:
|
||||
mkOptionType rec {
|
||||
name = "separatedString";
|
||||
description =
|
||||
if sep == "" then
|
||||
"Concatenated string" # for types.string.
|
||||
else
|
||||
"strings concatenated with ${builtins.toJSON sep}";
|
||||
description = "strings concatenated with ${builtins.toJSON sep}";
|
||||
descriptionClass = "noun";
|
||||
check = isString;
|
||||
merge = loc: defs: concatStringsSep sep (getValues defs);
|
||||
@@ -578,19 +602,6 @@ let
|
||||
commas = separatedString ",";
|
||||
envVar = separatedString ":";
|
||||
|
||||
# Deprecated; should not be used because it quietly concatenates
|
||||
# strings, which is usually not what you want.
|
||||
# We use a lib.warn because `deprecationMessage` doesn't trigger in nested types such as `attrsOf string`
|
||||
string =
|
||||
lib.warn
|
||||
"The type `types.string` is deprecated. See https://github.com/NixOS/nixpkgs/pull/66346 for better alternative types."
|
||||
(
|
||||
separatedString ""
|
||||
// {
|
||||
name = "string";
|
||||
}
|
||||
);
|
||||
|
||||
passwdEntry =
|
||||
entryType:
|
||||
addCheck entryType (str: !(hasInfix ":" str || hasInfix "\n" str))
|
||||
@@ -612,6 +623,15 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
fileset = mkOptionType {
|
||||
name = "fileset";
|
||||
description = "fileset";
|
||||
descriptionClass = "noun";
|
||||
check = isFileset;
|
||||
merge = loc: defs: unions (map (x: x.value) defs);
|
||||
emptyValue.value = empty;
|
||||
};
|
||||
|
||||
# A package is a top-level store path (/nix/store/hash-name). This includes:
|
||||
# - derivations
|
||||
# - more generally, attribute sets with an `outPath` or `__toString` attribute
|
||||
@@ -656,6 +676,11 @@ let
|
||||
inStore = true;
|
||||
};
|
||||
|
||||
externalPath = pathWith {
|
||||
absolute = true;
|
||||
inStore = false;
|
||||
};
|
||||
|
||||
pathWith =
|
||||
{
|
||||
inStore ? null,
|
||||
@@ -711,7 +736,10 @@ let
|
||||
optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType
|
||||
}";
|
||||
descriptionClass = "composite";
|
||||
check = isList;
|
||||
check = {
|
||||
__functor = _self: isList;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
merge = {
|
||||
__functor =
|
||||
self: loc: defs:
|
||||
@@ -824,7 +852,10 @@ let
|
||||
(if lazy then "lazy attribute set" else "attribute set")
|
||||
+ " of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
||||
descriptionClass = "composite";
|
||||
check = isAttrs;
|
||||
check = {
|
||||
__functor = _self: isAttrs;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
merge = {
|
||||
__functor =
|
||||
self: loc: defs:
|
||||
@@ -1236,7 +1267,10 @@ let
|
||||
|
||||
name = "submodule";
|
||||
|
||||
check = x: isAttrs x || isFunction x || path.check x;
|
||||
check = {
|
||||
__functor = _self: x: isAttrs x || isFunction x || path.check x;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
in
|
||||
mkOptionType {
|
||||
inherit name;
|
||||
@@ -1420,7 +1454,10 @@ let
|
||||
) t2
|
||||
}";
|
||||
descriptionClass = "conjunction";
|
||||
check = x: t1.check x || t2.check x;
|
||||
check = {
|
||||
__functor = _self: x: t1.check x || t2.check x;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
merge = {
|
||||
__functor =
|
||||
self: loc: defs:
|
||||
@@ -1430,7 +1467,7 @@ let
|
||||
let
|
||||
t1CheckedAndMerged =
|
||||
if t1.merge ? v2 then
|
||||
t1.merge.v2 { inherit loc defs; }
|
||||
checkV2MergeCoherence loc t1 (t1.merge.v2 { inherit loc defs; })
|
||||
else
|
||||
{
|
||||
value = t1.merge loc defs;
|
||||
@@ -1439,7 +1476,7 @@ let
|
||||
};
|
||||
t2CheckedAndMerged =
|
||||
if t2.merge ? v2 then
|
||||
t2.merge.v2 { inherit loc defs; }
|
||||
checkV2MergeCoherence loc t2 (t2.merge.v2 { inherit loc defs; })
|
||||
else
|
||||
{
|
||||
value = t2.merge loc defs;
|
||||
@@ -1464,7 +1501,7 @@ let
|
||||
One or more definitions did not pass the type-check of the 'either' type.
|
||||
${headError.message}
|
||||
If `either`, `oneOf` or similar is used in freeformType, ensure that it is preceded by an 'attrsOf' such as: `freeformType = types.attrsOf (types.either t1 t2)`.
|
||||
Otherwise consider using the correct type for the option `${showOption loc}`. This will be an error in Nixpkgs 26.06.
|
||||
Otherwise consider using the correct type for the option `${showOption loc}`. This will be an error in Nixpkgs 26.05.
|
||||
'' (mergeOneOption loc defs);
|
||||
};
|
||||
in
|
||||
@@ -1509,7 +1546,10 @@ let
|
||||
description = "${optionDescriptionPhrase (class: class == "noun") finalType} or ${
|
||||
optionDescriptionPhrase (class: class == "noun") coercedType
|
||||
} convertible to it";
|
||||
check = x: (coercedType.check x && finalType.check (coerceFunc x)) || finalType.check x;
|
||||
check = {
|
||||
__functor = _self: x: (coercedType.check x && finalType.check (coerceFunc x)) || finalType.check x;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
merge = {
|
||||
__functor =
|
||||
self: loc: defs:
|
||||
@@ -1524,10 +1564,16 @@ let
|
||||
// {
|
||||
value =
|
||||
let
|
||||
merged = coercedType.merge.v2 {
|
||||
inherit loc;
|
||||
defs = [ def ];
|
||||
};
|
||||
merged =
|
||||
if coercedType.merge ? v2 then
|
||||
checkV2MergeCoherence loc coercedType (
|
||||
coercedType.merge.v2 {
|
||||
inherit loc;
|
||||
defs = [ def ];
|
||||
}
|
||||
)
|
||||
else
|
||||
null;
|
||||
in
|
||||
if coercedType.merge ? v2 then
|
||||
if merged.headError == null then coerceFunc def.value else def.value
|
||||
@@ -1540,10 +1586,12 @@ let
|
||||
);
|
||||
in
|
||||
if finalType.merge ? v2 then
|
||||
finalType.merge.v2 {
|
||||
inherit loc;
|
||||
defs = finalDefs;
|
||||
}
|
||||
checkV2MergeCoherence loc finalType (
|
||||
finalType.merge.v2 {
|
||||
inherit loc;
|
||||
defs = finalDefs;
|
||||
}
|
||||
)
|
||||
else
|
||||
{
|
||||
value = finalType.merge loc finalDefs;
|
||||
@@ -1576,7 +1624,10 @@ let
|
||||
if elemType.merge ? v2 then
|
||||
elemType
|
||||
// {
|
||||
check = x: elemType.check x && check x;
|
||||
check = {
|
||||
__functor = _self: x: elemType.check x && check x;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
merge = {
|
||||
__functor =
|
||||
self: loc: defs:
|
||||
@@ -1584,7 +1635,7 @@ let
|
||||
v2 =
|
||||
{ loc, defs }:
|
||||
let
|
||||
orig = elemType.merge.v2 { inherit loc defs; };
|
||||
orig = checkV2MergeCoherence loc elemType (elemType.merge.v2 { inherit loc defs; });
|
||||
headError' = if orig.headError != null then orig.headError else checkDefsForError check loc defs;
|
||||
in
|
||||
orig
|
||||
|
||||
@@ -32,7 +32,7 @@ Commit access to the Nixpkgs repository is not required for that.
|
||||
In order to do so, add yourself to the [`maintainer-list.nix`](./maintainer-list.nix), and then to the desired package's `meta.maintainers` list, and send a PR with the changes.
|
||||
|
||||
If you're adding yourself as a maintainer as part of another PR (in which you become a maintainer of a package, for example), make your change to
|
||||
`maintainer-list.nix` in a separate commit titled `maintainers: add <name>`.
|
||||
`maintainer-list.nix` in a separate commit titled `maintainers: add <handle>`.
|
||||
|
||||
### Losing maintainer status
|
||||
|
||||
@@ -158,13 +158,17 @@ If the team lists no specific membership policy, feel free to merge changes to t
|
||||
> [!IMPORTANT]
|
||||
> If a team says it is a closed group, do not merge additions to the team without an approval by at least one existing member.
|
||||
|
||||
A corresponding GitHub team can be created by any org member.
|
||||
#### Synced GitHub teams
|
||||
|
||||
As an alternative to tracking team members in `team-list.nix`, a corresponding GitHub team can be created by any org member and its members subsequently managed directly on GitHub.
|
||||
When creating the team it should be created with the `nixpkgs-maintainers` team as parent.
|
||||
Once approved, the team will have the right privileges to be pinged and requested for review in Nixpkgs.
|
||||
|
||||
> [!TIP]
|
||||
> The team name should be as short as possible; because it is nested under the maintainers group, no -maintainers suffix is needed.
|
||||
|
||||
After the first [weekly team sync](../.github/workflows/team-sync.yml) with the new team, it's then also possible to link it to the entry in `team-list.nix` by setting its `github` field to the GitHub team name.
|
||||
|
||||
# Maintainer scripts
|
||||
|
||||
Various utility scripts, which are mainly useful for nixpkgs maintainers, are available under `./scripts/`.
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Extends ./team-list.nix with synced GitHub information from ./github-teams.json
|
||||
{ lib }:
|
||||
let
|
||||
githubTeams = lib.importJSON ./github-teams.json;
|
||||
teams = import ./team-list.nix { inherit lib; };
|
||||
|
||||
# A fast maintainer id lookup table
|
||||
maintainersById = lib.pipe lib.maintainers [
|
||||
lib.attrValues
|
||||
(lib.groupBy (attrs: toString attrs.githubId))
|
||||
(lib.mapAttrs (_: lib.head))
|
||||
];
|
||||
|
||||
maintainerSetToList =
|
||||
githubTeam:
|
||||
lib.mapAttrsToList (
|
||||
login: id:
|
||||
maintainersById.${toString id}
|
||||
or (throw "lib.teams: No maintainer entry for GitHub user @${login} who's part of the @NixOS/${githubTeam} team")
|
||||
);
|
||||
|
||||
in
|
||||
# TODO: Consider automatically exposing all GitHub teams under `lib.teams`,
|
||||
# so that no manual PRs are necessary to add such teams anymore
|
||||
lib.mapAttrs (
|
||||
name: attrs:
|
||||
if attrs ? github then
|
||||
let
|
||||
githubTeam =
|
||||
githubTeams.${attrs.github}
|
||||
or (throw "lib.teams.${name}: Corresponding GitHub team ${attrs.github} not known yet, make sure to create it and wait for the regular team sync");
|
||||
in
|
||||
# TODO: Consider specifying `githubId` in team-list.nix and inferring `github` from it (or even dropping it)
|
||||
# This would make renames easier because no additional place needs to keep track of them.
|
||||
# Though in a future where all Nixpkgs GitHub teams are automatically exposed under `lib.teams`,
|
||||
# this would also not be an issue anymore.
|
||||
assert lib.assertMsg (!attrs ? githubId)
|
||||
"lib.teams.${name}: Both `githubId` and `github` is set, but the former is synced from the latter";
|
||||
assert lib.assertMsg (!attrs ? shortName)
|
||||
"lib.teams.${name}: Both `shortName` and `github` is set, but the former is synced from the latter";
|
||||
assert lib.assertMsg (
|
||||
!attrs ? scope
|
||||
) "lib.teams.${name}: Both `scope` and `github` is set, but the former is synced from the latter";
|
||||
assert lib.assertMsg (
|
||||
!attrs ? members
|
||||
) "lib.teams.${name}: Both `members` and `github` is set, but the former is synced from the latter";
|
||||
attrs
|
||||
// {
|
||||
githubId = githubTeam.id;
|
||||
shortName = githubTeam.name;
|
||||
scope = githubTeam.description;
|
||||
members =
|
||||
maintainerSetToList attrs.github githubTeam.maintainers
|
||||
++ maintainerSetToList attrs.github githubTeam.members;
|
||||
githubMaintainers = maintainerSetToList attrs.github githubTeam.maintainers;
|
||||
}
|
||||
else
|
||||
attrs
|
||||
) teams
|
||||
@@ -0,0 +1,985 @@
|
||||
{
|
||||
"acme": {
|
||||
"description": "Maintain ACME-related packages and modules.",
|
||||
"id": 3806126,
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"arianvp": 628387,
|
||||
"emilazy": 18535642,
|
||||
"m1cr0man": 3044438
|
||||
},
|
||||
"name": "ACME"
|
||||
},
|
||||
"agda": {
|
||||
"description": "Maintain Agda-related packages and modules",
|
||||
"id": 14416551,
|
||||
"maintainers": {
|
||||
"alexarice": 17208985,
|
||||
"ncfavier": 4323933,
|
||||
"turion": 303489
|
||||
},
|
||||
"members": {
|
||||
"phijor": 10487782
|
||||
},
|
||||
"name": "agda"
|
||||
},
|
||||
"android": {
|
||||
"description": "Maintain Android-related tooling in nixpkgs",
|
||||
"id": 11821955,
|
||||
"maintainers": {
|
||||
"RossComputerGuy": 19699320,
|
||||
"numinit": 369111
|
||||
},
|
||||
"members": {
|
||||
"JohnRTitor": 50095635,
|
||||
"adrian-gierakowski": 330177,
|
||||
"hadilq": 5190539
|
||||
},
|
||||
"name": "Android"
|
||||
},
|
||||
"bazel": {
|
||||
"description": "Maintenance of https://bazel.build/ and related packages",
|
||||
"id": 5468470,
|
||||
"maintainers": {
|
||||
"Profpatsch": 3153638
|
||||
},
|
||||
"members": {
|
||||
"aherrmann": 732652,
|
||||
"avdv": 3471749,
|
||||
"ethercrow": 222467,
|
||||
"groodt": 343415,
|
||||
"kalbasit": 87115,
|
||||
"mboes": 51356,
|
||||
"uri-canva": 33242106
|
||||
},
|
||||
"name": "Bazel"
|
||||
},
|
||||
"beam": {
|
||||
"description": "Maintain BEAM-related packages and modules.",
|
||||
"id": 4502493,
|
||||
"maintainers": {
|
||||
"happysalada": 5317234
|
||||
},
|
||||
"members": {
|
||||
"Br1ght0ne": 12615679,
|
||||
"DianaOlympos": 15774340,
|
||||
"adamcstephens": 2071575,
|
||||
"ankhers": 750786,
|
||||
"gleber": 33185,
|
||||
"minijackson": 1200507,
|
||||
"savtrip": 42227195,
|
||||
"yurrriq": 1866448
|
||||
},
|
||||
"name": "Beam"
|
||||
},
|
||||
"bootstrapping": {
|
||||
"description": "coordinates efforts towards bootstrappable builds (see https://bootstrappable.org/)",
|
||||
"id": 9141350,
|
||||
"maintainers": {
|
||||
"zeuner": 2545850
|
||||
},
|
||||
"members": {
|
||||
"philiptaron": 43863
|
||||
},
|
||||
"name": "bootstrapping"
|
||||
},
|
||||
"categorization": {
|
||||
"description": "Maintain the categorization system in Nixpkgs, per RFC 0146. This team has authority over all categorization issues in Nixpkgs. Matrix: https://matrix.to/#/%23nixpkgs-categorization:matrix.org",
|
||||
"id": 11723948,
|
||||
"maintainers": {
|
||||
"7c6f434c": 1891350,
|
||||
"Aleksanaa": 42209822,
|
||||
"GetPsyched": 43472218,
|
||||
"Lyndeno": 13490857,
|
||||
"SigmaSquadron": 174749595,
|
||||
"fgaz": 8182846,
|
||||
"natsukium": 25083790,
|
||||
"philiptaron": 43863,
|
||||
"pyrotelekinetic": 29682759,
|
||||
"tomodachi94": 68489118
|
||||
},
|
||||
"members": {},
|
||||
"name": "Categorization"
|
||||
},
|
||||
"channel-updaters": {
|
||||
"description": "Users who can update the Nixpkgs/NixOS channels",
|
||||
"id": 3475569,
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"nixos-channel-bot": 56695723
|
||||
},
|
||||
"name": "channel-updaters"
|
||||
},
|
||||
"coq": {
|
||||
"description": "Coq proof assistant and package maintainers",
|
||||
"id": 7617261,
|
||||
"maintainers": {
|
||||
"Alizter": 8614547,
|
||||
"Zimmi48": 1108325,
|
||||
"vbgl": 2612464
|
||||
},
|
||||
"members": {},
|
||||
"name": "Coq"
|
||||
},
|
||||
"cosmic": {
|
||||
"description": "Maintain the COSMIC DE and related packages.",
|
||||
"id": 12734494,
|
||||
"maintainers": {
|
||||
"alyssais": 2768870,
|
||||
"nyabinary": 97130632
|
||||
},
|
||||
"members": {
|
||||
"HeitorAugustoLN": 44377258,
|
||||
"Pandapip1": 45835846,
|
||||
"a-kenji": 65275785,
|
||||
"ahoneybun": 4884946,
|
||||
"drakon64": 6444703,
|
||||
"michaelBelsanti": 62124625,
|
||||
"thefossguy": 44400303
|
||||
},
|
||||
"name": "COSMIC"
|
||||
},
|
||||
"crystal-lang": {
|
||||
"description": "The Crystal Lang eco-system",
|
||||
"id": 3806663,
|
||||
"maintainers": {
|
||||
"peterhoeg": 722550
|
||||
},
|
||||
"members": {
|
||||
"Br1ght0ne": 12615679,
|
||||
"manveru": 3507
|
||||
},
|
||||
"name": "crystal-lang"
|
||||
},
|
||||
"cuda-maintainers": {
|
||||
"description": "Maintain CUDA-enabled packages",
|
||||
"id": 5704451,
|
||||
"maintainers": {
|
||||
"ConnorBaker": 3880346,
|
||||
"SomeoneSerge": 9720532,
|
||||
"samuela": 226872
|
||||
},
|
||||
"members": {
|
||||
"GaetanLepage": 33058747,
|
||||
"prusnak": 42201
|
||||
},
|
||||
"name": "cuda-maintainers"
|
||||
},
|
||||
"darwin-core": {
|
||||
"description": "Maintain core platform support and packages for macOS and other Apple platforms",
|
||||
"id": 11265438,
|
||||
"maintainers": {
|
||||
"emilazy": 18535642
|
||||
},
|
||||
"members": {
|
||||
"reckenrode": 7413633,
|
||||
"toonn": 1486805
|
||||
},
|
||||
"name": "darwin-core"
|
||||
},
|
||||
"darwin-maintainers": {
|
||||
"description": "Improve Darwin-support across Nixpkgs and help maintainers without access to Darwin hardware. Apply to join through https://github.com/NixOS/nixpkgs/issues/323144 to keep the process transparent.",
|
||||
"id": 2385202,
|
||||
"maintainers": {
|
||||
"toonn": 1486805
|
||||
},
|
||||
"members": {
|
||||
"0xMRTT": 105598867,
|
||||
"21CSM": 81891917,
|
||||
"Aleksanaa": 42209822,
|
||||
"CorbanR": 1918683,
|
||||
"Emin017": 99674037,
|
||||
"Et7f3": 29592775,
|
||||
"FlameFlag": 57304299,
|
||||
"Guanran928": 68757440,
|
||||
"LnL7": 689294,
|
||||
"Mastermindaxe": 33257997,
|
||||
"Moraxyc": 69713071,
|
||||
"Prince213": 25235514,
|
||||
"Samasaur1": 30577766,
|
||||
"Sciencentistguy": 4983935,
|
||||
"Steven0351": 24440751,
|
||||
"afh": 16507,
|
||||
"azuwis": 9315,
|
||||
"booxter": 90200,
|
||||
"carlossless": 498906,
|
||||
"cideM": 4246921,
|
||||
"cidkidnix": 67574902,
|
||||
"copumpkin": 2623,
|
||||
"devusb": 4951663,
|
||||
"domenkozar": 126339,
|
||||
"donn": 12652988,
|
||||
"dwt": 57199,
|
||||
"emilazy": 18535642,
|
||||
"ethancedwards8": 60861925,
|
||||
"fiddlerwoaroof": 808745,
|
||||
"frogamic": 10263813,
|
||||
"gador": 1883533,
|
||||
"griff": 4368,
|
||||
"groodt": 343415,
|
||||
"gshpychka": 23005347,
|
||||
"hexagonal-sun": 222664,
|
||||
"heywoodlh": 18178614,
|
||||
"iedame": 60272,
|
||||
"isabelroses": 71222764,
|
||||
"jonhermansen": 660911,
|
||||
"juliusrickert": 5007494,
|
||||
"jwiegley": 8460,
|
||||
"kashw2": 15855440,
|
||||
"kevingriffin": 209729,
|
||||
"khaneliman": 1778670,
|
||||
"kloenk": 12898828,
|
||||
"konradmalik": 13033392,
|
||||
"kubukoz": 894884,
|
||||
"lutzmor": 9321736,
|
||||
"magistau": 43097806,
|
||||
"maljub01": 350635,
|
||||
"martinjlowm": 110860,
|
||||
"matteo-pacini": 3139724,
|
||||
"matthewbauer": 19036,
|
||||
"mexisme": 329349,
|
||||
"mikroskeem": 3490861,
|
||||
"mirkolenz": 5160954,
|
||||
"mstone": 412508,
|
||||
"n8henrie": 1234956,
|
||||
"niklaskorz": 590517,
|
||||
"ofalvai": 1694986,
|
||||
"pasqui23": 6931743,
|
||||
"prusnak": 42201,
|
||||
"pupbrained": 33522919,
|
||||
"reckenrode": 7413633,
|
||||
"ryand56": 22267679,
|
||||
"samrose": 115821,
|
||||
"sarahec": 11277967,
|
||||
"shaunsingh": 71196912,
|
||||
"sikmir": 688044,
|
||||
"siraben": 8219659,
|
||||
"siriobalmelli": 23038812,
|
||||
"starcraft66": 1858154,
|
||||
"stepbrobd": 81826728,
|
||||
"stephank": 89950,
|
||||
"stephenstubbs": 18033664,
|
||||
"t-monaghan": 62273348,
|
||||
"thefloweringash": 42933,
|
||||
"tricktron": 16036882,
|
||||
"uncenter": 47499684,
|
||||
"uri-canva": 33242106,
|
||||
"usertam": 22500027,
|
||||
"veprbl": 245573,
|
||||
"viraptor": 188063,
|
||||
"wegank": 9713184,
|
||||
"willcohen": 5185341,
|
||||
"willjr": 5904828,
|
||||
"wldhx": 15619766,
|
||||
"yeongsheng-tan": 809030,
|
||||
"youhaveme9": 58213083,
|
||||
"yzx9": 41458459,
|
||||
"zachcoyle": 908716
|
||||
},
|
||||
"name": "darwin-maintainers"
|
||||
},
|
||||
"documentation-team": {
|
||||
"description": "Maintain nixpkgs/NixOS documentation and tools for building it. https://nixos.org/community/teams/documentation",
|
||||
"id": 6590023,
|
||||
"maintainers": {
|
||||
"alejandrosame": 1078000
|
||||
},
|
||||
"members": {
|
||||
"hsjobeki": 50398876,
|
||||
"wamirez": 24505474
|
||||
},
|
||||
"name": "Documentation Team"
|
||||
},
|
||||
"dotnet": {
|
||||
"description": "Maintain the .NET ecosystem in nixpkgs",
|
||||
"id": 8173604,
|
||||
"maintainers": {
|
||||
"corngood": 3077118,
|
||||
"mdarocha": 11572618
|
||||
},
|
||||
"members": {
|
||||
"GGG-KILLER": 5892127,
|
||||
"IvarWithoutBones": 41924494,
|
||||
"JamieMagee": 1358764,
|
||||
"anpin": 6060545,
|
||||
"meenzen": 22305878,
|
||||
"raphaelr": 121178
|
||||
},
|
||||
"name": "Dotnet"
|
||||
},
|
||||
"emacs": {
|
||||
"description": "",
|
||||
"id": 2516946,
|
||||
"maintainers": {
|
||||
"jian-lin": 75130626,
|
||||
"matthewbauer": 19036
|
||||
},
|
||||
"members": {
|
||||
"AndersonTorres": 5954806,
|
||||
"adisbladis": 63286,
|
||||
"panchoh": 471059,
|
||||
"ttuegel": 563054
|
||||
},
|
||||
"name": "emacs"
|
||||
},
|
||||
"enlightenment": {
|
||||
"description": "Maintain Enlightenment desktop environment and related packages",
|
||||
"id": 5937665,
|
||||
"maintainers": {
|
||||
"romildo": 1217934
|
||||
},
|
||||
"members": {},
|
||||
"name": "Enlightenment"
|
||||
},
|
||||
"exotic-platform-maintainers": {
|
||||
"description": "",
|
||||
"id": 3727378,
|
||||
"maintainers": {
|
||||
"Ericson2314": 1055245,
|
||||
"matthewbauer": 19036
|
||||
},
|
||||
"members": {
|
||||
"aaronjanse": 16829510,
|
||||
"alyssais": 2768870,
|
||||
"emilytrau": 13267947,
|
||||
"minijackson": 1200507,
|
||||
"r-burns": 52847440,
|
||||
"siraben": 8219659,
|
||||
"sternenseemann": 3154475
|
||||
},
|
||||
"name": "exotic-platform-maintainers"
|
||||
},
|
||||
"flutter": {
|
||||
"description": "Maintain Flutter and Dart-related packages and build tools",
|
||||
"id": 7718198,
|
||||
"maintainers": {
|
||||
"RossComputerGuy": 19699320
|
||||
},
|
||||
"members": {
|
||||
"FlafyDev": 44374434,
|
||||
"hacker1024": 20849728,
|
||||
"mkg20001": 7735145
|
||||
},
|
||||
"name": "Flutter"
|
||||
},
|
||||
"freedesktop": {
|
||||
"description": "Maintain Freedesktop.org packages for graphical desktop.",
|
||||
"id": 3806136,
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"jtojnar": 705123
|
||||
},
|
||||
"name": "Freedesktop"
|
||||
},
|
||||
"geospatial": {
|
||||
"description": "Maintain geospatial, remote sensing and OpenStreetMap software",
|
||||
"id": 7084621,
|
||||
"maintainers": {
|
||||
"imincik": 476346
|
||||
},
|
||||
"members": {
|
||||
"autra": 1576598,
|
||||
"l0b0": 168301,
|
||||
"nh2": 399535,
|
||||
"nialov": 47318483,
|
||||
"sikmir": 688044,
|
||||
"willcohen": 5185341
|
||||
},
|
||||
"name": "Geospatial"
|
||||
},
|
||||
"gitlab": {
|
||||
"description": "Maintain GitLab-related packages and modules",
|
||||
"id": 8157777,
|
||||
"maintainers": {
|
||||
"leona-ya": 11006031,
|
||||
"xanderio": 6298052,
|
||||
"yayayayaka": 73759599
|
||||
},
|
||||
"members": {
|
||||
"talyz": 63433
|
||||
},
|
||||
"name": "GitLab"
|
||||
},
|
||||
"gnome": {
|
||||
"description": "Maintain GNOME desktop environment and platform.",
|
||||
"id": 3806133,
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"bobby285271": 20080233,
|
||||
"dasj19": 7589338,
|
||||
"hedning": 71978,
|
||||
"jtojnar": 705123
|
||||
},
|
||||
"name": "GNOME"
|
||||
},
|
||||
"golang": {
|
||||
"description": "Maintain Golang compilers",
|
||||
"id": 4020424,
|
||||
"maintainers": {
|
||||
"Mic92": 96200,
|
||||
"kalbasit": 87115,
|
||||
"zowoq": 59103226
|
||||
},
|
||||
"members": {
|
||||
"katexochen": 49727155,
|
||||
"mfrw": 4929861,
|
||||
"qbit": 68368
|
||||
},
|
||||
"name": "golang"
|
||||
},
|
||||
"haskell": {
|
||||
"description": "Maintain Haskell packages and infrastructure",
|
||||
"id": 4769723,
|
||||
"maintainers": {
|
||||
"cdepillabout": 64804,
|
||||
"maralorn": 1651325,
|
||||
"sternenseemann": 3154475
|
||||
},
|
||||
"members": {
|
||||
"wolfgangwalther": 9132420
|
||||
},
|
||||
"name": "Haskell"
|
||||
},
|
||||
"hyprland": {
|
||||
"description": "Maintain Hyprland compositor and ecosystem.",
|
||||
"id": 12048885,
|
||||
"maintainers": {
|
||||
"khaneliman": 1778670
|
||||
},
|
||||
"members": {
|
||||
"JohnRTitor": 50095635,
|
||||
"NotAShelf": 62766066,
|
||||
"donovanglover": 2374245,
|
||||
"fufexan": 36706276
|
||||
},
|
||||
"name": "hyprland"
|
||||
},
|
||||
"java": {
|
||||
"description": "Maintainers of the Nixpkgs Java ecosystem (JDK, JVM, Java, Gradle, Maven, Ant, and adjacent projects); frequently lingering in #jvm:nixos.org on Matrix",
|
||||
"id": 11412419,
|
||||
"maintainers": {
|
||||
"FliegendeWurst": 12560461,
|
||||
"Infinidoge": 22727114,
|
||||
"chayleaf": 9590981,
|
||||
"tomodachi94": 68489118
|
||||
},
|
||||
"members": {
|
||||
"msgilligan": 61612
|
||||
},
|
||||
"name": "Java"
|
||||
},
|
||||
"k3s": {
|
||||
"description": "Maintain K3s package, NixOS module, NixOS tests, update script",
|
||||
"id": 7725877,
|
||||
"maintainers": {
|
||||
"Mic92": 96200,
|
||||
"euank": 2147649,
|
||||
"marcusramberg": 5526,
|
||||
"wrmilling": 6162814
|
||||
},
|
||||
"members": {
|
||||
"frederictobiasc": 26125115,
|
||||
"heywoodlh": 18178614,
|
||||
"rorosen": 76747196
|
||||
},
|
||||
"name": "k3s"
|
||||
},
|
||||
"kodi": {
|
||||
"description": "Maintain Kodi related packages.",
|
||||
"id": 4642467,
|
||||
"maintainers": {
|
||||
"aanderse": 7755101
|
||||
},
|
||||
"members": {
|
||||
"cpages": 411324,
|
||||
"edwtjo": 54799,
|
||||
"minijackson": 1200507,
|
||||
"peterhoeg": 722550,
|
||||
"sephalon": 893474
|
||||
},
|
||||
"name": "kodi"
|
||||
},
|
||||
"kubernetes": {
|
||||
"description": "Maintain the Kubernetes package and module",
|
||||
"id": 5536808,
|
||||
"maintainers": {
|
||||
"johanot": 998763,
|
||||
"offlinehacker": 585547,
|
||||
"saschagrunert": 695473,
|
||||
"srhb": 219362
|
||||
},
|
||||
"members": {},
|
||||
"name": "kubernetes"
|
||||
},
|
||||
"linux-kernel": {
|
||||
"description": "Maintain the Linux kernel",
|
||||
"id": 13371617,
|
||||
"maintainers": {
|
||||
"alyssais": 2768870
|
||||
},
|
||||
"members": {
|
||||
"K900": 386765,
|
||||
"Ma27": 6025220,
|
||||
"NeQuissimus": 628342,
|
||||
"TredwellGit": 61860346
|
||||
},
|
||||
"name": "Linux kernel"
|
||||
},
|
||||
"lisp": {
|
||||
"description": "Maintain the Lisp ecosystem",
|
||||
"id": 7678368,
|
||||
"maintainers": {
|
||||
"7c6f434c": 1891350,
|
||||
"Uthar": 15697697,
|
||||
"hraban": 137852,
|
||||
"lukego": 13791,
|
||||
"nagy": 692274
|
||||
},
|
||||
"members": {},
|
||||
"name": "lisp"
|
||||
},
|
||||
"lix-maintainers": {
|
||||
"description": "Lix maintainers in nixpkgs/NixOS",
|
||||
"id": 13838744,
|
||||
"maintainers": {
|
||||
"lf-": 6652840
|
||||
},
|
||||
"members": {
|
||||
"9999years": 15312184,
|
||||
"Qyriad": 1542224,
|
||||
"RaitoBezarius": 314564,
|
||||
"alois31": 36605164
|
||||
},
|
||||
"name": "Lix maintainers"
|
||||
},
|
||||
"llvm": {
|
||||
"description": "Maintain LLVM package sets and related packages",
|
||||
"id": 9955829,
|
||||
"maintainers": {
|
||||
"RossComputerGuy": 19699320,
|
||||
"alyssais": 2768870
|
||||
},
|
||||
"members": {
|
||||
"Ericson2314": 1055245,
|
||||
"dtzWill": 817330,
|
||||
"emilazy": 18535642,
|
||||
"lovek323": 265084,
|
||||
"rrbutani": 7833358,
|
||||
"sternenseemann": 3154475
|
||||
},
|
||||
"name": "LLVM"
|
||||
},
|
||||
"loongarch64": {
|
||||
"description": "Maintain LoongArch64 related packages and code",
|
||||
"id": 13371619,
|
||||
"maintainers": {
|
||||
"Aleksanaa": 42209822
|
||||
},
|
||||
"members": {
|
||||
"Cryolitia": 23723294,
|
||||
"darkyzhou": 7220778,
|
||||
"dramforever": 2818072,
|
||||
"wegank": 9713184
|
||||
},
|
||||
"name": "loongarch64"
|
||||
},
|
||||
"lua": {
|
||||
"description": "Maintain the lua ecosystem",
|
||||
"id": 5255750,
|
||||
"maintainers": {
|
||||
"teto": 886074
|
||||
},
|
||||
"members": {
|
||||
"7c6f434c": 1891350,
|
||||
"Shados": 338268,
|
||||
"khaneliman": 1778670,
|
||||
"spencerpogo": 34356756
|
||||
},
|
||||
"name": "lua"
|
||||
},
|
||||
"lumina": {
|
||||
"description": "Maintain lumina desktop environment and related packages",
|
||||
"id": 5937661,
|
||||
"maintainers": {
|
||||
"romildo": 1217934
|
||||
},
|
||||
"members": {},
|
||||
"name": "Lumina"
|
||||
},
|
||||
"lxc": {
|
||||
"description": "LXC, LXD, Incus",
|
||||
"id": 9223525,
|
||||
"maintainers": {
|
||||
"adamcstephens": 2071575
|
||||
},
|
||||
"members": {
|
||||
"aanderse": 7755101,
|
||||
"jnsgruk": 668505,
|
||||
"megheaiulian": 1788114,
|
||||
"mkg20001": 7735145
|
||||
},
|
||||
"name": "LXC"
|
||||
},
|
||||
"lxqt": {
|
||||
"description": "Maintain LXQt desktop environment and related packages",
|
||||
"id": 5937679,
|
||||
"maintainers": {
|
||||
"romildo": 1217934
|
||||
},
|
||||
"members": {},
|
||||
"name": "LXQt"
|
||||
},
|
||||
"marketing-team": {
|
||||
"description": "Marketing team [leader=@djacu]",
|
||||
"id": 7709512,
|
||||
"maintainers": {
|
||||
"djacu": 7043297,
|
||||
"tomberek": 178444
|
||||
},
|
||||
"members": {
|
||||
"flyfloh": 74379,
|
||||
"thilobillerbeck": 7442383
|
||||
},
|
||||
"name": "Marketing Team"
|
||||
},
|
||||
"mate": {
|
||||
"description": "Maintainers of the MATE Desktop Environment",
|
||||
"id": 5937667,
|
||||
"maintainers": {
|
||||
"romildo": 1217934
|
||||
},
|
||||
"members": {
|
||||
"bobby285271": 20080233
|
||||
},
|
||||
"name": "MATE"
|
||||
},
|
||||
"neovim": {
|
||||
"description": "Maintain the vim and neovim text editors and related packages",
|
||||
"id": 6748534,
|
||||
"maintainers": {
|
||||
"GaetanLepage": 33058747
|
||||
},
|
||||
"members": {
|
||||
"PerchunPak": 68118654,
|
||||
"khaneliman": 1778670,
|
||||
"mrcjkb": 12857160
|
||||
},
|
||||
"name": "neovim"
|
||||
},
|
||||
"nix-formatting": {
|
||||
"description": "Maintain the official Nix formatter and apply it to Nixpkgs: https://nixos.org/community/teams/formatting/",
|
||||
"id": 9676823,
|
||||
"maintainers": {
|
||||
"infinisil": 20525370,
|
||||
"jfly": 277474
|
||||
},
|
||||
"members": {
|
||||
"0x4A6F": 9675338,
|
||||
"MattSturgeon": 5046562,
|
||||
"Sereja313": 112060595,
|
||||
"dasJ": 4971975,
|
||||
"piegamesde": 14054505
|
||||
},
|
||||
"name": "nix-formatting"
|
||||
},
|
||||
"nix-team": {
|
||||
"description": "",
|
||||
"id": 174820,
|
||||
"maintainers": {
|
||||
"tomberek": 178444
|
||||
},
|
||||
"members": {
|
||||
"Ericson2314": 1055245,
|
||||
"Mic92": 96200,
|
||||
"edolstra": 1148549,
|
||||
"xokdvium": 145775305
|
||||
},
|
||||
"name": "Nix team"
|
||||
},
|
||||
"nixos-release-managers": {
|
||||
"description": "Manage the current nixpkgs/NixOS release",
|
||||
"id": 3620128,
|
||||
"maintainers": {
|
||||
"jopejoe1": 34899572,
|
||||
"leona-ya": 11006031
|
||||
},
|
||||
"members": {},
|
||||
"name": "nixos-release-managers"
|
||||
},
|
||||
"nixpkgs-ci": {
|
||||
"description": "Maintain Nixpkgs' in-tree Continuous Integration, including GitHub Actions",
|
||||
"id": 13362067,
|
||||
"maintainers": {
|
||||
"philiptaron": 43863,
|
||||
"wolfgangwalther": 9132420
|
||||
},
|
||||
"members": {
|
||||
"MattSturgeon": 5046562,
|
||||
"Mic92": 96200,
|
||||
"zowoq": 59103226
|
||||
},
|
||||
"name": "Nixpkgs CI"
|
||||
},
|
||||
"nixpkgs-core": {
|
||||
"description": "Provides leadership for and has authority over Nixpkgs.",
|
||||
"id": 14317027,
|
||||
"maintainers": {
|
||||
"alyssais": 2768870,
|
||||
"emilazy": 18535642,
|
||||
"wolfgangwalther": 9132420
|
||||
},
|
||||
"members": {},
|
||||
"name": "Nixpkgs core"
|
||||
},
|
||||
"nixpkgs-merge-bot": {
|
||||
"description": "This team exists as a target for triggering the nixpkgs merge bot.",
|
||||
"id": 13926892,
|
||||
"maintainers": {},
|
||||
"members": {},
|
||||
"name": "nixpkgs-merge-bot"
|
||||
},
|
||||
"node": {
|
||||
"description": "Maintains Node.js runtimes and build tooling.\r\n\r\n\"JS is hecked, thanks for coming to my TED Talk\" - @lilyinstarlight",
|
||||
"id": 7309872,
|
||||
"maintainers": {
|
||||
"lilyinstarlight": 298109,
|
||||
"winterqt": 78392041
|
||||
},
|
||||
"members": {},
|
||||
"name": "Node"
|
||||
},
|
||||
"ocaml": {
|
||||
"description": "Maintain the OCaml compiler and package set",
|
||||
"id": 7553013,
|
||||
"maintainers": {
|
||||
"Alizter": 8614547,
|
||||
"romildo": 1217934,
|
||||
"ulrikstrid": 1607770
|
||||
},
|
||||
"members": {
|
||||
"redianthus": 16472988
|
||||
},
|
||||
"name": "OCaml"
|
||||
},
|
||||
"pantheon": {
|
||||
"description": "Maintain Pantheon desktop environment and platform",
|
||||
"id": 4786995,
|
||||
"maintainers": {
|
||||
"davidak": 91113
|
||||
},
|
||||
"members": {
|
||||
"bobby285271": 20080233
|
||||
},
|
||||
"name": "Pantheon"
|
||||
},
|
||||
"php": {
|
||||
"description": "Maintain PHP related packages and extensions.",
|
||||
"id": 3806182,
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"Ma27": 6025220,
|
||||
"aanderse": 7755101,
|
||||
"piotrkwiecinski": 2151333,
|
||||
"talyz": 63433
|
||||
},
|
||||
"name": "php"
|
||||
},
|
||||
"podman": {
|
||||
"description": "Maintain Podman and CRI-O related packages and modules.",
|
||||
"id": 3806184,
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"saschagrunert": 695473,
|
||||
"vdemeester": 6508
|
||||
},
|
||||
"name": "podman"
|
||||
},
|
||||
"postgres": {
|
||||
"description": "Maintain the PostgreSQL package and plugins along with the NixOS module.",
|
||||
"id": 11455958,
|
||||
"maintainers": {
|
||||
"Ma27": 6025220,
|
||||
"thoughtpolice": 3416,
|
||||
"wolfgangwalther": 9132420
|
||||
},
|
||||
"members": {},
|
||||
"name": "postgres"
|
||||
},
|
||||
"qt-kde": {
|
||||
"description": "Maintain the Qt framework, KDE application suite, Plasma desktop environment and related projects",
|
||||
"id": 4341481,
|
||||
"maintainers": {
|
||||
"ttuegel": 563054
|
||||
},
|
||||
"members": {
|
||||
"FRidh": 2129135,
|
||||
"K900": 386765,
|
||||
"LunNova": 782440,
|
||||
"NickCao": 15247171,
|
||||
"SCOTT-HAMILTON": 24496705,
|
||||
"SuperSandro2000": 7258858,
|
||||
"bkchr": 5718007,
|
||||
"ilya-fedin": 17829319,
|
||||
"mjm": 1181,
|
||||
"nyanloutre": 7677321,
|
||||
"peterhoeg": 722550
|
||||
},
|
||||
"name": "Qt-KDE"
|
||||
},
|
||||
"reproducible": {
|
||||
"description": "Team that is interested in reproducible builds",
|
||||
"id": 7625643,
|
||||
"maintainers": {
|
||||
"raboof": 131856,
|
||||
"zimbatm": 3248
|
||||
},
|
||||
"members": {
|
||||
"Artturin": 56650223,
|
||||
"Atemu": 18599032,
|
||||
"RaitoBezarius": 314564,
|
||||
"davidak": 91113,
|
||||
"mschwaig": 3856390
|
||||
},
|
||||
"name": "reproducible"
|
||||
},
|
||||
"risc-v": {
|
||||
"description": "RISC-V team",
|
||||
"id": 13425811,
|
||||
"maintainers": {
|
||||
"0x4A6F": 9675338
|
||||
},
|
||||
"members": {
|
||||
"DarkKirb": 23011243,
|
||||
"dramforever": 2818072,
|
||||
"fgaz": 8182846,
|
||||
"jonhermansen": 660911
|
||||
},
|
||||
"name": "RISC-V"
|
||||
},
|
||||
"rocm": {
|
||||
"description": "Maintain ROCm and related packages",
|
||||
"id": 6921873,
|
||||
"maintainers": {
|
||||
"mschwaig": 3856390
|
||||
},
|
||||
"members": {
|
||||
"Flakebi": 6499211,
|
||||
"GZGavinZhao": 74938940,
|
||||
"LunNova": 782440
|
||||
},
|
||||
"name": "rocm"
|
||||
},
|
||||
"rust": {
|
||||
"description": "Maintain the Rust compiler toolchain and nixpkgs integration",
|
||||
"id": 7304571,
|
||||
"maintainers": {
|
||||
"Mic92": 96200,
|
||||
"winterqt": 78392041,
|
||||
"zowoq": 59103226
|
||||
},
|
||||
"members": {
|
||||
"tjni": 3806110
|
||||
},
|
||||
"name": "rust"
|
||||
},
|
||||
"scala": {
|
||||
"description": "Maintain Scala-related packages and modules.",
|
||||
"id": 11193149,
|
||||
"maintainers": {
|
||||
"dottybot": 12519979,
|
||||
"hamzaremmal": 56235032
|
||||
},
|
||||
"members": {
|
||||
"natsukagami": 9061737
|
||||
},
|
||||
"name": "Scala"
|
||||
},
|
||||
"sdl": {
|
||||
"description": "Maintain core SDL libraries",
|
||||
"id": 13033942,
|
||||
"maintainers": {
|
||||
"pbsds": 140964
|
||||
},
|
||||
"members": {
|
||||
"LordGrimmauld": 49513131,
|
||||
"evysgarden": 92547295,
|
||||
"jansol": 2588851,
|
||||
"marcin-serwin": 12128106
|
||||
},
|
||||
"name": "SDL"
|
||||
},
|
||||
"static": {
|
||||
"description": "People interested in static builds (creation of `.a` files, fully static executables, etc.) and keeping them working",
|
||||
"id": 5906550,
|
||||
"maintainers": {
|
||||
"nh2": 399535
|
||||
},
|
||||
"members": {
|
||||
"Ericson2314": 1055245,
|
||||
"aherrmann": 732652,
|
||||
"alyssais": 2768870,
|
||||
"basvandijk": 576355,
|
||||
"cdepillabout": 64804,
|
||||
"dtzWill": 817330,
|
||||
"lorenzleutgeb": 542154,
|
||||
"matthewbauer": 19036,
|
||||
"r-burns": 52847440,
|
||||
"rnhmjoj": 2817565,
|
||||
"sternenseemann": 3154475
|
||||
},
|
||||
"name": "static"
|
||||
},
|
||||
"stdenv": {
|
||||
"description": "Maintain the standard environment and its surrounding logic.",
|
||||
"id": 11265412,
|
||||
"maintainers": {
|
||||
"RossComputerGuy": 19699320
|
||||
},
|
||||
"members": {
|
||||
"Artturin": 56650223,
|
||||
"Ericson2314": 1055245,
|
||||
"emilazy": 18535642,
|
||||
"philiptaron": 43863,
|
||||
"reckenrode": 7413633
|
||||
},
|
||||
"name": "stdenv"
|
||||
},
|
||||
"systemd": {
|
||||
"description": "Maintain systemd for NixOS",
|
||||
"id": 3894007,
|
||||
"maintainers": {
|
||||
"flokli": 183879
|
||||
},
|
||||
"members": {
|
||||
"ElvishJerricco": 1365692,
|
||||
"LordGrimmauld": 49513131,
|
||||
"aanderse": 7755101,
|
||||
"arianvp": 628387
|
||||
},
|
||||
"name": "systemd"
|
||||
},
|
||||
"xen-project": {
|
||||
"description": "Maintain the Xen Project Hypervisor and the related tooling ecosystem. Members listed as \"Maintainers\" are recipients of Xen Security Advisories sent to xsa@nixos.org.",
|
||||
"id": 11127725,
|
||||
"maintainers": {
|
||||
"CertainLach": 6235312,
|
||||
"SigmaSquadron": 174749595,
|
||||
"hehongbo": 665472
|
||||
},
|
||||
"members": {
|
||||
"digitalrane": 1829286
|
||||
},
|
||||
"name": "Xen Project"
|
||||
},
|
||||
"xfce": {
|
||||
"description": "Maintainers of the Xfce Desktop Environment",
|
||||
"id": 5421745,
|
||||
"maintainers": {
|
||||
"romildo": 1217934
|
||||
},
|
||||
"members": {
|
||||
"bobby285271": 20080233
|
||||
},
|
||||
"name": "Xfce"
|
||||
}
|
||||
}
|
||||
+250
-61
@@ -587,7 +587,7 @@
|
||||
};
|
||||
adamperkowski = {
|
||||
name = "Adam Perkowski";
|
||||
email = "adas1per@protonmail.com";
|
||||
email = "me@adamperkowski.dev";
|
||||
matrix = "@xx0a_q:matrix.org";
|
||||
github = "adamperkowski";
|
||||
githubId = 75480869;
|
||||
@@ -1069,6 +1069,13 @@
|
||||
}
|
||||
];
|
||||
};
|
||||
alch-emi = {
|
||||
email = "emi@alchemi.dev";
|
||||
github = "Alch-Emi";
|
||||
githubId = 38897201;
|
||||
name = "Emi";
|
||||
matrix = "@emi:the-apothecary.club";
|
||||
};
|
||||
aldenparker = {
|
||||
github = "aldenparker";
|
||||
githubId = 32986873;
|
||||
@@ -1106,6 +1113,12 @@
|
||||
githubId = 83360;
|
||||
name = "Aleksey Sidorov";
|
||||
};
|
||||
alemonmk = {
|
||||
email = "almk@rmntn.net";
|
||||
github = "alemonmk";
|
||||
githubId = 3955369;
|
||||
name = "Lemon Lam";
|
||||
};
|
||||
alerque = {
|
||||
email = "caleb@alerque.com";
|
||||
github = "alerque";
|
||||
@@ -2331,7 +2344,7 @@
|
||||
email = "assistant.moetron@gmail.com";
|
||||
github = "Assistant";
|
||||
githubId = 2748721;
|
||||
matrix = "@assistant:pygmalion.chat";
|
||||
matrix = "@self:assistant.moe";
|
||||
name = "Assistant Moetron";
|
||||
};
|
||||
astavie = {
|
||||
@@ -2360,12 +2373,6 @@
|
||||
name = "Vincent Fischer";
|
||||
keys = [ { fingerprint = "BF47 81E1 F304 1ADF 18CE C401 DE16 C7D1 536D A72F"; } ];
|
||||
};
|
||||
astronaut0212 = {
|
||||
email = "goatastronaut0212@outlook.com";
|
||||
github = "goatastronaut0212";
|
||||
githubId = 119769817;
|
||||
name = "goatastronaut0212";
|
||||
};
|
||||
asymmetric = {
|
||||
email = "lorenzo@mailbox.org";
|
||||
github = "asymmetric";
|
||||
@@ -2489,6 +2496,7 @@
|
||||
github = "auscyber";
|
||||
name = "Ivy Pierlot";
|
||||
githubId = 12080502;
|
||||
matrix = "@ivy:faggot.sh";
|
||||
};
|
||||
austin-artificial = {
|
||||
email = "austin.platt@artificial.io";
|
||||
@@ -2632,13 +2640,6 @@
|
||||
github = "aware70";
|
||||
githubId = 7832566;
|
||||
};
|
||||
awwpotato = {
|
||||
email = "awwpotato@voidq.com";
|
||||
matrix = "@awwpotato:envs.net";
|
||||
github = "awwpotato";
|
||||
githubId = 153149335;
|
||||
name = "awwpotato";
|
||||
};
|
||||
axertheaxe = {
|
||||
email = "axertheaxe@proton.me";
|
||||
github = "AxerTheAxe";
|
||||
@@ -3833,6 +3834,11 @@
|
||||
githubId = 40476330;
|
||||
name = "brokenpip3";
|
||||
};
|
||||
BronzeDeer = {
|
||||
github = "BronzeDeer";
|
||||
githubId = 74385045;
|
||||
name = "Joël Pepper";
|
||||
};
|
||||
brpaz = {
|
||||
email = "oss@brunopaz.dev";
|
||||
github = "brpaz";
|
||||
@@ -4248,6 +4254,11 @@
|
||||
githubId = 498906;
|
||||
name = "Karolis Stasaitis";
|
||||
};
|
||||
carlostome = {
|
||||
name = "Carlos Tomé Cortiñas";
|
||||
github = "carlostome";
|
||||
githubId = 2206578;
|
||||
};
|
||||
carlsverre = {
|
||||
email = "accounts@carlsverre.com";
|
||||
github = "carlsverre";
|
||||
@@ -5228,12 +5239,6 @@
|
||||
githubId = 3077118;
|
||||
name = "David McFarland";
|
||||
};
|
||||
coroa = {
|
||||
email = "jonas@chaoflow.net";
|
||||
github = "coroa";
|
||||
githubId = 2552981;
|
||||
name = "Jonas Hörsch";
|
||||
};
|
||||
costrouc = {
|
||||
email = "chris.ostrouchov@gmail.com";
|
||||
github = "costrouc";
|
||||
@@ -5556,6 +5561,13 @@
|
||||
githubId = 102048662;
|
||||
name = "Dalton Luce";
|
||||
};
|
||||
da157 = {
|
||||
email = "da157@voidq.com";
|
||||
matrix = "@da157:catgirl.cloud";
|
||||
github = "0xda157";
|
||||
githubId = 153149335;
|
||||
name = "0xda157";
|
||||
};
|
||||
dabao1955 = {
|
||||
email = "dabao1955@163.com";
|
||||
github = "dabao1955";
|
||||
@@ -5954,6 +5966,12 @@
|
||||
githubId = 49904992;
|
||||
name = "Dawid Sowa";
|
||||
};
|
||||
dawnofmidnight = {
|
||||
email = "dawnofmidnight@duck.com";
|
||||
github = "dawnofmidnight";
|
||||
githubId = 78233879;
|
||||
name = "whispers";
|
||||
};
|
||||
dawoox = {
|
||||
email = "contact@antoinebellanger.fr";
|
||||
github = "Dawoox";
|
||||
@@ -6260,6 +6278,12 @@
|
||||
githubId = 19733;
|
||||
name = "Moritz Heidkamp";
|
||||
};
|
||||
DerHalbGrieche = {
|
||||
email = "vasilis12.manetas@gmail.com";
|
||||
github = "DerHalbGrieche";
|
||||
githubId = 77843198;
|
||||
name = "Vasilis Manetas";
|
||||
};
|
||||
DerickEddington = {
|
||||
email = "derick.eddington@pm.me";
|
||||
github = "DerickEddington";
|
||||
@@ -7011,6 +7035,13 @@
|
||||
name = "Will Dietz";
|
||||
keys = [ { fingerprint = "389A 78CB CD88 5E0C 4701 DEB9 FD42 C7D0 D414 94C8"; } ];
|
||||
};
|
||||
dudeofawesome = {
|
||||
email = "tourist-04.iced@icloud.com";
|
||||
github = "dudeofawesome";
|
||||
githubId = 1683595;
|
||||
name = "Louis Orleans";
|
||||
keys = [ { fingerprint = "llSOkL8Tn5+LOmWa4PDci+dQXZIRy11NSumDiFzNkAM"; } ];
|
||||
};
|
||||
dudymas = {
|
||||
email = "jeremy.white@cloudposse.com";
|
||||
github = "dudymas";
|
||||
@@ -7111,6 +7142,12 @@
|
||||
githubId = 90563298;
|
||||
name = "Dovydas Kersys";
|
||||
};
|
||||
dyegoaurelio = {
|
||||
name = "Dyego Aurelio";
|
||||
email = "d@dyego.email";
|
||||
github = "dyegoaurelio";
|
||||
githubId = 42411160;
|
||||
};
|
||||
dylan-gonzalez = {
|
||||
email = "dylcg10@gmail.com";
|
||||
github = "dylan-gonzalez";
|
||||
@@ -7229,6 +7266,11 @@
|
||||
githubId = 8146736;
|
||||
name = "Florentin Eckl";
|
||||
};
|
||||
eclairevoyant = {
|
||||
githubId = 848000;
|
||||
github = "eclairevoyant";
|
||||
name = "éclairevoyant";
|
||||
};
|
||||
edanaher = {
|
||||
email = "nixos@edanaher.net";
|
||||
github = "edanaher";
|
||||
@@ -7714,6 +7756,13 @@
|
||||
githubId = 3422442;
|
||||
name = "Ruben Maher";
|
||||
};
|
||||
er0k = {
|
||||
email = "er0k@er0k.net";
|
||||
github = "er0k";
|
||||
githubId = 916239;
|
||||
name = "er0k";
|
||||
keys = [ { fingerprint = "60DE 4570 2E31 81A2 AF87 F075 B005 BA3C 8EE8 108D"; } ];
|
||||
};
|
||||
eraserhd = {
|
||||
email = "jason.m.felice@gmail.com";
|
||||
github = "eraserhd";
|
||||
@@ -7967,7 +8016,7 @@
|
||||
};
|
||||
euxane = {
|
||||
name = "euxane";
|
||||
email = "r9uhdi.nixpkgs@euxane.net";
|
||||
email = "r9uhdi.nixpkgs@euxane.eu";
|
||||
github = "pacien";
|
||||
githubId = 1449319;
|
||||
};
|
||||
@@ -8446,13 +8495,6 @@
|
||||
githubId = 52276064;
|
||||
name = "figboy9";
|
||||
};
|
||||
figsoda = {
|
||||
email = "figsoda@pm.me";
|
||||
matrix = "@figsoda:matrix.org";
|
||||
github = "figsoda";
|
||||
githubId = 40620903;
|
||||
name = "figsoda";
|
||||
};
|
||||
fionera = {
|
||||
email = "nix@fionera.de";
|
||||
github = "fionera";
|
||||
@@ -9021,6 +9063,12 @@
|
||||
githubId = 1313787;
|
||||
name = "Gabriella Gonzalez";
|
||||
};
|
||||
GabrielMaguire = {
|
||||
email = "gabrielmaguire@proton.me";
|
||||
github = "GabrielMaguire";
|
||||
githubId = 39974571;
|
||||
name = "Gabriel Maguire";
|
||||
};
|
||||
gabyx = {
|
||||
email = "gnuetzi@gmail.com";
|
||||
github = "gabyx";
|
||||
@@ -9061,6 +9109,12 @@
|
||||
githubId = 7047019;
|
||||
name = "Florent Becker";
|
||||
};
|
||||
galabovaa = {
|
||||
name = "Ivet Galabova";
|
||||
email = "galabovaa@gmail.com";
|
||||
github = "galabovaa";
|
||||
githubId = 4016566;
|
||||
};
|
||||
galagora = {
|
||||
email = "lightningstrikeiv@gmail.com";
|
||||
github = "Galagora";
|
||||
@@ -10955,6 +11009,12 @@
|
||||
githubId = 993484;
|
||||
name = "Greg Hale";
|
||||
};
|
||||
imatpot = {
|
||||
email = "nixpkgs@brnk.vc";
|
||||
github = "imatpot";
|
||||
githubId = 39416660;
|
||||
name = "Mladen Branković";
|
||||
};
|
||||
imgabe = {
|
||||
email = "gabrielpmonte@hotmail.com";
|
||||
github = "ImGabe";
|
||||
@@ -11690,6 +11750,12 @@
|
||||
githubId = 29395089;
|
||||
name = "Jay Rovacsek";
|
||||
};
|
||||
jaysa68 = {
|
||||
email = "gh@jaysa.net";
|
||||
github = "jaysa68";
|
||||
githubId = 114126812;
|
||||
name = "Jaysa Maria Garcia";
|
||||
};
|
||||
jb55 = {
|
||||
email = "jb55@jb55.com";
|
||||
github = "jb55";
|
||||
@@ -12880,6 +12946,12 @@
|
||||
github = "jthulhu";
|
||||
githubId = 23179762;
|
||||
};
|
||||
jtliang24 = {
|
||||
name = "Jiatao Liang";
|
||||
email = "jtliang24@gmail.com";
|
||||
github = "jtliang24";
|
||||
githubId = 170479425;
|
||||
};
|
||||
jtobin = {
|
||||
email = "jared@jtobin.io";
|
||||
github = "jtobin";
|
||||
@@ -13933,6 +14005,14 @@
|
||||
githubId = 4032;
|
||||
name = "Kristoffer Thømt Ravneberg";
|
||||
};
|
||||
krishnans2006 = {
|
||||
email = "krishnans2006@gmail.com";
|
||||
matrix = "@krishnans2006:matrix.org";
|
||||
github = "krishnans2006";
|
||||
githubId = 62958782;
|
||||
name = "Krishnan Shankar";
|
||||
keys = [ { fingerprint = "A30C 1843 F470 4843 5D54 3D68 29CB 06A8 40D0 E14A"; } ];
|
||||
};
|
||||
kristian-brucaj = {
|
||||
email = "kbrucaj@gmail.com";
|
||||
github = "Flameslice";
|
||||
@@ -13988,6 +14068,12 @@
|
||||
name = "Tomas Krupka";
|
||||
matrix = "@krupkat:matrix.org";
|
||||
};
|
||||
kruziikrel13 = {
|
||||
github = "kruziikrel13";
|
||||
name = "Michael Petersen";
|
||||
email = "dev@michaelpetersen.io";
|
||||
githubId = 72793125;
|
||||
};
|
||||
krzaczek = {
|
||||
name = "Pawel Krzaczkowski";
|
||||
email = "pawel@printu.pl";
|
||||
@@ -14058,7 +14144,7 @@
|
||||
};
|
||||
KunyaKud = {
|
||||
name = "KunyaKud";
|
||||
email = "KunyaKud@proton.me";
|
||||
email = "wafuu@posteo.net";
|
||||
github = "KunyaKud";
|
||||
githubId = 238898928;
|
||||
};
|
||||
@@ -14249,6 +14335,17 @@
|
||||
githubId = 55911173;
|
||||
name = "Gwendolyn Quasebarth";
|
||||
};
|
||||
lajp = {
|
||||
email = "lajp@iki.fi";
|
||||
github = "lajp";
|
||||
githubId = 31856315;
|
||||
name = "Luukas Pörtfors";
|
||||
keys = [
|
||||
{
|
||||
fingerprint = "24E8 E4CC 0295 F4ED B9E0 B4A6 C913 9B8D EA65 BD82";
|
||||
}
|
||||
];
|
||||
};
|
||||
lamarios = {
|
||||
matrix = "@lamarios:matrix.org";
|
||||
github = "lamarios";
|
||||
@@ -14431,6 +14528,12 @@
|
||||
githubId = 4701504;
|
||||
name = "James Robinson";
|
||||
};
|
||||
leha44581 = {
|
||||
email = "leha55481@gmail.com";
|
||||
github = "Leha44581";
|
||||
githubId = 70238465;
|
||||
name = "Leha";
|
||||
};
|
||||
leifhelm = {
|
||||
email = "jakob.leifhelm@gmail.com";
|
||||
github = "leifhelm";
|
||||
@@ -14533,6 +14636,12 @@
|
||||
githubId = 737767;
|
||||
name = "Thomas Gerbet";
|
||||
};
|
||||
letgamer = {
|
||||
github = "Letgamer";
|
||||
githubId = 62446107;
|
||||
matrix = "@letgamer:tchncs.de";
|
||||
name = "Alex Stephan";
|
||||
};
|
||||
lethalman = {
|
||||
email = "lucabru@src.gnome.org";
|
||||
github = "lucabrunox";
|
||||
@@ -14721,6 +14830,13 @@
|
||||
githubId = 54189319;
|
||||
name = "Lilly Cham";
|
||||
};
|
||||
lilyball = {
|
||||
email = "lily@ballards.net";
|
||||
github = "lilyball";
|
||||
githubId = 714;
|
||||
matrix = "@esperlily:matrix.org";
|
||||
name = "Lily Ballard";
|
||||
};
|
||||
limeytexan = {
|
||||
email = "limeytexan@gmail.com";
|
||||
github = "limeytexan";
|
||||
@@ -14779,6 +14895,12 @@
|
||||
githubId = 74221543;
|
||||
name = "Moritz Goltdammer";
|
||||
};
|
||||
linuxmobile = {
|
||||
email = "bdiez19@gmail.com";
|
||||
github = "linuxmobile";
|
||||
githubId = 10554636;
|
||||
name = "Braian A. Diez";
|
||||
};
|
||||
linuxwhata = {
|
||||
email = "linuxwhata@qq.com";
|
||||
matrix = "@lwa:envs.net";
|
||||
@@ -17255,6 +17377,17 @@
|
||||
githubId = 7831184;
|
||||
name = "John Mercier";
|
||||
};
|
||||
mochienya = {
|
||||
name = "mochienya";
|
||||
github = "mochienya";
|
||||
githubId = 187453775;
|
||||
matrix = "@mochienya:matrix.org";
|
||||
keys = [
|
||||
{
|
||||
fingerprint = "7A49 5110 84F4 EAF1 BE30 5CF0 CC3B E964 564F 9554";
|
||||
}
|
||||
];
|
||||
};
|
||||
mockersf = {
|
||||
email = "francois.mockers@vleue.com";
|
||||
github = "mockersf";
|
||||
@@ -17983,6 +18116,12 @@
|
||||
name = "Nasir Hussain";
|
||||
keys = [ { fingerprint = "7A10 AB8E 0BEC 566B 090C 9BE3 D812 6E55 9CE7 C35D"; } ];
|
||||
};
|
||||
nasrally = {
|
||||
email = "suffer.ring@ya.ru";
|
||||
github = "nasrally";
|
||||
githubId = 50599445;
|
||||
name = "Nikita Grishko";
|
||||
};
|
||||
nat-418 = {
|
||||
github = "nat-418";
|
||||
githubId = 93013864;
|
||||
@@ -18654,6 +18793,12 @@
|
||||
github = "noahgitsham";
|
||||
githubId = 73707948;
|
||||
};
|
||||
nobbele = {
|
||||
name = "nobbele";
|
||||
email = "realnobbele@gmail.com";
|
||||
github = "nobbele";
|
||||
githubId = 17962514;
|
||||
};
|
||||
nobbz = {
|
||||
name = "Norbert Melzer";
|
||||
email = "timmelzer+nixpkgs@gmail.com";
|
||||
@@ -19471,6 +19616,12 @@
|
||||
githubId = 52569953;
|
||||
name = "Oskar Manhart";
|
||||
};
|
||||
oskarwires = {
|
||||
email = "me@usbcable.io";
|
||||
github = "oskarwires";
|
||||
githubId = 115482671;
|
||||
name = "Oskar";
|
||||
};
|
||||
osnyx = {
|
||||
email = "os@flyingcircus.io";
|
||||
github = "osnyx";
|
||||
@@ -19923,12 +20074,6 @@
|
||||
githubId = 6498458;
|
||||
name = "pebble kite";
|
||||
};
|
||||
pbogdan = {
|
||||
email = "ppbogdan@gmail.com";
|
||||
github = "pbogdan";
|
||||
githubId = 157610;
|
||||
name = "Piotr Bogdan";
|
||||
};
|
||||
pborzenkov = {
|
||||
email = "pavel@borzenkov.net";
|
||||
github = "pborzenkov";
|
||||
@@ -21230,6 +21375,12 @@
|
||||
githubId = 39039420;
|
||||
name = "Quinn Dougherty";
|
||||
};
|
||||
quinneden = {
|
||||
email = "quinn@qeden.dev";
|
||||
github = "quinneden";
|
||||
githubId = 125415641;
|
||||
name = "Quinn Edenfield";
|
||||
};
|
||||
QuiNzX = {
|
||||
name = "QuiNz-";
|
||||
github = "QuiNzX";
|
||||
@@ -21275,6 +21426,11 @@
|
||||
matrix = "@qyriad:katesiria.org";
|
||||
name = "Qyriad";
|
||||
};
|
||||
qzylinra = {
|
||||
github = "qzylinra";
|
||||
githubId = 225773816;
|
||||
name = "qzylinra";
|
||||
};
|
||||
r-aizawa = {
|
||||
github = "Xantibody";
|
||||
githubId = 109563705;
|
||||
@@ -21650,12 +21806,6 @@
|
||||
{ fingerprint = "01D7 5486 3A6D 64EA AC77 0D26 FBF1 9A98 2CCE 0048"; }
|
||||
];
|
||||
};
|
||||
redbaron = {
|
||||
email = "ivanov.maxim@gmail.com";
|
||||
github = "redbaron";
|
||||
githubId = 16624;
|
||||
name = "Maxim Ivanov";
|
||||
};
|
||||
redfish64 = {
|
||||
email = "engler@gmail.com";
|
||||
github = "redfish64";
|
||||
@@ -22001,12 +22151,6 @@
|
||||
githubId = 1810487;
|
||||
name = "Rika";
|
||||
};
|
||||
rileyinman = {
|
||||
email = "rileyminman@gmail.com";
|
||||
github = "rileyinman";
|
||||
githubId = 37246692;
|
||||
name = "Riley Inman";
|
||||
};
|
||||
rinx = {
|
||||
email = "rintaro.okamura@gmail.com";
|
||||
github = "rinx";
|
||||
@@ -23059,6 +23203,11 @@
|
||||
githubId = 99875823;
|
||||
name = "Michael Savedra";
|
||||
};
|
||||
savtrip = {
|
||||
github = "savtrip";
|
||||
githubId = 42227195;
|
||||
name = "Sav Tripodi";
|
||||
};
|
||||
savyajha = {
|
||||
email = "savya.jha@hawkradius.com";
|
||||
github = "savyajha";
|
||||
@@ -23458,6 +23607,14 @@
|
||||
githubId = 5791019;
|
||||
name = "Jiuyang Liu";
|
||||
};
|
||||
Sereja313 = {
|
||||
name = "Sergey Gulin";
|
||||
github = "Sereja313";
|
||||
githubId = 112060595;
|
||||
email = "sergeygulin96@gmail.com";
|
||||
matrix = "@sereja:sereja.xyz";
|
||||
keys = [ { fingerprint = "AEF0 79C6 7618 8929 4124 22DB 3AB4 2DF3 F50E 3420"; } ];
|
||||
};
|
||||
serge = {
|
||||
email = "sb@canva.com";
|
||||
github = "serge-belov";
|
||||
@@ -24104,6 +24261,11 @@
|
||||
name = "Sebastian Kowalak";
|
||||
matrix = "@scl:tchncs.de";
|
||||
};
|
||||
skwig = {
|
||||
name = "skwig";
|
||||
github = "skwig";
|
||||
githubId = 16136203;
|
||||
};
|
||||
skyesoss = {
|
||||
name = "Skye Soss";
|
||||
matrix = "@skyesoss:matrix.org";
|
||||
@@ -25641,12 +25803,6 @@
|
||||
githubId = 102452;
|
||||
name = "Niclas Thall";
|
||||
};
|
||||
thammers = {
|
||||
email = "jawr@gmx.de";
|
||||
github = "tobias-hammerschmidt";
|
||||
githubId = 2543259;
|
||||
name = "Tobias Hammerschmidt";
|
||||
};
|
||||
thanegill = {
|
||||
email = "me@thanegill.com";
|
||||
github = "thanegill";
|
||||
@@ -25739,11 +25895,10 @@
|
||||
github = "thefossguy";
|
||||
githubId = 44400303;
|
||||
};
|
||||
thehans255 = {
|
||||
name = "Hans Jorgensen";
|
||||
email = "foss-contact@thehans255.com";
|
||||
github = "thehans255";
|
||||
githubId = 15896573;
|
||||
thegu5 = {
|
||||
name = "Gus";
|
||||
github = "thegu5";
|
||||
githubId = 58223632;
|
||||
};
|
||||
thekostins = {
|
||||
name = "Konstantin";
|
||||
@@ -25784,10 +25939,10 @@
|
||||
};
|
||||
theobori = {
|
||||
name = "Théo Bori";
|
||||
email = "theo1.bori@epitech.eu";
|
||||
email = "theobori@disroot.org";
|
||||
github = "theobori";
|
||||
githubId = 71843723;
|
||||
keys = [ { fingerprint = "EEFB CC3A C529 CFD1 943D A75C BDD5 7BE9 9D55 5965"; } ];
|
||||
keys = [ { fingerprint = "0636 56A5 6E31 5FFD BE46 8522 6D22 B068 2CCF 9294"; } ];
|
||||
};
|
||||
theonlymrcat = {
|
||||
name = "Max Guppy";
|
||||
@@ -25846,6 +26001,11 @@
|
||||
githubId = 91203390;
|
||||
name = "Felix Kimmel";
|
||||
};
|
||||
thesn = {
|
||||
github = "thesn10";
|
||||
githubId = 38666407;
|
||||
name = "TheSN";
|
||||
};
|
||||
thesola10 = {
|
||||
email = "me@thesola.io";
|
||||
github = "Thesola10";
|
||||
@@ -27010,6 +27170,11 @@
|
||||
githubId = 5155100;
|
||||
name = "Utkarsh Gupta";
|
||||
};
|
||||
utopiatopia = {
|
||||
github = "utopiatopia";
|
||||
githubId = 98685984;
|
||||
name = "utopiatopia";
|
||||
};
|
||||
uvnikita = {
|
||||
email = "uv.nikita@gmail.com";
|
||||
github = "uvNikita";
|
||||
@@ -27731,6 +27896,12 @@
|
||||
githubId = 43357387;
|
||||
keys = [ { fingerprint = "F844 80B2 0CA9 D6CC C7F5 2479 A776 D2AD 099E 8BC0"; } ];
|
||||
};
|
||||
wetisobe = {
|
||||
name = "Martin Woods";
|
||||
github = "wetisobe";
|
||||
email = "weti.sobe@pen-net.de";
|
||||
githubId = 172606048;
|
||||
};
|
||||
wetrustinprize = {
|
||||
email = "git@wetrustinprize.com";
|
||||
github = "wetrustinprize";
|
||||
@@ -28929,6 +29100,13 @@
|
||||
github = "zeri42";
|
||||
githubId = 68825133;
|
||||
};
|
||||
zerodya = {
|
||||
name = "Nicola";
|
||||
email = "nicola.pagliuca@pm.me";
|
||||
matrix = "@zerodya:beeper.com";
|
||||
github = "Zerodya";
|
||||
githubId = 73220426;
|
||||
};
|
||||
zestsystem = {
|
||||
email = "mk337337@gmail.com";
|
||||
github = "zestsystem";
|
||||
@@ -28946,6 +29124,11 @@
|
||||
githubId = 1329212;
|
||||
name = "Andy Zhang";
|
||||
};
|
||||
zhaithizaliel = {
|
||||
name = "Zhaith Izaliel";
|
||||
github = "Zhaith-Izaliel";
|
||||
githubId = 39216756;
|
||||
};
|
||||
zhaofengli = {
|
||||
email = "hello@zhaofeng.li";
|
||||
matrix = "@zhaofeng:zhaofeng.li";
|
||||
@@ -29091,6 +29274,12 @@
|
||||
githubId = 332534;
|
||||
name = "Zach Shipko";
|
||||
};
|
||||
zstg = {
|
||||
email = "zestig@duck.com";
|
||||
github = "zstg";
|
||||
githubId = 69384921;
|
||||
name = "ZeStig";
|
||||
};
|
||||
ztzg = {
|
||||
email = "dd@crosstwine.com";
|
||||
github = "ztzg";
|
||||
|
||||
@@ -52,17 +52,6 @@ The maintainer is designated by a `selector` which must be one of:
|
||||
|
||||
[`maintainer-list.nix`]: ../maintainer-list.nix
|
||||
|
||||
### `get-maintainer-pings-between.sh`
|
||||
|
||||
Gets which maintainers would be pinged between two Nixpkgs revisions.
|
||||
Outputs a JSON object on stdout mapping GitHub usernames to the attributes that they would be getting pinged for.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
maintainers/scripts/get-maintainer-pings-between.sh HEAD^ HEAD
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
### `sha-to-sri.py`
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p bundler-audit
|
||||
|
||||
set -o errexit -o nounset -o pipefail
|
||||
|
||||
bundle-audit check "$(nix-build --no-out-link maintainers/scripts/audit-ruby-packages/default.nix)"
|
||||
@@ -0,0 +1,15 @@
|
||||
let
|
||||
pkgs = import ../../.. { };
|
||||
lockFileBody = pkgs.lib.concatStringsSep "\n" (
|
||||
pkgs.lib.mapAttrsToList (name: props: " ${name} (${props.version})") (
|
||||
pkgs.lib.filterAttrs (name: _props: name != "recurseForDerivations") pkgs.rubyPackages
|
||||
)
|
||||
);
|
||||
in
|
||||
pkgs.runCommand "bundle-audit" { } ''
|
||||
mkdir "$out"
|
||||
echo 'GEM' > "$out/Gemfile.lock"
|
||||
echo ' remote: https://rubygems.org/' >> "$out/Gemfile.lock"
|
||||
echo ' specs:' >> "$out/Gemfile.lock"
|
||||
echo '${lockFileBody}' >> "$out/Gemfile.lock"
|
||||
''
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i perl -p perl -p perlPackages.JSON perlPackages.LWPUserAgent perlPackages.LWPProtocolHttps perlPackages.TermReadKey
|
||||
#!nix-shell -i perl -p perl -p perlPackages.JSON github-cli
|
||||
|
||||
# This script generates a list of teams to ping for the Feature Freeze announcement on Discourse.
|
||||
# It's intended to be used by Release Managers before creating such posts.
|
||||
#
|
||||
# The script interactively reads a GitHub username and a corresponding GitHub Personal Access token.
|
||||
# This is required to access the GitHub Teams API so the token needs at least the read:org privilege.
|
||||
# The script uses the credentials from the GitHub CLI (gh)
|
||||
# This is required to access the GitHub Teams API so it needs at least the read:org privilege.
|
||||
|
||||
## no critic (InputOutput::RequireCheckedSyscalls, InputOutput::ProhibitBacktickOperators)
|
||||
use strict;
|
||||
@@ -14,39 +14,21 @@ use Carp;
|
||||
use Cwd 'abs_path';
|
||||
use File::Basename;
|
||||
use JSON qw(decode_json);
|
||||
use LWP::UserAgent;
|
||||
use Term::ReadKey qw(ReadLine ReadMode);
|
||||
|
||||
sub github_team_members {
|
||||
my ($team_name, $username, $token) = @_;
|
||||
my ($team_name) = @_;
|
||||
my @ret;
|
||||
|
||||
my $req = HTTP::Request->new('GET', "https://api.github.com/orgs/NixOS/teams/$team_name/members", [ 'Accept' => 'application/vnd.github.v3+json' ]);
|
||||
$req->authorization_basic($username, $token);
|
||||
my $response = LWP::UserAgent->new->request($req);
|
||||
|
||||
if ($response->is_success) {
|
||||
my $content = decode_json($response->decoded_content);
|
||||
foreach (@{$content}) {
|
||||
push @ret, $_->{'login'};
|
||||
}
|
||||
} else {
|
||||
print {*STDERR} "!! Requesting members of GitHub Team '$team_name' failed: " . $response->status_line;
|
||||
my $content = decode_json(`gh api orgs/NixOS/teams/$team_name/members`);
|
||||
foreach (@{$content}) {
|
||||
push @ret, $_->{'login'};
|
||||
}
|
||||
|
||||
return \@ret;
|
||||
}
|
||||
|
||||
# Read GitHub credentials
|
||||
print {*STDERR} 'GitHub username: ';
|
||||
my $github_user = ReadLine(0);
|
||||
ReadMode('noecho');
|
||||
print {*STDERR} 'GitHub personal access token (no echo): ';
|
||||
my $github_token = ReadLine(0);
|
||||
ReadMode('restore');
|
||||
print {*STDERR} "\n";
|
||||
chomp $github_user;
|
||||
chomp $github_token;
|
||||
`gh auth status` or die "`gh` comes from `pkgs.github-cli`, or in one command:
|
||||
nix-shell -p github-cli --run 'gh auth login'\n";
|
||||
|
||||
# Read nix output
|
||||
my $nix_version = `nix --version`;
|
||||
@@ -60,7 +42,6 @@ if ($nix_version =~ m/2[.]3[.]/msx) {
|
||||
my $data = decode_json($out);
|
||||
|
||||
# Process teams
|
||||
print {*STDERR} "\n";
|
||||
while (my ($team_nix_key, $team_config) = each %{$data}) {
|
||||
# Ignore teams that don't want to be or can't be pinged
|
||||
if (not defined $team_config->{enableFeatureFreezePing} or not $team_config->{enableFeatureFreezePing}) {
|
||||
@@ -71,12 +52,12 @@ while (my ($team_nix_key, $team_config) = each %{$data}) {
|
||||
next;
|
||||
}
|
||||
# Team name
|
||||
print {*STDERR} "$team_config->{shortName}:";
|
||||
print {*STDOUT} "$team_config->{shortName}:";
|
||||
# GitHub Teams
|
||||
my @github_members;
|
||||
if (defined $team_config->{github}) {
|
||||
print {*STDERR} " \@NixOS/$team_config->{github}";
|
||||
push @github_members, @{github_team_members($team_config->{github}, $github_user, $github_token)};
|
||||
print {*STDOUT} " \@NixOS/$team_config->{github}";
|
||||
push @github_members, @{github_team_members($team_config->{github})};
|
||||
}
|
||||
my %github_members = map { $_ => 1 } @github_members;
|
||||
# Members
|
||||
@@ -88,9 +69,11 @@ while (my ($team_nix_key, $team_config) = each %{$data}) {
|
||||
if (defined $github_members{$github_handle}) {
|
||||
next;
|
||||
}
|
||||
print {*STDERR} " \@$github_handle";
|
||||
print {*STDOUT} " \@$github_handle";
|
||||
}
|
||||
}
|
||||
|
||||
print {*STDERR} "\n";
|
||||
print {*STDOUT} "\n";
|
||||
}
|
||||
|
||||
print {*STDOUT} "Everyone else: \@NixOS/nixpkgs-committers\n";
|
||||
|
||||
@@ -159,5 +159,5 @@ tree-sitter-http,,,,0.0.33-1,,
|
||||
tree-sitter-norg,,,,,5.1,mrcjkb
|
||||
tree-sitter-orgmode,,,,,,
|
||||
vstruct,,,,,,
|
||||
vusted,,,,,,figsoda
|
||||
vusted,,,,,,
|
||||
xml2lua,,,,,,teto
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages(ps: with ps; [ ])" nix
|
||||
"""
|
||||
A program to remove old aliases or convert old aliases to throws
|
||||
Converts old aliases to warnings, converts old warnings to throws, and removes old throws.
|
||||
Example usage:
|
||||
./maintainers/scripts/remove-old-aliases.py --year 2018 --file ./pkgs/top-level/aliases.nix
|
||||
|
||||
@@ -31,22 +31,42 @@ def process_args() -> argparse.Namespace:
|
||||
arg_parser.add_argument(
|
||||
"--only-throws",
|
||||
action="store_true",
|
||||
help="only operate on throws. e.g remove throws older than $date",
|
||||
help="Deprecated, use --only throws instead",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--only",
|
||||
choices=["aliases", "warnings", "throws"],
|
||||
help="Only act on the specified types"
|
||||
"(i.e. only act on entries that are 'normal' aliases, warnings, or throws)."
|
||||
"Can be repeated.",
|
||||
action="append",
|
||||
dest="operate_on",
|
||||
)
|
||||
arg_parser.add_argument("--file", required=True, type=Path, help="alias file")
|
||||
arg_parser.add_argument(
|
||||
"--dry-run", action="store_true", help="don't modify files, only print results"
|
||||
)
|
||||
return arg_parser.parse_args()
|
||||
|
||||
parsed = arg_parser.parse_args()
|
||||
|
||||
if parsed.only_throws:
|
||||
parsed.operate_on.append("throws")
|
||||
|
||||
if parsed.operate_on is None:
|
||||
parsed.operate_on = ["aliases", "warnings", "throws"]
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def get_date_lists(
|
||||
txt: list[str], cutoffdate: datetimedate, only_throws: bool
|
||||
) -> tuple[list[str], list[str], list[str]]:
|
||||
txt: list[str], cutoffdate: datetimedate
|
||||
) -> tuple[list[str], list[str], list[str], list[str], list[str]]:
|
||||
"""get a list of lines in which the date is older than $cutoffdate"""
|
||||
date_older_list: list[str] = []
|
||||
date_older_throw_list: list[str] = []
|
||||
date_older_warning_list: list[str] = []
|
||||
date_sep_line_list: list[str] = []
|
||||
date_too_complex_list: list[str] = []
|
||||
|
||||
for lineno, line in enumerate(txt, start=1):
|
||||
line = line.rstrip()
|
||||
@@ -69,68 +89,104 @@ def get_date_lists(
|
||||
):
|
||||
continue
|
||||
|
||||
if "=" not in line:
|
||||
date_sep_line_list.append(f"{lineno} {line}")
|
||||
if line.lstrip().startswith("inherit (") and ";" in line:
|
||||
date_older_list.append(line)
|
||||
elif "=" not in line:
|
||||
date_sep_line_list.append(f"{lineno:>5} {line}")
|
||||
# 'if' lines could be complicated
|
||||
elif "if " in line and "if =" not in line:
|
||||
print(f"RESOLVE MANUALLY {line}")
|
||||
elif "throw" in line:
|
||||
date_too_complex_list.append(f"{lineno:>5} {line}")
|
||||
elif "= with " in line:
|
||||
date_too_complex_list.append(f"{lineno:>5} {line}")
|
||||
elif "warnAlias" in line or "warning" in line:
|
||||
if 'warnAlias "' in line:
|
||||
date_older_warning_list.append(line)
|
||||
else:
|
||||
date_too_complex_list.append(f"{lineno:>5} {line}")
|
||||
elif " = throw" in line:
|
||||
date_older_throw_list.append(line)
|
||||
elif not only_throws:
|
||||
else:
|
||||
date_older_list.append(line)
|
||||
|
||||
return (
|
||||
date_older_list,
|
||||
date_sep_line_list,
|
||||
date_too_complex_list,
|
||||
date_older_throw_list,
|
||||
date_older_warning_list,
|
||||
)
|
||||
|
||||
|
||||
def convert_to_throw(date_older_list: list[str]) -> list[tuple[str, str]]:
|
||||
"""convert a list of lines to throws"""
|
||||
converted_list = []
|
||||
for line in date_older_list.copy():
|
||||
def convert(lines: list[str], convert_to: str) -> list[tuple[str, str]]:
|
||||
"""convert a list of lines to either "throws" or "warnings"."""
|
||||
converted_lines = {}
|
||||
for line in lines.copy():
|
||||
indent: str = " " * (len(line) - len(line.lstrip()))
|
||||
before_equal = ""
|
||||
after_equal = ""
|
||||
try:
|
||||
before_equal, after_equal = (x.strip() for x in line.split("=", maxsplit=2))
|
||||
except ValueError as err:
|
||||
print(err, line, "\n")
|
||||
date_older_list.remove(line)
|
||||
continue
|
||||
|
||||
alias = before_equal
|
||||
alias_unquoted = before_equal.strip('"')
|
||||
replacement = next(x.strip(";:") for x in after_equal.split())
|
||||
if "=" not in line:
|
||||
assert "inherit (" in line
|
||||
before, sep, after = line.partition("inherit (")
|
||||
inside, sep, after = after.partition(")")
|
||||
if not sep:
|
||||
print(f"FAILED ON {line}")
|
||||
continue
|
||||
alias, *_ = after.strip().split(";")[0].split()
|
||||
replacement = f"{inside.strip()}.{alias}"
|
||||
|
||||
else:
|
||||
before_equal = ""
|
||||
after_equal = ""
|
||||
try:
|
||||
before_equal, after_equal = (
|
||||
x.strip() for x in line.split("=", maxsplit=2)
|
||||
)
|
||||
if after_equal.startswith("warnAlias"):
|
||||
after_equal = after_equal.split("\"", maxsplit=3)[2].strip()
|
||||
except ValueError as err:
|
||||
print(err, line, "\n")
|
||||
lines.remove(line)
|
||||
continue
|
||||
|
||||
alias = before_equal
|
||||
replacement = next(x.strip(";:") for x in after_equal.split())
|
||||
|
||||
alias_unquoted = alias.strip('"')
|
||||
replacement = replacement.removeprefix("pkgs.")
|
||||
|
||||
converted = (
|
||||
f"{indent}{alias} = throw \"'{alias_unquoted}' has been"
|
||||
f" renamed to/replaced by '{replacement}'\";"
|
||||
f" # Converted to throw {datetime.today().strftime('%Y-%m-%d')}"
|
||||
)
|
||||
converted_list.append((line, converted))
|
||||
if convert_to == "throws":
|
||||
converted = (
|
||||
f"{indent}{alias} = throw \"'{alias_unquoted}' has been"
|
||||
f" renamed to/replaced by '{replacement}'\";"
|
||||
f" # Converted to throw {datetime.today().strftime('%Y-%m-%d')}"
|
||||
)
|
||||
converted_lines[line] = converted
|
||||
elif convert_to == "warnings":
|
||||
converted = (
|
||||
f"{indent}{alias} = warnAlias \"'{alias_unquoted}' has been"
|
||||
f" renamed to/replaced by '{replacement}'\" {replacement};"
|
||||
f" # Converted to warning {datetime.today().strftime('%Y-%m-%d')}"
|
||||
)
|
||||
converted_lines[line] = converted
|
||||
else:
|
||||
raise ValueError("'convert_to' must be either 'throws' or 'warnings'")
|
||||
|
||||
return converted_list
|
||||
return converted_lines
|
||||
|
||||
|
||||
def generate_text_to_write(
|
||||
txt: list[str],
|
||||
date_older_list: list[str],
|
||||
converted_to_throw: list[tuple[str, str]],
|
||||
date_older_throw_list: list[str],
|
||||
converted_lines: dict[str, str],
|
||||
) -> list[str]:
|
||||
"""generate a list of text to be written to the aliasfile"""
|
||||
text_to_write: list[str] = []
|
||||
for line in txt:
|
||||
text_to_append: str = ""
|
||||
if converted_to_throw:
|
||||
for tupl in converted_to_throw:
|
||||
if line == tupl[0]:
|
||||
text_to_append = f"{tupl[1]}\n"
|
||||
if line not in date_older_list and line not in date_older_throw_list:
|
||||
text_to_append = f"{line}\n"
|
||||
try:
|
||||
new_line = converted_lines[line]
|
||||
if new_line is not None:
|
||||
text_to_write.append(f"{new_line}\n")
|
||||
except KeyError:
|
||||
text_to_write.append(f"{line}\n")
|
||||
if text_to_append:
|
||||
text_to_write.append(text_to_append)
|
||||
|
||||
@@ -171,30 +227,48 @@ def main() -> None:
|
||||
"""main"""
|
||||
args = process_args()
|
||||
|
||||
only_throws = args.only_throws
|
||||
aliasfile = Path(args.file).absolute()
|
||||
cutoffdate = (datetime.strptime(f"{args.year}-{args.month}-01", "%Y-%m-%d")).date()
|
||||
|
||||
txt: list[str] = (aliasfile.read_text(encoding="utf-8")).splitlines()
|
||||
|
||||
date_older_list: list[str] = []
|
||||
date_sep_line_list: list[str] = []
|
||||
date_older_warning_list: list[str] = []
|
||||
date_older_throw_list: list[str] = []
|
||||
date_sep_line_list: list[str] = []
|
||||
date_too_complex_list: list[str] = []
|
||||
|
||||
date_older_list, date_sep_line_list, date_older_throw_list = get_date_lists(
|
||||
txt, cutoffdate, only_throws
|
||||
)
|
||||
(
|
||||
date_older_list,
|
||||
date_sep_line_list,
|
||||
date_too_complex_list,
|
||||
date_older_throw_list,
|
||||
date_older_warning_list,
|
||||
) = get_date_lists(txt, cutoffdate)
|
||||
|
||||
converted_to_throw: list[tuple[str, str]] = []
|
||||
if date_older_list:
|
||||
converted_to_throw = convert_to_throw(date_older_list)
|
||||
print(" Will be converted to throws. ".center(100, "-"))
|
||||
converted_lines: dict[str, str] = {}
|
||||
|
||||
if date_older_list and "aliases" in args.operate_on:
|
||||
converted_lines.update(convert(date_older_list, "warnings"))
|
||||
print(" Will be converted to warnings. ".center(100, "-"))
|
||||
for l_n in date_older_list:
|
||||
print(l_n)
|
||||
|
||||
if date_older_throw_list:
|
||||
if date_older_warning_list and "warnings" in args.operate_on:
|
||||
converted_lines.update(convert(date_older_warning_list, "throws"))
|
||||
print(" Will be converted to throws. ".center(100, "-"))
|
||||
for l_n in date_older_warning_list:
|
||||
print(l_n)
|
||||
|
||||
if date_older_throw_list and "throws" in args.operate_on:
|
||||
print(" Will be removed. ".center(100, "-"))
|
||||
for l_n in date_older_throw_list:
|
||||
converted_lines[l_n] = None
|
||||
print(l_n)
|
||||
|
||||
if date_too_complex_list:
|
||||
print(" Too complex, resolve manually. ".center(100, "-"))
|
||||
for l_n in date_too_complex_list:
|
||||
print(l_n)
|
||||
|
||||
if date_sep_line_list:
|
||||
@@ -203,9 +277,7 @@ def main() -> None:
|
||||
print(l_n)
|
||||
|
||||
if not args.dry_run:
|
||||
text_to_write = generate_text_to_write(
|
||||
txt, date_older_list, converted_to_throw, date_older_throw_list
|
||||
)
|
||||
text_to_write = generate_text_to_write(txt, converted_lines)
|
||||
write_file(aliasfile, text_to_write)
|
||||
|
||||
|
||||
|
||||
+15
-381
@@ -1,11 +1,9 @@
|
||||
/*
|
||||
List of maintainer teams.
|
||||
name = {
|
||||
# Required
|
||||
members = [ maintainer1 maintainer2 ];
|
||||
scope = "Maintain foo packages.";
|
||||
shortName = "foo";
|
||||
# Optional
|
||||
enableFeatureFreezePing = true;
|
||||
github = "my-subsystem";
|
||||
};
|
||||
@@ -18,7 +16,12 @@
|
||||
- `enableFeatureFreezePing` will ping this team during the Feature Freeze announcements on releases
|
||||
- There is limited mention capacity in a single post, so this should be reserved for critical components
|
||||
or larger ecosystems within nixpkgs.
|
||||
- `github` will ping the specified GitHub team as well
|
||||
- `github` will ping the specified GitHub team and sync the `members`, `scope` and `shortName` fields from it
|
||||
- `githubId` will be set automatically based on `github`
|
||||
|
||||
If `github` is specified and you'd like to be added to the team, contact one of the `githubMaintainers` of the team:
|
||||
|
||||
nix eval -f lib teams.someTeam.githubMaintainers --json | jq
|
||||
|
||||
More fields may be added in the future.
|
||||
|
||||
@@ -37,7 +40,6 @@ with lib.maintainers;
|
||||
aanderse
|
||||
arianvp
|
||||
emily
|
||||
flokli
|
||||
m1cr0man
|
||||
];
|
||||
scope = "Maintain ACME-related packages and modules.";
|
||||
@@ -46,27 +48,11 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
agda = {
|
||||
members = [
|
||||
alexarice
|
||||
ncfavier
|
||||
phijor
|
||||
turion
|
||||
];
|
||||
scope = "Maintain Agda-related packages and modules.";
|
||||
shortName = "Agda";
|
||||
github = "agda";
|
||||
};
|
||||
|
||||
android = {
|
||||
members = [
|
||||
adrian-gierakowski
|
||||
hadilq
|
||||
johnrtitor
|
||||
numinit
|
||||
RossComputerGuy
|
||||
];
|
||||
scope = "Maintain Android-related tooling in nixpkgs.";
|
||||
github = "android";
|
||||
shortName = "Android";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -107,19 +93,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
beam = {
|
||||
members = [
|
||||
adamcstephens
|
||||
ankhers
|
||||
Br1ght0ne
|
||||
DianaOlympos
|
||||
gleber
|
||||
happysalada
|
||||
minijackson
|
||||
yurrriq
|
||||
];
|
||||
github = "beam";
|
||||
scope = "Maintain BEAM-related packages and modules.";
|
||||
shortName = "BEAM";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -193,34 +167,11 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
categorization = {
|
||||
members = [
|
||||
aleksana
|
||||
fgaz
|
||||
getpsyched
|
||||
lyndeno
|
||||
natsukium
|
||||
philiptaron
|
||||
pyrotelekinetic
|
||||
raskin
|
||||
sigmasquadron
|
||||
tomodachi94
|
||||
];
|
||||
github = "categorization";
|
||||
scope = "Maintain the categorization system in Nixpkgs, per RFC 146. This team has authority over all categorization issues in Nixpkgs.";
|
||||
shortName = "Categorization";
|
||||
};
|
||||
|
||||
ci = {
|
||||
members = [
|
||||
MattSturgeon
|
||||
mic92
|
||||
philiptaron
|
||||
wolfgangwalther
|
||||
zowoq
|
||||
];
|
||||
github = "nixpkgs-ci";
|
||||
scope = "Maintain Nixpkgs' in-tree Continuous Integration, including GitHub Actions.";
|
||||
shortName = "CI";
|
||||
};
|
||||
|
||||
cinnamon = {
|
||||
@@ -237,7 +188,6 @@ with lib.maintainers;
|
||||
members = [ floriansanderscc ];
|
||||
scope = "Maintain Clever Cloud related packages.";
|
||||
shortName = "CleverCloud";
|
||||
github = "CleverCloud";
|
||||
};
|
||||
|
||||
cloudposse = {
|
||||
@@ -263,21 +213,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
cosmic = {
|
||||
members = [
|
||||
a-kenji
|
||||
ahoneybun
|
||||
drakon64
|
||||
griffi-gh
|
||||
HeitorAugustoLN
|
||||
nyabinary
|
||||
pandapip1
|
||||
qyliss
|
||||
thefossguy
|
||||
michaelBelsanti
|
||||
];
|
||||
github = "cosmic";
|
||||
shortName = "cosmic";
|
||||
scope = "Maintain the COSMIC DE and related packages.";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -291,15 +227,6 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
cuda = {
|
||||
members = [
|
||||
connorbaker
|
||||
GaetanLepage
|
||||
prusnak
|
||||
samuela
|
||||
SomeoneSerge
|
||||
];
|
||||
scope = "Maintain CUDA-enabled packages";
|
||||
shortName = "Cuda";
|
||||
github = "cuda-maintainers";
|
||||
};
|
||||
|
||||
@@ -309,20 +236,14 @@ with lib.maintainers;
|
||||
xanderio
|
||||
blitz
|
||||
snu
|
||||
e1mo
|
||||
];
|
||||
scope = "Team for Cyberus Technology employees who collectively maintain packages.";
|
||||
shortName = "Cyberus Technology employees";
|
||||
};
|
||||
|
||||
darwin = {
|
||||
members = [
|
||||
emily
|
||||
reckenrode
|
||||
toonn
|
||||
];
|
||||
github = "darwin-core";
|
||||
scope = "Maintain core platform support and packages for macOS and other Apple platforms.";
|
||||
shortName = "Darwin";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -366,10 +287,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
docs = {
|
||||
members = [ ];
|
||||
github = "documentation-team";
|
||||
scope = "Maintain nixpkgs/NixOS documentation and tools for building it.";
|
||||
shortName = "Docs";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -410,31 +328,11 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
enlightenment = {
|
||||
members = [ romildo ];
|
||||
github = "enlightenment";
|
||||
scope = "Maintain Enlightenment desktop environment and related packages.";
|
||||
shortName = "Enlightenment";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
# Dummy group for the "everyone else" section
|
||||
feature-freeze-everyone-else = {
|
||||
members = [ ];
|
||||
github = "nixpkgs-committers";
|
||||
scope = "Dummy team for the #everyone else' section during feture freezes, not to be used as package maintainers!";
|
||||
shortName = "Everyone else";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
flutter = {
|
||||
members = [
|
||||
mkg20001
|
||||
RossComputerGuy
|
||||
FlafyDev
|
||||
hacker1024
|
||||
];
|
||||
scope = "Maintain Flutter and Dart-related packages and build tools";
|
||||
shortName = "flutter";
|
||||
enableFeatureFreezePing = false;
|
||||
github = "flutter";
|
||||
};
|
||||
@@ -453,24 +351,11 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
formatter = {
|
||||
members = [
|
||||
piegames
|
||||
infinisil
|
||||
das_j
|
||||
_0x4A6F
|
||||
MattSturgeon
|
||||
jfly
|
||||
# Not in the maintainer list
|
||||
# Sereja313
|
||||
];
|
||||
scope = "Nix formatting team: https://nixos.org/community/teams/formatting/";
|
||||
shortName = "Nix formatting team";
|
||||
github = "nix-formatting";
|
||||
};
|
||||
|
||||
freedesktop = {
|
||||
members = [ jtojnar ];
|
||||
scope = "Maintain Freedesktop.org packages for graphical desktop.";
|
||||
shortName = "freedesktop.org packaging";
|
||||
github = "freedesktop";
|
||||
};
|
||||
|
||||
fslabs = {
|
||||
@@ -495,18 +380,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
geospatial = {
|
||||
members = [
|
||||
autra
|
||||
imincik
|
||||
l0b0
|
||||
nh2
|
||||
nialov
|
||||
sikmir
|
||||
willcohen
|
||||
];
|
||||
github = "geospatial";
|
||||
scope = "Maintain geospatial, remote sensing and OpenStreetMap software.";
|
||||
shortName = "Geospatial";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -523,15 +397,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
gnome = {
|
||||
members = [
|
||||
bobby285271
|
||||
hedning
|
||||
jtojnar
|
||||
dasj19
|
||||
];
|
||||
github = "gnome";
|
||||
scope = "Maintain GNOME desktop environment and platform.";
|
||||
shortName = "GNOME";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -546,17 +412,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
golang = {
|
||||
members = [
|
||||
kalbasit
|
||||
katexochen
|
||||
mic92
|
||||
zowoq
|
||||
qbit
|
||||
mfrw
|
||||
];
|
||||
github = "golang";
|
||||
scope = "Maintain Golang compilers.";
|
||||
shortName = "Go";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -572,15 +428,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
haskell = {
|
||||
members = [
|
||||
cdepillabout
|
||||
maralorn
|
||||
sternenseemann
|
||||
wolfgangwalther
|
||||
];
|
||||
github = "haskell";
|
||||
scope = "Maintain Haskell packages and infrastructure.";
|
||||
shortName = "Haskell";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -606,16 +454,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
hyprland = {
|
||||
members = [
|
||||
donovanglover
|
||||
fufexan
|
||||
johnrtitor
|
||||
khaneliman
|
||||
NotAShelf
|
||||
];
|
||||
github = "hyprland";
|
||||
scope = "Maintain Hyprland compositor and ecosystem";
|
||||
shortName = "Hyprland";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -637,14 +476,6 @@ with lib.maintainers;
|
||||
|
||||
java = {
|
||||
github = "java";
|
||||
members = [
|
||||
chayleaf
|
||||
fliegendewurst
|
||||
infinidoge
|
||||
tomodachi94
|
||||
];
|
||||
shortName = "Java";
|
||||
scope = "Maintainers of the Nixpkgs Java ecosystem (JDK, JVM, Java, Gradle, Maven, Ant, and adjacent projects)";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -683,17 +514,6 @@ with lib.maintainers;
|
||||
|
||||
k3s = {
|
||||
github = "k3s";
|
||||
members = [
|
||||
euank
|
||||
frederictobiasc
|
||||
heywoodlh
|
||||
marcusramberg
|
||||
mic92
|
||||
rorosen
|
||||
wrmilling
|
||||
];
|
||||
scope = "Maintain K3s package, NixOS module, NixOS tests, update script";
|
||||
shortName = "K3s";
|
||||
};
|
||||
|
||||
kodi = {
|
||||
@@ -711,14 +531,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
kubernetes = {
|
||||
members = [
|
||||
johanot
|
||||
offline
|
||||
saschagrunert
|
||||
srhb
|
||||
];
|
||||
scope = "Maintain the Kubernetes package and module";
|
||||
shortName = "Kubernetes";
|
||||
github = "kubernetes";
|
||||
};
|
||||
|
||||
libretro = {
|
||||
@@ -733,58 +546,21 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
linux-kernel = {
|
||||
members = [
|
||||
TredwellGit
|
||||
k900
|
||||
ma27
|
||||
nequissimus
|
||||
qyliss
|
||||
];
|
||||
scope = "Maintain the Linux kernel.";
|
||||
shortName = "Linux Kernel";
|
||||
github = "linux-kernel";
|
||||
};
|
||||
|
||||
lisp = {
|
||||
members = [
|
||||
raskin
|
||||
lukego
|
||||
nagy
|
||||
uthar
|
||||
hraban
|
||||
];
|
||||
github = "lisp";
|
||||
scope = "Maintain the Lisp ecosystem.";
|
||||
shortName = "lisp";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
lix = {
|
||||
members = [
|
||||
raitobezarius
|
||||
qyriad
|
||||
_9999years
|
||||
lf-
|
||||
alois31
|
||||
];
|
||||
scope = "Maintain the Lix package manager inside of Nixpkgs.";
|
||||
shortName = "Lix ecosystem";
|
||||
github = "lix-maintainers";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
llvm = {
|
||||
members = [
|
||||
dtzWill
|
||||
emily
|
||||
ericson2314
|
||||
lovek323
|
||||
qyliss
|
||||
RossComputerGuy
|
||||
rrbutani
|
||||
sternenseemann
|
||||
];
|
||||
github = "llvm";
|
||||
scope = "Maintain LLVM package sets and related packages";
|
||||
shortName = "LLVM";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -796,23 +572,12 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
loongarch64 = {
|
||||
members = [
|
||||
aleksana
|
||||
Cryolitia
|
||||
darkyzhou
|
||||
dramforever
|
||||
wegank
|
||||
];
|
||||
github = "loongarch64";
|
||||
scope = "Maintain LoongArch64 related packages and code";
|
||||
shortName = "LoongArch64";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
lua = {
|
||||
github = "lua";
|
||||
scope = "Maintain the lua ecosystem.";
|
||||
shortName = "lua";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -827,10 +592,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
lumina = {
|
||||
members = [ romildo ];
|
||||
github = "lumina";
|
||||
scope = "Maintain lumina desktop environment and related packages.";
|
||||
shortName = "Lumina";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -846,23 +608,12 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
lxqt = {
|
||||
members = [ romildo ];
|
||||
github = "lxqt";
|
||||
scope = "Maintain LXQt desktop environment and related packages.";
|
||||
shortName = "LXQt";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
marketing = {
|
||||
members = [
|
||||
djacu
|
||||
flyfloh
|
||||
thilobillerbeck
|
||||
tomberek
|
||||
];
|
||||
github = "marketing-team";
|
||||
scope = "Marketing of Nix/NixOS/nixpkgs.";
|
||||
shortName = "Marketing";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -926,15 +677,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
neovim = {
|
||||
members = [
|
||||
GaetanLepage
|
||||
khaneliman
|
||||
mrcjkb
|
||||
perchun
|
||||
];
|
||||
github = "neovim";
|
||||
scope = "Maintain the vim and neovim text editors and related packages.";
|
||||
shortName = "Vim/Neovim";
|
||||
};
|
||||
|
||||
nextcloud = {
|
||||
@@ -992,10 +735,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
ocaml = {
|
||||
members = [ alizter ];
|
||||
github = "ocaml";
|
||||
scope = "Maintain the OCaml compiler and package set.";
|
||||
shortName = "OCaml";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1027,13 +767,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
pantheon = {
|
||||
members = [
|
||||
davidak
|
||||
bobby285271
|
||||
];
|
||||
github = "pantheon";
|
||||
scope = "Maintain Pantheon desktop environment and platform.";
|
||||
shortName = "Pantheon";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1049,36 +783,16 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
php = {
|
||||
members = [
|
||||
aanderse
|
||||
ma27
|
||||
piotrkwiecinski
|
||||
talyz
|
||||
];
|
||||
github = "php";
|
||||
scope = "Maintain PHP related packages and extensions.";
|
||||
shortName = "PHP";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
podman = {
|
||||
members = [
|
||||
saschagrunert
|
||||
vdemeester
|
||||
];
|
||||
github = "podman";
|
||||
scope = "Maintain Podman and CRI-O related packages and modules.";
|
||||
shortName = "Podman";
|
||||
};
|
||||
|
||||
postgres = {
|
||||
members = [
|
||||
thoughtpolice
|
||||
ma27
|
||||
wolfgangwalther
|
||||
];
|
||||
scope = "Maintain the PostgreSQL package and plugins along with the NixOS module.";
|
||||
shortName = "PostgreSQL";
|
||||
github = "postgres";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1093,18 +807,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
qt-kde = {
|
||||
members = [
|
||||
ilya-fedin
|
||||
k900
|
||||
LunNova
|
||||
mjm
|
||||
nickcao
|
||||
SuperSandro2000
|
||||
ttuegel
|
||||
];
|
||||
github = "qt-kde";
|
||||
scope = "Maintain the Qt framework, KDE application suite, Plasma desktop environment and related projects.";
|
||||
shortName = "Qt / KDE";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1130,43 +833,12 @@ with lib.maintainers;
|
||||
shortName = "Red Code Labs";
|
||||
};
|
||||
|
||||
release = {
|
||||
members = [ ];
|
||||
github = "nixos-release-managers";
|
||||
scope = "Manage the current nixpkgs/NixOS release.";
|
||||
shortName = "Release";
|
||||
};
|
||||
|
||||
rocm = {
|
||||
members = [
|
||||
Flakebi
|
||||
GZGavinZhao
|
||||
LunNova
|
||||
mschwaig
|
||||
];
|
||||
github = "rocm";
|
||||
scope = "Maintain ROCm and related packages.";
|
||||
shortName = "ROCm";
|
||||
};
|
||||
|
||||
ruby = {
|
||||
members = [ ];
|
||||
scope = "Maintain the Ruby interpreter and related packages.";
|
||||
shortName = "Ruby";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
rust = {
|
||||
members = [
|
||||
figsoda
|
||||
mic92
|
||||
tjni
|
||||
winter
|
||||
zowoq
|
||||
];
|
||||
github = "rust";
|
||||
scope = "Maintain the Rust compiler toolchain and nixpkgs integration.";
|
||||
shortName = "Rust";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1181,16 +853,7 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
sdl = {
|
||||
members = [
|
||||
evythedemon
|
||||
grimmauld
|
||||
jansol
|
||||
marcin-serwin
|
||||
pbsds
|
||||
];
|
||||
github = "SDL";
|
||||
scope = "Maintain core SDL libraries.";
|
||||
shortName = "SDL";
|
||||
github = "sdl";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1217,16 +880,6 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
stdenv = {
|
||||
members = [
|
||||
artturin
|
||||
emily
|
||||
ericson2314
|
||||
philiptaron
|
||||
reckenrode
|
||||
RossComputerGuy
|
||||
];
|
||||
scope = "Maintain the standard environment and its surrounding logic.";
|
||||
shortName = "stdenv";
|
||||
enableFeatureFreezePing = true;
|
||||
github = "stdenv";
|
||||
};
|
||||
@@ -1256,23 +909,13 @@ with lib.maintainers;
|
||||
samasaur
|
||||
stephank
|
||||
trepetti
|
||||
trundle
|
||||
];
|
||||
scope = "Maintain Swift compiler suite for NixOS.";
|
||||
shortName = "Swift";
|
||||
};
|
||||
|
||||
systemd = {
|
||||
members = [
|
||||
flokli
|
||||
arianvp
|
||||
elvishjerricco
|
||||
aanderse
|
||||
grimmauld
|
||||
];
|
||||
github = "systemd";
|
||||
scope = "Maintain systemd for NixOS.";
|
||||
shortName = "systemd";
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
@@ -1322,14 +965,6 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
xen = {
|
||||
members = [
|
||||
hehongbo
|
||||
lach
|
||||
sigmasquadron
|
||||
rane
|
||||
];
|
||||
scope = "Maintain the Xen Project Hypervisor and the related tooling ecosystem.";
|
||||
shortName = "Xen Project Hypervisor";
|
||||
enableFeatureFreezePing = true;
|
||||
github = "xen-project";
|
||||
};
|
||||
@@ -1347,7 +982,6 @@ with lib.maintainers;
|
||||
|
||||
zig = {
|
||||
members = [
|
||||
figsoda
|
||||
RossComputerGuy
|
||||
];
|
||||
scope = "Maintain the Zig compiler toolchain and nixpkgs integration.";
|
||||
|
||||
@@ -31,6 +31,21 @@ merging is handled.
|
||||
: A path that is contained in the Nix store. This can be a top-level store
|
||||
path like `pkgs.hello` or a descendant like `"${pkgs.hello}/bin/hello"`.
|
||||
|
||||
`types.externalPath`
|
||||
|
||||
: A path that is not contained in the Nix store. Typical use cases are:
|
||||
secrets, password or any other external file.
|
||||
|
||||
::: {.warning}
|
||||
This type only validates that the path is not *currently* in the Nix store.
|
||||
It does NOT prevent the value from being copied to the store later when:
|
||||
- Referenced in a derivation
|
||||
- Used in certain path operations (e.g., `${path}` interpolation)
|
||||
- Passed to functions that copy to the store
|
||||
|
||||
Users must still be careful about how they reference these paths.
|
||||
:::
|
||||
|
||||
`types.pathWith` { *`inStore`* ? `null`, *`absolute`* ? `null` }
|
||||
|
||||
: A filesystem path. Either a string or something that can be coerced
|
||||
@@ -316,22 +331,34 @@ A union of types is a type such that a value is valid when it is valid for at le
|
||||
|
||||
If some values are instances of more than one of the types, it is not possible to distinguish which type they are meant to be instances of. If that's needed, consider using a [sum type](#sec-option-types-sums).
|
||||
|
||||
<!-- SYNC WITH oneOf BELOW -->
|
||||
`types.either` *`t1 t2`*
|
||||
|
||||
: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`.
|
||||
Multiple definitions cannot be merged.
|
||||
|
||||
::: {.warning}
|
||||
`either` and `oneOf` eagerly decide the active type based on the passed types' shallow check method. For composite types like `attrsOf` and `submodule`, which both match all attribute set definitions, the first type argument will be chosen for the returned option value, and this therefore also decides how nested values are checked and merged. For example, `either (attrsOf int) (submodule {...})` will always use `attrsOf int` for any attribute set value, even if it was intended as a submodule. This behavior is a trade-off that keeps the implementation simple and the evaluation order predictable, avoiding unexpected strictness problems such as infinite recursions. When proper type discrimination is needed, consider using a [sum type](#sec-option-types-sums) like `attrTag` instead.
|
||||
:::
|
||||
|
||||
<!-- SYNC WITH either ABOVE -->
|
||||
`types.oneOf` \[ *`t1 t2`* ... \]
|
||||
|
||||
: Type *`t1`* or type *`t2`* and so forth, e.g.
|
||||
`with types; oneOf [ int str bool ]`. Multiple definitions cannot be
|
||||
merged.
|
||||
|
||||
::: {.warning}
|
||||
`either` and `oneOf` eagerly decide the active type based on the passed types' shallow check method. For composite types like `attrsOf` and `submodule`, which both match all attribute set definitions, the first matching type in the list will be chosen for the returned option value, and this therefore also decides how nested values are checked and merged. For example, `oneOf [ (attrsOf int) (submodule {...}) ]` will always use `attrsOf int` for any attribute set value, even if it was intended as a submodule. This behavior is a trade-off that keeps the implementation simple and the evaluation order predictable, avoiding unexpected strictness problems such as infinite recursions. When proper type discrimination is needed, consider using a [sum type](#sec-option-types-sums) like `attrTag` instead.
|
||||
:::
|
||||
|
||||
`types.nullOr` *`t`*
|
||||
|
||||
: `null` or type *`t`*. Multiple definitions are merged according to
|
||||
type *`t`*.
|
||||
|
||||
This is mostly equivalent to `either (enum [ null ]) t`, but `nullOr` provides a `null` fallback for attribute values with `mkIf false` definitions in `lazyAttrsOf (nullOr t)`, whereas `either` would throw an error when the attribute is accessed.
|
||||
|
||||
|
||||
## Sum types {#sec-option-types-sums}
|
||||
|
||||
|
||||
@@ -166,6 +166,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- [twingate](https://docs.twingate.com/docs/linux), a high performance, easy to use zero trust solution that enables access to private resources from any device with better security than a VPN.
|
||||
|
||||
- [iio-niri](https://github.com/Zhaith-Izaliel/iio-niri), a utils that listens to `iio-sensor-proxy` and updates Niri output orientation depending on the accelerometer orientation.
|
||||
|
||||
## Backward Incompatibilities {#sec-release-21.11-incompatibilities}
|
||||
|
||||
- The NixOS VM test framework, `pkgs.nixosTest`/`make-test-python.nix` (`pkgs.testers.nixosTest` since 22.05), now requires detaching commands such as `succeed("foo &")` and `succeed("foo | xclip -i")` to close stdout.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user