Compare commits
380 Commits
freebsd
...
failed-val
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110a9ef105 | ||
|
|
6bc358ba38 | ||
|
|
9aa3cc9c8f | ||
|
|
6de4db100f | ||
|
|
b13143280c | ||
|
|
8c789db05b | ||
|
|
f8b15bfc7f | ||
|
|
5013b38df4 | ||
|
|
247d16a530 | ||
|
|
d1d3ed6241 | ||
|
|
7d26bf8cc7 | ||
|
|
9c186c35fa | ||
|
|
2ed2c79721 | ||
|
|
3c331b7ef3 | ||
|
|
4524235af4 | ||
|
|
86d19956f2 | ||
|
|
4fb61bc5af | ||
|
|
137a55122c | ||
|
|
7658f00bb1 | ||
|
|
a97c5df47c | ||
|
|
371623bf0c | ||
|
|
7128abd217 | ||
|
|
7cc654afa9 | ||
|
|
38663fb434 | ||
|
|
ed6ef7cdf4 | ||
|
|
12db0726e9 | ||
|
|
525245181a | ||
|
|
9302ec5e0e | ||
|
|
9c832a08b0 | ||
|
|
bccdb95a86 | ||
|
|
258d41bfb6 | ||
|
|
dbc235cc62 | ||
|
|
df9b3bfba8 | ||
|
|
14c001d613 | ||
|
|
e791ede495 | ||
|
|
a73cf447ac | ||
|
|
9ff427d7ba | ||
|
|
4dd27a292c | ||
|
|
5ae1b5f88b | ||
|
|
a7c6a42344 | ||
|
|
f363d958a7 | ||
|
|
a44dcbff13 | ||
|
|
12b6d8d208 | ||
|
|
bbdabe4973 | ||
|
|
1d62ccdb3d | ||
|
|
533c6d38aa | ||
|
|
dbc8d0ab64 | ||
|
|
738924b705 | ||
|
|
211cbe4abf | ||
|
|
3513ab13dc | ||
|
|
49e9c14e2f | ||
|
|
25d3c197b8 | ||
|
|
2acb9559d5 | ||
|
|
14c206f05a | ||
|
|
7f3314a68c | ||
|
|
b69576e2b3 | ||
|
|
7b22cd5105 | ||
|
|
1732b4a61b | ||
|
|
819bf13607 | ||
|
|
81e068ab8a | ||
|
|
a30bf96349 | ||
|
|
c0c2a89f05 | ||
|
|
450633aa8c | ||
|
|
671c21db9f | ||
|
|
8089102164 | ||
|
|
f6bc47bc50 | ||
|
|
fa76b6e215 | ||
|
|
44d096f68d | ||
|
|
7e4608a3f8 | ||
|
|
eb56b181ae | ||
|
|
c6ba120000 | ||
|
|
3b9c510ab1 | ||
|
|
a63ac8d98b | ||
|
|
51dadaded4 | ||
|
|
7c1e5b3345 | ||
|
|
4c44a213a3 | ||
|
|
95c5779880 | ||
|
|
c7603c61c8 | ||
|
|
2fe629c5d4 | ||
|
|
1286d5db78 | ||
|
|
cbcb434cb3 | ||
|
|
1935c19705 | ||
|
|
6bdb5e8e09 | ||
|
|
b806440808 | ||
|
|
7f91e91876 | ||
|
|
ab095c029c | ||
|
|
7195250fc4 | ||
|
|
34181afc6a | ||
|
|
d62cfc1c97 | ||
|
|
3a19ea96d9 | ||
|
|
2b310aee13 | ||
|
|
d2f1860ee5 | ||
|
|
a0ce514769 | ||
|
|
0d300112fa | ||
|
|
de7f137f31 | ||
|
|
7fde4f7d6f | ||
|
|
dc29cdf66d | ||
|
|
3e0fb3f8d2 | ||
|
|
04ad66af5f | ||
|
|
fea4a29c0a | ||
|
|
e548700010 | ||
|
|
acd627fa46 | ||
|
|
8251305aff | ||
|
|
73cdfe7066 | ||
|
|
1f7d43e5bd | ||
|
|
363620dd24 | ||
|
|
112f311c50 | ||
|
|
2746985d90 | ||
|
|
e1c9bc0ef6 | ||
|
|
18c3d2348f | ||
|
|
a38ebdd511 | ||
|
|
401e7fe3ad | ||
|
|
b88a22504f | ||
|
|
511d885d60 | ||
|
|
3ef3f525c3 | ||
|
|
53a7d87b93 | ||
|
|
a8c4cfae26 | ||
|
|
d50d4b01c7 | ||
|
|
b6f98b52a4 | ||
|
|
d7ed86ceb1 | ||
|
|
76125f8eb1 | ||
|
|
0d006aedd6 | ||
|
|
04d2122de2 | ||
|
|
8825bfa7fe | ||
|
|
d59b959c87 | ||
|
|
47cae1f72b | ||
|
|
1f607b5def | ||
|
|
53c31c8b29 | ||
|
|
731349639f | ||
|
|
f019f1b75a | ||
|
|
c436b7a32a | ||
|
|
6839f3de55 | ||
|
|
3e0b1705c1 | ||
|
|
c2782d7b84 | ||
|
|
bde745cb3f | ||
|
|
c632c823ce | ||
|
|
4388e3dcb5 | ||
|
|
49da508f46 | ||
|
|
557bbe969e | ||
|
|
4db6bf96b7 | ||
|
|
8dd289099c | ||
|
|
374f8e79a1 | ||
|
|
0b85b023d8 | ||
|
|
ff961fd9e2 | ||
|
|
2eacb3c36f | ||
|
|
169033001d | ||
|
|
0590b13156 | ||
|
|
241abcca86 | ||
|
|
35978ca47b | ||
|
|
d1bdaef04e | ||
|
|
6c8f5ef9f7 | ||
|
|
193ad73ce2 | ||
|
|
f4a0161cb1 | ||
|
|
79211b6110 | ||
|
|
f5f9e32f54 | ||
|
|
725a2f379f | ||
|
|
564593bcb9 | ||
|
|
8ee74792fe | ||
|
|
e82210b3b2 | ||
|
|
625477a7df | ||
|
|
231f3af535 | ||
|
|
cc4aa70e6e | ||
|
|
0bd9d6a28e | ||
|
|
7989e3192d | ||
|
|
1e16a54ee5 | ||
|
|
afade27123 | ||
|
|
0250d50df3 | ||
|
|
c1e2396d58 | ||
|
|
ca94905593 | ||
|
|
e492c64c8e | ||
|
|
e4e8a615fa | ||
|
|
fac34ad20f | ||
|
|
024d3954af | ||
|
|
f0e4af4365 | ||
|
|
5985d67906 | ||
|
|
9bee0fa6ac | ||
|
|
adec28bf85 | ||
|
|
f5e09d9b58 | ||
|
|
f67daa4a87 | ||
|
|
7b8ceb5d2d | ||
|
|
c9211b0b2d | ||
|
|
2fa2c0b09f | ||
|
|
ebf1cf5227 | ||
|
|
3e86d75c9d | ||
|
|
72a548ed6a | ||
|
|
4083eff0c0 | ||
|
|
9c6019dd1a | ||
|
|
82d3662f09 | ||
|
|
01691e1180 | ||
|
|
c0246460a0 | ||
|
|
0c46c2c37f | ||
|
|
58278974b6 | ||
|
|
b853994e7a | ||
|
|
a1b3934a78 | ||
|
|
ae09483498 | ||
|
|
4dcfb36c1e | ||
|
|
2e7bb61a83 | ||
|
|
0eaed891f4 | ||
|
|
6c391b7446 | ||
|
|
d7612f350f | ||
|
|
4fe700b7cb | ||
|
|
3826d51a65 | ||
|
|
615b10cb44 | ||
|
|
e2b984704a | ||
|
|
4c76db8e7c | ||
|
|
08e42e20fa | ||
|
|
1d3ddb21fa | ||
|
|
e3c74f5a13 | ||
|
|
92b10cf3f5 | ||
|
|
2767ae35d9 | ||
|
|
ca86d34077 | ||
|
|
a712445a7a | ||
|
|
52212635db | ||
|
|
bce29ab2cf | ||
|
|
8463fef161 | ||
|
|
d53c7b816b | ||
|
|
4ab579b469 | ||
|
|
0df147b145 | ||
|
|
4ab8ff5b4c | ||
|
|
349d2c58e5 | ||
|
|
bb600e1048 | ||
|
|
088cc176f1 | ||
|
|
4134258c03 | ||
|
|
69fcc2cfc1 | ||
|
|
a92a996dba | ||
|
|
5c0eff24d5 | ||
|
|
03101cc839 | ||
|
|
f3bd18f2b4 | ||
|
|
62018b3a7f | ||
|
|
dc2478fe79 | ||
|
|
8283a20c6a | ||
|
|
051290b155 | ||
|
|
b263bfcecd | ||
|
|
73f6729147 | ||
|
|
1d943f5819 | ||
|
|
aa0dc0d7e7 | ||
|
|
fc33681583 | ||
|
|
f51779ee25 | ||
|
|
c82b67fa05 | ||
|
|
48b600d995 | ||
|
|
0216775ab7 | ||
|
|
d48e04b05a | ||
|
|
b21304fe4c | ||
|
|
3ffeed497a | ||
|
|
da8759bb41 | ||
|
|
f6db80a553 | ||
|
|
1d7ac6603c | ||
|
|
4284497d98 | ||
|
|
e244e32308 | ||
|
|
72c8aa8bb1 | ||
|
|
723656daab | ||
|
|
1cf0fe3186 | ||
|
|
bb9148fd5d | ||
|
|
ccc0a31f39 | ||
|
|
8be1cc6e96 | ||
|
|
347ed8d9ba | ||
|
|
f13aeaf2f1 | ||
|
|
d6973e105c | ||
|
|
3c0a5e0a51 | ||
|
|
695f3bc7e3 | ||
|
|
dc1b2012af | ||
|
|
0fd9ef0cf3 | ||
|
|
d5102ab30c | ||
|
|
0348030ae2 | ||
|
|
048cfb9cd6 | ||
|
|
9fb62805b0 | ||
|
|
3b03872ebf | ||
|
|
97c966cc69 | ||
|
|
9ccbe23056 | ||
|
|
870bb68d38 | ||
|
|
4bc9ae67c7 | ||
|
|
14e355d87d | ||
|
|
79fb9b0d3c | ||
|
|
316fef35dc | ||
|
|
1ed3ae8a9d | ||
|
|
0ef818dd92 | ||
|
|
64c2ee3f45 | ||
|
|
22378ea093 | ||
|
|
408c09a120 | ||
|
|
c736db5320 | ||
|
|
cea85e79ee | ||
|
|
4e776a5be8 | ||
|
|
677b1c0f8f | ||
|
|
f64000e3f4 | ||
|
|
e74ef417db | ||
|
|
4b4895e750 | ||
|
|
1b7ffa53af | ||
|
|
58eabe7479 | ||
|
|
e6f3a193d8 | ||
|
|
26dbda6302 | ||
|
|
48d15ed1fb | ||
|
|
4a2de1dbab | ||
|
|
f155dffe59 | ||
|
|
c940283750 | ||
|
|
14441f9382 | ||
|
|
88275e5723 | ||
|
|
7707d0acad | ||
|
|
766a52ce87 | ||
|
|
2324fe3515 | ||
|
|
b6ca60cb82 | ||
|
|
2600391147 | ||
|
|
1a6f92837a | ||
|
|
14173d761c | ||
|
|
4b6edfcfc7 | ||
|
|
cf7084a67c | ||
|
|
3e7879e6df | ||
|
|
dfcbe70564 | ||
|
|
ed55937002 | ||
|
|
c37df9c87c | ||
|
|
be3a508b74 | ||
|
|
75740fbd75 | ||
|
|
5d3197bb6c | ||
|
|
53ac49f72c | ||
|
|
8e5ca787f4 | ||
|
|
ccf658ed5c | ||
|
|
68839b9545 | ||
|
|
b5289fa130 | ||
|
|
320b2c74ef | ||
|
|
dc769d72cb | ||
|
|
ffe5c1ecb4 | ||
|
|
d8fc55a46e | ||
|
|
a80a5c4dba | ||
|
|
df4e55ffc1 | ||
|
|
7ed0229d1a | ||
|
|
4fb89eb2ea | ||
|
|
6d481efd37 | ||
|
|
e8d780642d | ||
|
|
b21f811ff6 | ||
|
|
0ef6f72c9c | ||
|
|
f93d25c0e7 | ||
|
|
dfb78af184 | ||
|
|
f62b022872 | ||
|
|
41af531392 | ||
|
|
73ebdf2497 | ||
|
|
2c38ad2cfa | ||
|
|
28b74c3143 | ||
|
|
a7fb257ec2 | ||
|
|
920a878eaa | ||
|
|
9d033733f2 | ||
|
|
1030ed1e7d | ||
|
|
2b2c832f0a | ||
|
|
83c43d9311 | ||
|
|
46b6907346 | ||
|
|
b2fb421386 | ||
|
|
4b3ca9bd80 | ||
|
|
0675094861 | ||
|
|
867b69f533 | ||
|
|
e8e9376a7b | ||
|
|
b5f843a565 | ||
|
|
937780ea08 | ||
|
|
0b7f7e4b03 | ||
|
|
6ec88b93ba | ||
|
|
5451ad4a4c | ||
|
|
bd9ce27df0 | ||
|
|
8e35f3ca1e | ||
|
|
d2022189a1 | ||
|
|
d4c6f24e9f | ||
|
|
51c0e6bc63 | ||
|
|
cac8ec3b05 | ||
|
|
2e3ebfb829 | ||
|
|
1b4aa5c1ef | ||
|
|
e74cfc52fe | ||
|
|
11d03893f8 | ||
|
|
73d09e67a7 | ||
|
|
bf320465ae | ||
|
|
90aa2b83b5 | ||
|
|
143bd60136 | ||
|
|
241420a788 | ||
|
|
628d423a12 | ||
|
|
ddd3034909 | ||
|
|
1cce358c40 | ||
|
|
3ba103865d | ||
|
|
9d8d8df729 | ||
|
|
5fe6c53703 | ||
|
|
f0c7fbcdab | ||
|
|
3c0cd73418 | ||
|
|
6bf940d636 | ||
|
|
4ba3b15a10 | ||
|
|
6e733b0544 | ||
|
|
d60a8ee8b0 |
@@ -2,3 +2,5 @@
|
||||
e4f62e46088919428a68bd8014201dc8e379fed7 # !autorebase ./maintainers/format.sh --until-stable
|
||||
# meson re-formatting
|
||||
385e2c3542c707d95e3784f7f6d623f67e77ab61 # !autorebase ./maintainers/format.sh --until-stable
|
||||
# nixfmt 1.0.0
|
||||
1d943f581908f35075a84a3d89c2eba3ff35067f # !autorebase ./maintainers/format.sh --until-stable
|
||||
|
||||
@@ -9,7 +9,7 @@ inputs:
|
||||
install_url:
|
||||
description: "URL of the Nix installer"
|
||||
required: false
|
||||
default: "https://releases.nixos.org/nix/nix-2.30.1/install"
|
||||
default: "https://releases.nixos.org/nix/nix-2.30.2/install"
|
||||
github_token:
|
||||
description: "Github token"
|
||||
required: true
|
||||
|
||||
54
.github/workflows/ci.yml
vendored
54
.github/workflows/ci.yml
vendored
@@ -2,7 +2,15 @@ name: "CI"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
merge_group:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dogfood:
|
||||
description: 'Use dogfood Nix build'
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
permissions: read-all
|
||||
|
||||
@@ -10,12 +18,12 @@ jobs:
|
||||
eval:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
dogfood: true
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
extra_nix_config:
|
||||
experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -48,17 +56,15 @@ jobs:
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
dogfood: true
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
# The sandbox would otherwise be disabled by default on Darwin
|
||||
extra_nix_config: |
|
||||
sandbox = true
|
||||
max-jobs = 1
|
||||
extra_nix_config: "sandbox = true"
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
# Since ubuntu 22.30, unprivileged usernamespaces are no longer allowed to map to the root user:
|
||||
# https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
|
||||
@@ -110,9 +116,9 @@ jobs:
|
||||
name: installer test ${{ matrix.scenario }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Download installer tarball
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: installer-${{matrix.os}}
|
||||
path: out
|
||||
@@ -141,17 +147,17 @@ jobs:
|
||||
check_secrets:
|
||||
permissions:
|
||||
contents: none
|
||||
name: Check Docker secrets present for installer tests
|
||||
name: Check presence of secrets
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
docker: ${{ steps.secret.outputs.docker }}
|
||||
steps:
|
||||
- name: Check for secrets
|
||||
- name: Check for DockerHub secrets
|
||||
id: secret
|
||||
env:
|
||||
_DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
|
||||
run: |
|
||||
echo "::set-output name=docker::${{ env._DOCKER_SECRETS != '' }}"
|
||||
echo "docker=${{ env._DOCKER_SECRETS != '' }}" >> $GITHUB_OUTPUT
|
||||
|
||||
docker_push_image:
|
||||
needs: [tests, vm_tests, check_secrets]
|
||||
@@ -164,13 +170,7 @@ jobs:
|
||||
github.ref_name == 'master'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Check for secrets
|
||||
id: secret
|
||||
env:
|
||||
_DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
|
||||
run: |
|
||||
echo "::set-output name=docker::${{ env._DOCKER_SECRETS != '' }}"
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: cachix/install-nix-action@v31
|
||||
@@ -216,10 +216,10 @@ jobs:
|
||||
vm_tests:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
dogfood: true
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
extra_nix_config:
|
||||
experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -237,20 +237,20 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout nix
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Checkout flake-regressions
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: NixOS/flake-regressions
|
||||
path: flake-regressions
|
||||
- name: Checkout flake-regressions-data
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: NixOS/flake-regressions-data
|
||||
path: flake-regressions/tests
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
dogfood: true
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
extra_nix_config:
|
||||
experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -265,13 +265,13 @@ jobs:
|
||||
github.event_name == 'push' &&
|
||||
github.ref_name == 'master'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
dogfood: true
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
extra_nix_config: |
|
||||
experimental-features = flakes nix-command ca-derivations impure-derivations
|
||||
max-jobs = 1
|
||||
|
||||
2
.github/workflows/labels.yml
vendored
2
.github/workflows/labels.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.repository_owner == 'NixOS'
|
||||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
- uses: actions/labeler@v6
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sync-labels: false
|
||||
|
||||
11
.mergify.yml
11
.mergify.yml
@@ -161,3 +161,14 @@ pull_request_rules:
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.31
|
||||
conditions:
|
||||
- label=backport 2.31-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.31-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
nixFlake ? builtins.getFlake ("git+file://" + toString ../../..),
|
||||
system ? builtins.currentSystem,
|
||||
pkgs ? nixFlake.inputs.nixpkgs.legacyPackages.${system},
|
||||
nixComponents ? (
|
||||
nixFlake.lib.makeComponents {
|
||||
inherit pkgs;
|
||||
inherit getStdenv;
|
||||
}
|
||||
),
|
||||
getStdenv ? p: p.stdenv,
|
||||
componentTestsPrefix ? "",
|
||||
withSanitizers ? false,
|
||||
@@ -49,13 +55,11 @@ let
|
||||
};
|
||||
|
||||
# Done in a pre-configure hook, because $NIX_BUILD_TOP needs to be substituted.
|
||||
preConfigure =
|
||||
prevAttrs.preConfigure or ""
|
||||
+ ''
|
||||
mappingFlag=" -fcoverage-prefix-map=$NIX_BUILD_TOP/${finalAttrs.src.name}=${finalAttrs.src}"
|
||||
CFLAGS+="$mappingFlag"
|
||||
CXXFLAGS+="$mappingFlag"
|
||||
'';
|
||||
preConfigure = prevAttrs.preConfigure or "" + ''
|
||||
mappingFlag=" -fcoverage-prefix-map=$NIX_BUILD_TOP/${finalAttrs.src.name}=${finalAttrs.src}"
|
||||
CFLAGS+="$mappingFlag"
|
||||
CXXFLAGS+="$mappingFlag"
|
||||
'';
|
||||
};
|
||||
|
||||
componentOverrides =
|
||||
@@ -64,18 +68,13 @@ let
|
||||
in
|
||||
|
||||
rec {
|
||||
nixComponents =
|
||||
(nixFlake.lib.makeComponents {
|
||||
inherit pkgs;
|
||||
inherit getStdenv;
|
||||
}).overrideScope
|
||||
(
|
||||
final: prev: {
|
||||
nix-store-tests = prev.nix-store-tests.override { withBenchmarks = true; };
|
||||
nixComponentsInstrumented = nixComponents.overrideScope (
|
||||
final: prev: {
|
||||
nix-store-tests = prev.nix-store-tests.override { withBenchmarks = true; };
|
||||
|
||||
mesonComponentOverrides = lib.composeManyExtensions componentOverrides;
|
||||
}
|
||||
);
|
||||
mesonComponentOverrides = lib.composeManyExtensions componentOverrides;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
Top-level tests for the flake outputs, as they would be built by hydra.
|
||||
@@ -120,15 +119,15 @@ rec {
|
||||
lib.concatMapAttrs (testName: test: {
|
||||
"${componentTestsPrefix}${pkgName}-${testName}" = test;
|
||||
}) (pkg.tests or { })
|
||||
) nixComponents)
|
||||
) nixComponentsInstrumented)
|
||||
// lib.optionalAttrs (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) {
|
||||
"${componentTestsPrefix}nix-functional-tests" = nixComponents.nix-functional-tests;
|
||||
"${componentTestsPrefix}nix-functional-tests" = nixComponentsInstrumented.nix-functional-tests;
|
||||
};
|
||||
|
||||
codeCoverage =
|
||||
let
|
||||
componentsTestsToProfile =
|
||||
(builtins.mapAttrs (n: v: nixComponents.${n}.tests.run) {
|
||||
(builtins.mapAttrs (n: v: nixComponentsInstrumented.${n}.tests.run) {
|
||||
"nix-util-tests" = { };
|
||||
"nix-store-tests" = { };
|
||||
"nix-fetchers-tests" = { };
|
||||
@@ -136,7 +135,7 @@ rec {
|
||||
"nix-flake-tests" = { };
|
||||
})
|
||||
// {
|
||||
inherit (nixComponents) nix-functional-tests;
|
||||
inherit (nixComponentsInstrumented) nix-functional-tests;
|
||||
};
|
||||
|
||||
coverageProfileDrvs = lib.mapAttrs (
|
||||
@@ -170,12 +169,13 @@ rec {
|
||||
|
||||
coverageReports =
|
||||
let
|
||||
nixComponentDrvs = lib.filter (lib.isDerivation) (lib.attrValues nixComponents);
|
||||
nixComponentDrvs = lib.filter (lib.isDerivation) (lib.attrValues nixComponentsInstrumented);
|
||||
in
|
||||
pkgs.runCommand "code-coverage-report"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
pkgs.llvmPackages.libllvm
|
||||
pkgs.jq
|
||||
];
|
||||
__structuredAttrs = true;
|
||||
nixComponents = nixComponentDrvs;
|
||||
@@ -201,6 +201,24 @@ rec {
|
||||
echo
|
||||
} >> $out/index.txt
|
||||
|
||||
llvm-cov export $arguments -instr-profile ${mergedProfdata} -format=text > $out/coverage.json
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
|
||||
coverageTotals=$(jq ".data[0].totals" $out/coverage.json)
|
||||
|
||||
# Mostly inline from pkgs/build-support/setup-hooks/make-coverage-analysis-report.sh [1],
|
||||
# which we can't use here, because we rely on LLVM's infra for source code coverage collection.
|
||||
# [1]: https://github.com/NixOS/nixpkgs/blob/67bb48c4c8e327417d6d5aa7e538244b209e852b/pkgs/build-support/setup-hooks/make-coverage-analysis-report.sh#L16
|
||||
declare -A metricsArray=(["lineCoverage"]="lines" ["functionCoverage"]="functions" ["branchCoverage"]="branches")
|
||||
|
||||
for metricName in "''\${!metricsArray[@]}"; do
|
||||
key="''\${metricsArray[$metricName]}"
|
||||
metric=$(echo "$coverageTotals" | jq ".$key.percent * 10 | round / 10")
|
||||
echo "$metricName $metric %" >> $out/nix-support/hydra-metrics
|
||||
done
|
||||
|
||||
echo "report coverage $out" >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
in
|
||||
assert withCoverage;
|
||||
|
||||
@@ -46,24 +46,23 @@ mkMesonDerivation (finalAttrs: {
|
||||
];
|
||||
|
||||
# Hack for sake of the dev shell
|
||||
passthru.externalNativeBuildInputs =
|
||||
[
|
||||
meson
|
||||
ninja
|
||||
(lib.getBin lowdown-unsandboxed)
|
||||
mdbook
|
||||
mdbook-linkcheck
|
||||
jq
|
||||
python3
|
||||
rsync
|
||||
changelog-d
|
||||
]
|
||||
++ lib.optionals (!officialRelease) [
|
||||
# When not an official release, we likely have changelog entries that have
|
||||
# yet to be rendered.
|
||||
# When released, these are rendered into a committed file to save a dependency.
|
||||
changelog-d
|
||||
];
|
||||
passthru.externalNativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
(lib.getBin lowdown-unsandboxed)
|
||||
mdbook
|
||||
mdbook-linkcheck
|
||||
jq
|
||||
python3
|
||||
rsync
|
||||
changelog-d
|
||||
]
|
||||
++ lib.optionals (!officialRelease) [
|
||||
# When not an official release, we likely have changelog entries that have
|
||||
# yet to be rendered.
|
||||
# When released, these are rendered into a committed file to save a dependency.
|
||||
changelog-d
|
||||
];
|
||||
|
||||
nativeBuildInputs = finalAttrs.passthru.externalNativeBuildInputs ++ [
|
||||
nix-cli
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
synopsis: "`build-cores = 0` now auto-detects CPU cores"
|
||||
prs: [13402]
|
||||
---
|
||||
|
||||
When `build-cores` is set to `0`, nix now automatically detects the number of available CPU cores and passes this value via `NIX_BUILD_CORES`, instead of passing `0` directly. This matches the behavior when `build-cores` is unset. This prevents the builder from having to detect the number of cores.
|
||||
23
doc/manual/rl-next/c-api-recoverable-errors.md
Normal file
23
doc/manual/rl-next/c-api-recoverable-errors.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
synopsis: "C API: Errors returned from your primops are not treated as recoverable by default"
|
||||
prs: [13930]
|
||||
---
|
||||
|
||||
Nix 2.32 by default remembers the error in the thunk that triggered it.
|
||||
|
||||
Previously the following sequence of events worked:
|
||||
|
||||
1. Have a thunk that invokes a primop that's defined through the C API
|
||||
2. The primop returns an error
|
||||
3. Force the thunk again
|
||||
4. The primop returns a value
|
||||
5. The thunk evaluated successfully
|
||||
|
||||
**Resolution**
|
||||
|
||||
C API consumers that rely on this must change their recoverable error calls:
|
||||
|
||||
```diff
|
||||
-nix_set_err_msg(context, NIX_ERR_*, msg);
|
||||
+nix_set_err_msg(context, NIX_ERR_RECOVERABLE, msg);
|
||||
```
|
||||
6
doc/manual/rl-next/dropped-compat.md
Normal file
6
doc/manual/rl-next/dropped-compat.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
synopsis: "Removed support for daemons and clients older than Nix 2.0"
|
||||
prs: [13951]
|
||||
---
|
||||
|
||||
We have dropped support in the daemon worker protocol for daemons and clients that don't speak at least version 18 of the protocol. This first Nix release that supports this version is Nix 2.0, released in February 2018.
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
synopsis: "Add support for user@address:port syntax in store URIs"
|
||||
prs: [3425]
|
||||
issues: [7044]
|
||||
---
|
||||
|
||||
It's now possible to specify the port used for the SSH stores directly in the store URL in accordance with [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986). Previously the only way to specify custom ports was via `ssh_config` or `NIX_SSHOPTS` environment variable, because Nix incorrectly passed the port number together with the host name to the SSH executable. This has now been fixed.
|
||||
|
||||
This change affects [store references](@docroot@/store/types/index.md#store-url-format) passed via the `--store` and similar flags in CLI as well as in the configuration for [remote builders](@docroot@/command-ref/conf-file.md#conf-builders). For example, the following store URIs now work:
|
||||
|
||||
- `ssh://127.0.0.1:2222`
|
||||
- `ssh://[b573:6a48:e224:840b:6007:6275:f8f7:ebf3]:22`
|
||||
- `ssh-ng://[b573:6a48:e224:840b:6007:6275:f8f7:ebf3]:22`
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
synopsis: "Represent IPv6 RFC4007 ZoneId literals in conformance with RFC6874"
|
||||
prs: [13445]
|
||||
---
|
||||
|
||||
Prior versions of Nix since [#4646](https://github.com/NixOS/nix/pull/4646) accepted [IPv6 scoped addresses](https://datatracker.ietf.org/doc/html/rfc4007) in URIs like [store references](@docroot@/store/types/index.md#store-url-format) in the textual representation with a literal percent character: `[fe80::1%18]`. This was ambiguous, because the the percent literal `%` is reserved by [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986), since it's used to indicate percent encoding. Nix now requires that the percent `%` symbol is percent-encoded as `%25`. This implements [RFC6874](https://datatracker.ietf.org/doc/html/rfc6874), which defines the representation of zone identifiers in URIs. The example from above now has to be specified as `[fe80::1%2518]`.
|
||||
6
doc/manual/rl-next/shorter-build-dir-names.md
Normal file
6
doc/manual/rl-next/shorter-build-dir-names.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
synopsis: "Temporary build directories no longer include derivation names"
|
||||
prs: [13839]
|
||||
---
|
||||
|
||||
Temporary build directories created during derivation builds no longer include the derivation name in their path to avoid build failures when the derivation name is too long. This change ensures predictable prefix lengths for build directories under `/nix/var/nix/builds`.
|
||||
@@ -138,6 +138,7 @@
|
||||
- [Contributing](development/contributing.md)
|
||||
- [Releases](release-notes/index.md)
|
||||
{{#include ./SUMMARY-rl-next.md}}
|
||||
- [Release 2.31 (2025-08-21)](release-notes/rl-2.31.md)
|
||||
- [Release 2.30 (2025-07-07)](release-notes/rl-2.30.md)
|
||||
- [Release 2.29 (2025-05-14)](release-notes/rl-2.29.md)
|
||||
- [Release 2.28 (2025-04-02)](release-notes/rl-2.28.md)
|
||||
|
||||
@@ -75,7 +75,7 @@ Most Nix commands interpret the following environment variables:
|
||||
- <span id="env-NIX_CONF_DIR">[`NIX_CONF_DIR`](#env-NIX_CONF_DIR)</span>
|
||||
|
||||
Overrides the location of the system Nix configuration directory
|
||||
(default `prefix/etc/nix`).
|
||||
(default `sysconfdir/nix`, i.e. `/etc/nix` on most systems).
|
||||
|
||||
- <span id="env-NIX_CONFIG">[`NIX_CONFIG`](#env-NIX_CONFIG)</span>
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ $ nix-shell --attr devShells.x86_64-linux.native-clangStdenvPackages
|
||||
To build Nix itself in this shell:
|
||||
|
||||
```console
|
||||
[nix-shell]$ mesonFlags+=" --prefix=$(pwd)/outputs/out"
|
||||
[nix-shell]$ out="$(pwd)/outputs/out" dev=$out debug=$out mesonFlags+=" --prefix=${out}"
|
||||
[nix-shell]$ dontAddPrefix=1 configurePhase
|
||||
[nix-shell]$ buildPhase
|
||||
```
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
- Bash Shell. The `./configure` script relies on bashisms, so Bash is
|
||||
required.
|
||||
|
||||
- A version of GCC or Clang that supports C++20.
|
||||
- A version of GCC or Clang that supports C++23.
|
||||
|
||||
- `pkg-config` to locate dependencies. If your distribution does not
|
||||
provide it, you can get it from
|
||||
|
||||
@@ -41,6 +41,38 @@ There may also be references to Nix in
|
||||
|
||||
which you may remove.
|
||||
|
||||
### FreeBSD
|
||||
|
||||
1. Stop and remove the Nix daemon service:
|
||||
|
||||
```console
|
||||
sudo service nix-daemon stop
|
||||
sudo rm -f /usr/local/etc/rc.d/nix-daemon
|
||||
sudo sysrc -x nix_daemon_enable
|
||||
```
|
||||
|
||||
2. Remove files created by Nix:
|
||||
|
||||
```console
|
||||
sudo rm -rf /etc/nix /usr/local/etc/profile.d/nix.sh /nix ~root/.nix-channels ~root/.nix-defexpr ~root/.nix-profile ~root/.cache/nix
|
||||
```
|
||||
|
||||
3. Remove build users and their group:
|
||||
|
||||
```console
|
||||
for i in $(seq 1 32); do
|
||||
sudo pw userdel nixbld$i
|
||||
done
|
||||
sudo pw groupdel nixbld
|
||||
```
|
||||
|
||||
4. There may also be references to Nix in:
|
||||
- `/usr/local/etc/bashrc`
|
||||
- `/usr/local/etc/zshrc`
|
||||
- Shell configuration files in users' home directories
|
||||
|
||||
which you may remove.
|
||||
|
||||
### macOS
|
||||
|
||||
> **Updating to macOS 15 Sequoia**
|
||||
|
||||
96
doc/manual/source/release-notes/rl-2.31.md
Normal file
96
doc/manual/source/release-notes/rl-2.31.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Release 2.31.0 (2025-08-21)
|
||||
|
||||
- `build-cores = 0` now auto-detects CPU cores [#13402](https://github.com/NixOS/nix/pull/13402)
|
||||
|
||||
When `build-cores` is set to `0`, Nix now automatically detects the number of available CPU cores and passes this value via `NIX_BUILD_CORES`, instead of passing `0` directly. This matches the behavior when `build-cores` is unset. This prevents the builder from having to detect the number of cores.
|
||||
|
||||
- Fix Git LFS SSH issues [#13337](https://github.com/NixOS/nix/issues/13337) [#13743](https://github.com/NixOS/nix/pull/13743)
|
||||
|
||||
Fixed some outstanding issues with Git LFS and SSH.
|
||||
|
||||
* Added support for `NIX_SSHOPTS`.
|
||||
* Properly use the parsed port from URL.
|
||||
* Better use of the response of `git-lfs-authenticate` to determine API endpoint when the API is not exposed on port 443.
|
||||
|
||||
- Add support for `user@address:port` syntax in store URIs [#7044](https://github.com/NixOS/nix/issues/7044) [#3425](https://github.com/NixOS/nix/pull/3425)
|
||||
|
||||
It's now possible to specify the port used for SSH stores directly in the store URL in accordance with [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986). Previously the only way to specify custom ports was via `ssh_config` or the `NIX_SSHOPTS` environment variable, because Nix incorrectly passed the port number together with the host name to the SSH executable.
|
||||
|
||||
This change affects [store references](@docroot@/store/types/index.md#store-url-format) passed via the `--store` and similar flags in CLI as well as in the configuration for [remote builders](@docroot@/command-ref/conf-file.md#conf-builders). For example, the following store URIs now work:
|
||||
|
||||
- `ssh://127.0.0.1:2222`
|
||||
- `ssh://[b573:6a48:e224:840b:6007:6275:f8f7:ebf3]:22`
|
||||
- `ssh-ng://[b573:6a48:e224:840b:6007:6275:f8f7:ebf3]:22`
|
||||
|
||||
- Represent IPv6 RFC4007 ZoneId literals in conformance with RFC6874 [#13445](https://github.com/NixOS/nix/pull/13445)
|
||||
|
||||
Prior versions of Nix since [#4646](https://github.com/NixOS/nix/pull/4646) accepted [IPv6 scoped addresses](https://datatracker.ietf.org/doc/html/rfc4007) in URIs like [store references](@docroot@/store/types/index.md#store-url-format) in the textual representation with a literal percent character: `[fe80::1%18]`. This was ambiguous, because the the percent literal `%` is reserved by [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986), since it's used to indicate percent encoding. Nix now requires that the percent `%` symbol is percent-encoded as `%25`. This implements [RFC6874](https://datatracker.ietf.org/doc/html/rfc6874), which defines the representation of zone identifiers in URIs. The example from above now has to be specified as `[fe80::1%2518]`.
|
||||
|
||||
- Use WAL mode for SQLite cache databases [#13800](https://github.com/NixOS/nix/pull/13800)
|
||||
|
||||
Previously, Nix used SQLite's "truncate" mode for caches. However, this could cause a Nix process to block if another process was updating the cache. This was a problem for the flake evaluation cache in particular, since it uses long-running transactions. Thus, concurrent Nix commands operating on the same flake could be blocked for an unbounded amount of time. WAL mode avoids this problem.
|
||||
|
||||
This change required updating the versions of the SQLite caches. For instance, `eval-cache-v5.sqlite` is now `eval-cache-v6.sqlite`.
|
||||
|
||||
- Enable parallel marking in bdwgc [#13708](https://github.com/NixOS/nix/pull/13708)
|
||||
|
||||
Previously marking was done by only one thread, which takes a long time if the heap gets big. Enabling parallel marking speeds up evaluation a lot, for example (on a Ryzen 9 5900X 12-Core):
|
||||
|
||||
* `nix search nixpkgs` from 24.3s to 18.9s.
|
||||
* Evaluating the `NixOS/nix/2.21.2` flake regression test from 86.1s to 71.2s.
|
||||
|
||||
- New command `nix flake prefetch-inputs` [#13565](https://github.com/NixOS/nix/pull/13565)
|
||||
|
||||
This command fetches all inputs of a flake in parallel. This can be a lot faster than the serialized on-demand fetching during regular flake evaluation. The downside is that it may fetch inputs that aren't normally used.
|
||||
|
||||
- Add `warn-short-path-literals` setting [#13489](https://github.com/NixOS/nix/pull/13489)
|
||||
|
||||
This setting, when enabled, causes Nix to emit warnings when encountering relative path literals that don't start with `.` or `/`, for instance suggesting that `foo/bar` should be rewritten to `./foo/bar`.
|
||||
|
||||
- When updating a lock, respect the input's lock file [#13437](https://github.com/NixOS/nix/pull/13437)
|
||||
|
||||
For example, if a flake has a lock for `a` and `a/b`, and we change the flakeref for `a`, previously Nix would fetch the latest version of `b` rather than using the lock for `b` from `a`.
|
||||
|
||||
- Implement support for Git hashing with SHA-256 [#13543](https://github.com/NixOS/nix/pull/13543)
|
||||
|
||||
The experimental support for [Git-hashing](@docroot@/development/experimental-features.md#xp-feature-git-hashing) store objects now also includes support for SHA-256, not just SHA-1, in line with upstream Git.
|
||||
|
||||
## Contributors
|
||||
|
||||
This release was made possible by the following 34 contributors:
|
||||
|
||||
- John Soo [**(@jsoo1)**](https://github.com/jsoo1)
|
||||
- Alan Urmancheev [**(@alurm)**](https://github.com/alurm)
|
||||
- Manse [**(@PedroManse)**](https://github.com/PedroManse)
|
||||
- Pol Dellaiera [**(@drupol)**](https://github.com/drupol)
|
||||
- DavHau [**(@DavHau)**](https://github.com/DavHau)
|
||||
- Leandro Emmanuel Reina Kiperman [**(@kip93)**](https://github.com/kip93)
|
||||
- h0nIg [**(@h0nIg)**](https://github.com/h0nIg)
|
||||
- Philip Taron [**(@philiptaron)**](https://github.com/philiptaron)
|
||||
- Eelco Dolstra [**(@edolstra)**](https://github.com/edolstra)
|
||||
- Connor Baker [**(@ConnorBaker)**](https://github.com/ConnorBaker)
|
||||
- kenji [**(@a-kenji)**](https://github.com/a-kenji)
|
||||
- Oleksandr Knyshuk [**(@k1gen)**](https://github.com/k1gen)
|
||||
- Maciej Krüger [**(@mkg20001)**](https://github.com/mkg20001)
|
||||
- Justin Bailey [**(@jgbailey-well)**](https://github.com/jgbailey-well)
|
||||
- Emily [**(@emilazy)**](https://github.com/emilazy)
|
||||
- Volker Diels-Grabsch [**(@vog)**](https://github.com/vog)
|
||||
- gustavderdrache [**(@gustavderdrache)**](https://github.com/gustavderdrache)
|
||||
- Elliot Cameron [**(@de11n)**](https://github.com/de11n)
|
||||
- Alexander V. Nikolaev [**(@avnik)**](https://github.com/avnik)
|
||||
- tomberek [**(@tomberek)**](https://github.com/tomberek)
|
||||
- Matthew Kenigsberg [**(@mkenigs)**](https://github.com/mkenigs)
|
||||
- Sergei Zimmerman [**(@xokdvium)**](https://github.com/xokdvium)
|
||||
- Cosima Neidahl [**(@OPNA2608)**](https://github.com/OPNA2608)
|
||||
- John Ericson [**(@Ericson2314)**](https://github.com/Ericson2314)
|
||||
- m4dc4p [**(@m4dc4p)**](https://github.com/m4dc4p)
|
||||
- Graham Christensen [**(@grahamc)**](https://github.com/grahamc)
|
||||
- Jason Yundt [**(@Jayman2000)**](https://github.com/Jayman2000)
|
||||
- Jens Petersen [**(@juhp)**](https://github.com/juhp)
|
||||
- the-sun-will-rise-tomorrow [**(@the-sun-will-rise-tomorrow)**](https://github.com/the-sun-will-rise-tomorrow)
|
||||
- Farid Zakaria [**(@fzakaria)**](https://github.com/fzakaria)
|
||||
- AGawas [**(@aln730)**](https://github.com/aln730)
|
||||
- Robert Hensing [**(@roberth)**](https://github.com/roberth)
|
||||
- Dmitry Bogatov [**(@KAction)**](https://github.com/KAction)
|
||||
- Jörg Thalheim [**(@Mic92)**](https://github.com/Mic92)
|
||||
- Philipp Otterbein
|
||||
@@ -9,7 +9,7 @@ This is where Nix distinguishes itself.
|
||||
|
||||
## Store Derivation {#store-derivation}
|
||||
|
||||
A derivation is a specification for running an executable on precisely defined input to produce on more [store objects][store object].
|
||||
A derivation is a specification for running an executable on precisely defined input to produce one or more [store objects][store object].
|
||||
These store objects are known as the derivation's *outputs*.
|
||||
|
||||
Derivations are *built*, in which case the process is spawned according to the spec, and when it exits, required to leave behind files which will (after post-processing) become the outputs of the derivation.
|
||||
|
||||
106
docker.nix
106
docker.nix
@@ -65,62 +65,61 @@ let
|
||||
iana-etc
|
||||
gitMinimal
|
||||
openssh
|
||||
] ++ extraPkgs;
|
||||
]
|
||||
++ extraPkgs;
|
||||
|
||||
users =
|
||||
{
|
||||
users = {
|
||||
|
||||
root = {
|
||||
uid = 0;
|
||||
shell = lib.getExe bashInteractive;
|
||||
home = "/root";
|
||||
gid = 0;
|
||||
groups = [ "root" ];
|
||||
description = "System administrator";
|
||||
};
|
||||
|
||||
nobody = {
|
||||
uid = 65534;
|
||||
shell = lib.getExe' shadow "nologin";
|
||||
home = "/var/empty";
|
||||
gid = 65534;
|
||||
groups = [ "nobody" ];
|
||||
description = "Unprivileged account (don't use!)";
|
||||
};
|
||||
|
||||
}
|
||||
// lib.optionalAttrs (uid != 0) {
|
||||
"${uname}" = {
|
||||
uid = uid;
|
||||
shell = lib.getExe bashInteractive;
|
||||
home = "/home/${uname}";
|
||||
gid = gid;
|
||||
groups = [ "${gname}" ];
|
||||
description = "Nix user";
|
||||
};
|
||||
}
|
||||
// lib.listToAttrs (
|
||||
map (n: {
|
||||
name = "nixbld${toString n}";
|
||||
value = {
|
||||
uid = 30000 + n;
|
||||
gid = 30000;
|
||||
groups = [ "nixbld" ];
|
||||
description = "Nix build user ${toString n}";
|
||||
};
|
||||
}) (lib.lists.range 1 32)
|
||||
);
|
||||
|
||||
groups =
|
||||
{
|
||||
root.gid = 0;
|
||||
nixbld.gid = 30000;
|
||||
nobody.gid = 65534;
|
||||
}
|
||||
// lib.optionalAttrs (gid != 0) {
|
||||
"${gname}".gid = gid;
|
||||
root = {
|
||||
uid = 0;
|
||||
shell = lib.getExe bashInteractive;
|
||||
home = "/root";
|
||||
gid = 0;
|
||||
groups = [ "root" ];
|
||||
description = "System administrator";
|
||||
};
|
||||
|
||||
nobody = {
|
||||
uid = 65534;
|
||||
shell = lib.getExe' shadow "nologin";
|
||||
home = "/var/empty";
|
||||
gid = 65534;
|
||||
groups = [ "nobody" ];
|
||||
description = "Unprivileged account (don't use!)";
|
||||
};
|
||||
|
||||
}
|
||||
// lib.optionalAttrs (uid != 0) {
|
||||
"${uname}" = {
|
||||
uid = uid;
|
||||
shell = lib.getExe bashInteractive;
|
||||
home = "/home/${uname}";
|
||||
gid = gid;
|
||||
groups = [ "${gname}" ];
|
||||
description = "Nix user";
|
||||
};
|
||||
}
|
||||
// lib.listToAttrs (
|
||||
map (n: {
|
||||
name = "nixbld${toString n}";
|
||||
value = {
|
||||
uid = 30000 + n;
|
||||
gid = 30000;
|
||||
groups = [ "nixbld" ];
|
||||
description = "Nix build user ${toString n}";
|
||||
};
|
||||
}) (lib.lists.range 1 32)
|
||||
);
|
||||
|
||||
groups = {
|
||||
root.gid = 0;
|
||||
nixbld.gid = 30000;
|
||||
nobody.gid = 65534;
|
||||
}
|
||||
// lib.optionalAttrs (gid != 0) {
|
||||
"${gname}".gid = gid;
|
||||
};
|
||||
|
||||
userToPasswd = (
|
||||
k:
|
||||
{
|
||||
@@ -282,7 +281,10 @@ let
|
||||
|
||||
# may get replaced by pkgs.dockerTools.caCertificates
|
||||
mkdir -p $out/etc/ssl/certs
|
||||
# Old NixOS compatibility.
|
||||
ln -s /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt $out/etc/ssl/certs
|
||||
# NixOS canonical location
|
||||
ln -s /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt $out/etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
cat $passwdContentsPath > $out/etc/passwd
|
||||
echo "" >> $out/etc/passwd
|
||||
|
||||
8
flake.lock
generated
8
flake.lock
generated
@@ -63,16 +63,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1747179050,
|
||||
"narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=",
|
||||
"lastModified": 1756178832,
|
||||
"narHash": "sha256-O2CIn7HjZwEGqBrwu9EU76zlmA5dbmna7jL1XUmAId8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e",
|
||||
"rev": "d98ce345cdab58477ca61855540999c86577d19d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixos-25.05-small",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
description = "The purely functional package manager";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05-small";
|
||||
|
||||
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
||||
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
|
||||
|
||||
@@ -46,7 +46,7 @@ The team meets twice a week (times are denoted in the [Europe/Amsterdam](https:/
|
||||
- mark it as draft if it is blocked on the contributor
|
||||
- escalate it back to the team by moving it to To discuss, and leaving a comment as to why the issue needs to be discussed again.
|
||||
|
||||
- Work meeting: Mondays 14:00-16:00 Europe/Amsterdam see [calendar](https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com).
|
||||
- Work meeting: Mondays 18:00-20:00 Europe/Amsterdam; see [calendar](https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com).
|
||||
|
||||
1. Code review on pull requests from [In review](#in-review).
|
||||
2. Other chores and tasks.
|
||||
|
||||
@@ -185,5 +185,23 @@
|
||||
"gwenn.lebihan7@gmail.com": "gwennlbh",
|
||||
"hey@ewen.works": "gwennlbh",
|
||||
"matt@sturgeon.me.uk": "MattSturgeon",
|
||||
"pbsds@hotmail.com": "pbsds"
|
||||
"pbsds@hotmail.com": "pbsds",
|
||||
"sergei@zimmerman.foo": "xokdvium",
|
||||
"v@njh.eu": "vog",
|
||||
"pedro.manse@dmk3.com.br": "PedroManse",
|
||||
"arnavgawas707@gmail.com": "aln730",
|
||||
"mkg20001@gmail.com": "mkg20001",
|
||||
"avn@avnik.info": "avnik",
|
||||
"olk@disr.it": "k1gen",
|
||||
"108410815+alurm@users.noreply.github.com": "alurm",
|
||||
"kaction.cc@gmail.com": "KAction",
|
||||
"juhpetersen@gmail.com": "juhp",
|
||||
"opna2608@protonmail.com": "OPNA2608",
|
||||
"jgbailey@gmail.com": "m4dc4p",
|
||||
"justin.bailey@well.co": "jgbailey-well",
|
||||
"130508846+de11n@users.noreply.github.com": "de11n",
|
||||
"ConnorBaker01@Gmail.com": "ConnorBaker",
|
||||
"jsoo1@asu.edu": "jsoo1",
|
||||
"hsngrmpf+github@gmail.com": "DavHau",
|
||||
"matthew@floxdev.com": "mkenigs"
|
||||
}
|
||||
@@ -162,5 +162,20 @@
|
||||
"pbsds": "Peder Bergebakken Sundt",
|
||||
"egorkonovalov": "Egor Konovalov",
|
||||
"jayeshv": "jayeshv",
|
||||
"vcunat": "Vladim\u00edr \u010cun\u00e1t"
|
||||
"vcunat": "Vladim\u00edr \u010cun\u00e1t",
|
||||
"mkenigs": "Matthew Kenigsberg",
|
||||
"alurm": "Alan Urmancheev",
|
||||
"jgbailey-well": "Justin Bailey",
|
||||
"k1gen": "Oleksandr Knyshuk",
|
||||
"juhp": "Jens Petersen",
|
||||
"de11n": "Elliot Cameron",
|
||||
"jsoo1": "John Soo",
|
||||
"m4dc4p": null,
|
||||
"PedroManse": "Manse",
|
||||
"OPNA2608": "Cosima Neidahl",
|
||||
"mkg20001": "Maciej Kr\u00fcger",
|
||||
"avnik": "Alexander V. Nikolaev",
|
||||
"DavHau": null,
|
||||
"aln730": "AGawas",
|
||||
"vog": "Volker Diels-Grabsch"
|
||||
}
|
||||
@@ -3,5 +3,9 @@
|
||||
|
||||
- https://github.com/NixOS/nixos-homepage/
|
||||
- https://github.com/orgs/NixOS/teams/nix-team
|
||||
- Matrix room
|
||||
- Matrix rooms
|
||||
- [private] Nix maintainer team
|
||||
- Nix ∪ Lix devs (also private)
|
||||
- any open security issues if present and needed
|
||||
|
||||
- Team member should subscribe to notifications for the [Nix development category on Discourse](https://discourse.nixos.org/c/dev/nix/50)
|
||||
|
||||
58
maintainers/release-notes-todo
Executable file
58
maintainers/release-notes-todo
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
# debug:
|
||||
# set -x
|
||||
|
||||
START_REF="${1}"
|
||||
END_REF="${2:-upstream/master}"
|
||||
|
||||
# Get the merge base
|
||||
MERGE_BASE=$(git merge-base "$START_REF" "$END_REF")
|
||||
unset START_REF
|
||||
|
||||
# Get date range
|
||||
START_DATE=$(git show -s --format=%cI "$MERGE_BASE")
|
||||
END_DATE=$(git show -s --format=%cI "$END_REF")
|
||||
|
||||
echo "Checking PRs merged between $START_DATE and $END_DATE" >&2
|
||||
|
||||
# Get all commits between merge base and HEAD
|
||||
COMMITS=$(git rev-list "$MERGE_BASE..$END_REF")
|
||||
|
||||
# Convert to set for fast lookup
|
||||
declare -A commit_set
|
||||
for commit in $COMMITS; do
|
||||
commit_set["$commit"]=1
|
||||
done
|
||||
|
||||
# Get the current changelog
|
||||
LOG_DONE="$(changelog-d doc/manual/rl-next)"
|
||||
is_done(){
|
||||
local nr="$1"
|
||||
echo "$LOG_DONE" | grep -E "^- .*/pull/$nr)"
|
||||
}
|
||||
|
||||
# Query merged PRs in date range
|
||||
gh pr list \
|
||||
--repo NixOS/nix \
|
||||
--state merged \
|
||||
--limit 1000 \
|
||||
--json number,title,author,mergeCommit \
|
||||
--search "merged:$START_DATE..$END_DATE" | \
|
||||
jq -r '.[] | [.number, .mergeCommit.oid, .title, .author.login] | @tsv' | \
|
||||
while IFS=$'\t' read -r pr_num merge_commit _title author; do
|
||||
# Check if this PR's merge commit is in our branch
|
||||
if [[ -n "${commit_set[$merge_commit]:-}" ]]; then
|
||||
# Full detail, not suitable for comment due to mass ping and duplicate title
|
||||
# echo "- #$pr_num $_title (@$author)"
|
||||
echo "- #$pr_num ($author)"
|
||||
if is_done "$pr_num"
|
||||
then
|
||||
echo " - [x] has note"
|
||||
else
|
||||
echo " - [ ] has note"
|
||||
fi
|
||||
echo " - [ ] skip"
|
||||
fi
|
||||
done
|
||||
@@ -24,11 +24,18 @@ release:
|
||||
* In a checkout of the Nix repo, make sure you're on `master` and run
|
||||
`git pull`.
|
||||
|
||||
* Compile a release notes to-do list by running
|
||||
|
||||
```console
|
||||
$ ./maintainers/release-notes-todo PREV_RELEASE HEAD
|
||||
```
|
||||
|
||||
* Compile the release notes by running
|
||||
|
||||
```console
|
||||
$ export VERSION=X.YY
|
||||
$ git checkout -b release-notes
|
||||
$ export GITHUB_TOKEN=...
|
||||
$ ./maintainers/release-notes
|
||||
```
|
||||
|
||||
@@ -126,6 +133,8 @@ release:
|
||||
|
||||
Commit and push this to the maintenance branch.
|
||||
|
||||
* Create a backport label.
|
||||
|
||||
* Bump the version of `master`:
|
||||
|
||||
```console
|
||||
@@ -133,6 +142,7 @@ release:
|
||||
$ git pull
|
||||
$ NEW_VERSION=2.13.0
|
||||
$ echo $NEW_VERSION > .version
|
||||
$ ... edit .mergify.yml to add the previous version ...
|
||||
$ git checkout -b bump-$NEW_VERSION
|
||||
$ git commit -a -m 'Bump version'
|
||||
$ git push --set-upstream origin bump-$NEW_VERSION
|
||||
@@ -140,10 +150,6 @@ release:
|
||||
|
||||
Make a pull request and auto-merge it.
|
||||
|
||||
* Create a backport label.
|
||||
|
||||
* Add the new backport label to `.mergify.yml`.
|
||||
|
||||
* Post an [announcement on Discourse](https://discourse.nixos.org/c/announcements/8), including the contents of
|
||||
`rl-$VERSION.md`.
|
||||
|
||||
|
||||
10
misc/freebsd/meson.build
Normal file
10
misc/freebsd/meson.build
Normal file
@@ -0,0 +1,10 @@
|
||||
configure_file(
|
||||
input : 'nix-daemon.in',
|
||||
output : 'nix-daemon',
|
||||
install : true,
|
||||
install_dir : get_option('prefix') / 'etc/rc.d',
|
||||
install_mode : 'rwxr-xr-x',
|
||||
configuration : {
|
||||
'bindir' : bindir,
|
||||
},
|
||||
)
|
||||
49
misc/freebsd/nix-daemon.in
Normal file
49
misc/freebsd/nix-daemon.in
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# PROVIDE: nix_daemon
|
||||
# REQUIRE: DAEMON
|
||||
# KEYWORD: shutdown
|
||||
#
|
||||
# Add the following lines to /etc/rc.conf to enable nix-daemon:
|
||||
#
|
||||
# nix_daemon_enable="YES"
|
||||
#
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. /etc/rc.subr
|
||||
|
||||
name="nix_daemon"
|
||||
# shellcheck disable=SC2034
|
||||
rcvar="nix_daemon_enable"
|
||||
|
||||
load_rc_config $name
|
||||
|
||||
: "${nix_daemon_enable:=NO}"
|
||||
|
||||
command="@bindir@/nix-daemon"
|
||||
command_args=""
|
||||
pidfile="/var/run/nix-daemon.pid"
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
start_cmd="${name}_start"
|
||||
# shellcheck disable=SC2034
|
||||
stop_cmd="${name}_stop"
|
||||
|
||||
nix_daemon_start() {
|
||||
echo "Starting ${name}."
|
||||
# command_args is intentionally unquoted to allow multiple arguments
|
||||
# shellcheck disable=SC2086
|
||||
/usr/sbin/daemon -c -f -p "${pidfile}" "${command}" ${command_args}
|
||||
}
|
||||
|
||||
nix_daemon_stop() {
|
||||
if [ -f "${pidfile}" ]; then
|
||||
echo "Stopping ${name}."
|
||||
kill -TERM "$(cat "${pidfile}")"
|
||||
rm -f "${pidfile}"
|
||||
else
|
||||
echo "${name} is not running."
|
||||
fi
|
||||
}
|
||||
|
||||
run_rc_command "$1"
|
||||
@@ -9,3 +9,7 @@ endif
|
||||
if host_machine.system() == 'darwin'
|
||||
subdir('launchd')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'freebsd'
|
||||
subdir('freebsd')
|
||||
endif
|
||||
|
||||
@@ -14,7 +14,7 @@ extra_pkg_config_variables = get_variable('extra_pkg_config_variables', {})
|
||||
|
||||
extra_cflags = []
|
||||
if not meson.project_name().endswith('-c')
|
||||
extra_cflags += [ '-std=c++2a' ]
|
||||
extra_cflags += [ '-std=c++23' ]
|
||||
endif
|
||||
|
||||
import('pkgconfig').generate(
|
||||
@@ -34,7 +34,7 @@ meson.override_dependency(
|
||||
declare_dependency(
|
||||
include_directories : include_dirs,
|
||||
link_with : this_library,
|
||||
compile_args : [ '-std=c++2a' ],
|
||||
compile_args : [ '-std=c++23' ],
|
||||
dependencies : deps_public_subproject + deps_public,
|
||||
variables : extra_pkg_config_variables,
|
||||
),
|
||||
|
||||
@@ -37,6 +37,9 @@ runCommand "nix-binary-tarball-${version}" env ''
|
||||
substitute ${../scripts/install-systemd-multi-user.sh} $TMPDIR/install-systemd-multi-user.sh \
|
||||
--subst-var-by nix ${nix} \
|
||||
--subst-var-by cacert ${cacert}
|
||||
substitute ${../scripts/install-freebsd-multi-user.sh} $TMPDIR/install-freebsd-multi-user.sh \
|
||||
--subst-var-by nix ${nix} \
|
||||
--subst-var-by cacert ${cacert}
|
||||
substitute ${../scripts/install-multi-user.sh} $TMPDIR/install-multi-user \
|
||||
--subst-var-by nix ${nix} \
|
||||
--subst-var-by cacert ${cacert}
|
||||
@@ -48,6 +51,7 @@ runCommand "nix-binary-tarball-${version}" env ''
|
||||
shellcheck $TMPDIR/create-darwin-volume.sh
|
||||
shellcheck $TMPDIR/install-darwin-multi-user.sh
|
||||
shellcheck $TMPDIR/install-systemd-multi-user.sh
|
||||
shellcheck $TMPDIR/install-freebsd-multi-user.sh
|
||||
|
||||
# SC1091: Don't panic about not being able to source
|
||||
# /etc/profile
|
||||
@@ -64,6 +68,7 @@ runCommand "nix-binary-tarball-${version}" env ''
|
||||
chmod +x $TMPDIR/create-darwin-volume.sh
|
||||
chmod +x $TMPDIR/install-darwin-multi-user.sh
|
||||
chmod +x $TMPDIR/install-systemd-multi-user.sh
|
||||
chmod +x $TMPDIR/install-freebsd-multi-user.sh
|
||||
chmod +x $TMPDIR/install-multi-user
|
||||
dir=nix-${version}-${system}
|
||||
fn=$out/$dir.tar.xz
|
||||
@@ -82,6 +87,7 @@ runCommand "nix-binary-tarball-${version}" env ''
|
||||
$TMPDIR/create-darwin-volume.sh \
|
||||
$TMPDIR/install-darwin-multi-user.sh \
|
||||
$TMPDIR/install-systemd-multi-user.sh \
|
||||
$TMPDIR/install-freebsd-multi-user.sh \
|
||||
$TMPDIR/install-multi-user \
|
||||
$TMPDIR/reginfo \
|
||||
$(cat ${installerClosureInfo}/store-paths)
|
||||
|
||||
@@ -54,12 +54,12 @@ let
|
||||
preConfigure =
|
||||
prevAttrs.preConfigure or ""
|
||||
+
|
||||
# Update the repo-global .version file.
|
||||
# Symlink ./.version points there, but by default only workDir is writable.
|
||||
''
|
||||
chmod u+w ./.version
|
||||
echo ${finalAttrs.version} > ./.version
|
||||
'';
|
||||
# Update the repo-global .version file.
|
||||
# Symlink ./.version points there, but by default only workDir is writable.
|
||||
''
|
||||
chmod u+w ./.version
|
||||
echo ${finalAttrs.version} > ./.version
|
||||
'';
|
||||
};
|
||||
|
||||
localSourceLayer =
|
||||
@@ -148,7 +148,8 @@ let
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
] ++ prevAttrs.nativeBuildInputs or [ ];
|
||||
]
|
||||
++ prevAttrs.nativeBuildInputs or [ ];
|
||||
mesonCheckFlags = prevAttrs.mesonCheckFlags or [ ] ++ [
|
||||
"--print-errorlogs"
|
||||
];
|
||||
|
||||
@@ -64,6 +64,28 @@ scope: {
|
||||
NIX_CFLAGS_COMPILE = "-DINITIAL_MARK_STACK_SIZE=1048576";
|
||||
});
|
||||
|
||||
lowdown = pkgs.lowdown.overrideAttrs (prevAttrs: rec {
|
||||
version = "2.0.2";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://kristaps.bsd.lv/lowdown/snapshots/lowdown-${version}.tar.gz";
|
||||
hash = "sha512-cfzhuF4EnGmLJf5EGSIbWqJItY3npbRSALm+GarZ7SMU7Hr1xw0gtBFMpOdi5PBar4TgtvbnG4oRPh+COINGlA==";
|
||||
};
|
||||
nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [ pkgs.buildPackages.bmake ];
|
||||
postInstall =
|
||||
lib.replaceStrings [ "lowdown.so.1" "lowdown.1.dylib" ] [ "lowdown.so.2" "lowdown.2.dylib" ]
|
||||
prevAttrs.postInstall;
|
||||
});
|
||||
|
||||
toml11 = pkgs.toml11.overrideAttrs rec {
|
||||
version = "4.4.0";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "ToruNiina";
|
||||
repo = "toml11";
|
||||
tag = "v${version}";
|
||||
hash = "sha256-sgWKYxNT22nw376ttGsTdg0AMzOwp8QH3E8mx0BZJTQ=";
|
||||
};
|
||||
};
|
||||
|
||||
# TODO Hack until https://github.com/NixOS/nixpkgs/issues/45462 is fixed.
|
||||
boost =
|
||||
(pkgs.boost.override {
|
||||
|
||||
@@ -71,17 +71,16 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
# We use this shell with the local checkout, not unpackPhase.
|
||||
src = null;
|
||||
|
||||
env =
|
||||
{
|
||||
# For `make format`, to work without installing pre-commit
|
||||
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
|
||||
modular.pre-commit.settings.rawConfig
|
||||
}";
|
||||
}
|
||||
// lib.optionalAttrs stdenv.hostPlatform.isLinux {
|
||||
CC_LD = "mold";
|
||||
CXX_LD = "mold";
|
||||
};
|
||||
env = {
|
||||
# For `make format`, to work without installing pre-commit
|
||||
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
|
||||
modular.pre-commit.settings.rawConfig
|
||||
}";
|
||||
}
|
||||
// lib.optionalAttrs stdenv.hostPlatform.isLinux {
|
||||
CC_LD = "mold";
|
||||
CXX_LD = "mold";
|
||||
};
|
||||
|
||||
mesonFlags =
|
||||
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
|
||||
@@ -119,23 +118,25 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
modular.pre-commit.settings.package
|
||||
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
|
||||
pkgs.buildPackages.nixfmt-rfc-style
|
||||
pkgs.buildPackages.gdb
|
||||
]
|
||||
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
|
||||
lib.hiPrio pkgs.buildPackages.clang-tools
|
||||
)
|
||||
++ lib.optional stdenv.hostPlatform.isLinux pkgs.buildPackages.mold-wrapped;
|
||||
|
||||
buildInputs =
|
||||
[ pkgs.gbenchmark ]
|
||||
++ attrs.buildInputs or [ ]
|
||||
++ pkgs.nixComponents2.nix-util.buildInputs
|
||||
++ pkgs.nixComponents2.nix-store.buildInputs
|
||||
++ pkgs.nixComponents2.nix-store-tests.externalBuildInputs
|
||||
++ pkgs.nixComponents2.nix-fetchers.buildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.buildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.externalPropagatedBuildInputs
|
||||
++ pkgs.nixComponents2.nix-cmd.buildInputs
|
||||
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.externalBuildInputs
|
||||
++ lib.optional havePerl pkgs.perl;
|
||||
buildInputs = [
|
||||
pkgs.gbenchmark
|
||||
]
|
||||
++ attrs.buildInputs or [ ]
|
||||
++ pkgs.nixComponents2.nix-util.buildInputs
|
||||
++ pkgs.nixComponents2.nix-store.buildInputs
|
||||
++ pkgs.nixComponents2.nix-store-tests.externalBuildInputs
|
||||
++ pkgs.nixComponents2.nix-fetchers.buildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.buildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.externalPropagatedBuildInputs
|
||||
++ pkgs.nixComponents2.nix-cmd.buildInputs
|
||||
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.externalBuildInputs
|
||||
++ lib.optional havePerl pkgs.perl;
|
||||
}
|
||||
)
|
||||
|
||||
@@ -47,25 +47,25 @@
|
||||
}:
|
||||
|
||||
let
|
||||
libs =
|
||||
{
|
||||
inherit
|
||||
nix-util
|
||||
nix-util-c
|
||||
nix-store
|
||||
nix-store-c
|
||||
nix-fetchers
|
||||
nix-fetchers-c
|
||||
nix-expr
|
||||
nix-expr-c
|
||||
nix-flake
|
||||
nix-flake-c
|
||||
nix-main
|
||||
nix-main-c
|
||||
nix-cmd
|
||||
;
|
||||
}
|
||||
// lib.optionalAttrs
|
||||
libs = {
|
||||
inherit
|
||||
nix-util
|
||||
nix-util-c
|
||||
nix-store
|
||||
nix-store-c
|
||||
nix-fetchers
|
||||
nix-fetchers-c
|
||||
nix-expr
|
||||
nix-expr-c
|
||||
nix-flake
|
||||
nix-flake-c
|
||||
nix-main
|
||||
nix-main-c
|
||||
nix-cmd
|
||||
;
|
||||
}
|
||||
//
|
||||
lib.optionalAttrs
|
||||
(!stdenv.hostPlatform.isStatic && stdenv.buildPlatform.canExecute stdenv.hostPlatform)
|
||||
{
|
||||
# Currently fails in static build
|
||||
@@ -127,20 +127,19 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
*/
|
||||
dontFixup = true;
|
||||
|
||||
checkInputs =
|
||||
[
|
||||
# Make sure the unit tests have passed
|
||||
nix-util-tests.tests.run
|
||||
nix-store-tests.tests.run
|
||||
nix-expr-tests.tests.run
|
||||
nix-fetchers-tests.tests.run
|
||||
nix-flake-tests.tests.run
|
||||
checkInputs = [
|
||||
# Make sure the unit tests have passed
|
||||
nix-util-tests.tests.run
|
||||
nix-store-tests.tests.run
|
||||
nix-expr-tests.tests.run
|
||||
nix-fetchers-tests.tests.run
|
||||
nix-flake-tests.tests.run
|
||||
|
||||
# Make sure the functional tests have passed
|
||||
nix-functional-tests
|
||||
]
|
||||
++ lib.optionals
|
||||
(!stdenv.hostPlatform.isStatic && stdenv.buildPlatform.canExecute stdenv.hostPlatform)
|
||||
# Make sure the functional tests have passed
|
||||
nix-functional-tests
|
||||
]
|
||||
++
|
||||
lib.optionals (!stdenv.hostPlatform.isStatic && stdenv.buildPlatform.canExecute stdenv.hostPlatform)
|
||||
[
|
||||
# Perl currently fails in static build
|
||||
# TODO: Split out tests into a separate derivation?
|
||||
|
||||
@@ -223,10 +223,17 @@ in
|
||||
dockerImage = lib.genAttrs linux64BitSystems (system: self.packages.${system}.dockerImage);
|
||||
|
||||
# # Line coverage analysis.
|
||||
# coverage = nixpkgsFor.x86_64-linux.native.nix.override {
|
||||
# pname = "nix-coverage";
|
||||
# withCoverageChecks = true;
|
||||
# };
|
||||
coverage =
|
||||
(import ./../ci/gha/tests rec {
|
||||
withCoverage = true;
|
||||
pkgs = nixpkgsFor.x86_64-linux.nativeForStdenv.clangStdenv;
|
||||
nixComponents = pkgs.nixComponents2;
|
||||
nixFlake = null;
|
||||
getStdenv = p: p.clangStdenv;
|
||||
}).codeCoverage.coverageReports.overrideAttrs
|
||||
{
|
||||
name = "nix-coverage"; # For historical consistency
|
||||
};
|
||||
|
||||
# Nix's manual
|
||||
manual = nixpkgsFor.x86_64-linux.native.nixComponents2.nix-manual;
|
||||
|
||||
173
scripts/install-freebsd-multi-user.sh
Normal file
173
scripts/install-freebsd-multi-user.sh
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
# System specific settings
|
||||
# FreeBSD typically uses UIDs from 1001+ for regular users,
|
||||
# so we'll use a range that's unlikely to conflict
|
||||
export NIX_FIRST_BUILD_UID="${NIX_FIRST_BUILD_UID:-30001}"
|
||||
export NIX_BUILD_GROUP_ID="${NIX_BUILD_GROUP_ID:-30000}"
|
||||
export NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d"
|
||||
|
||||
# FreeBSD service paths
|
||||
readonly SERVICE_SRC=/etc/rc.d/nix-daemon
|
||||
readonly SERVICE_DEST=/usr/local/etc/rc.d/nix-daemon
|
||||
|
||||
poly_cure_artifacts() {
|
||||
:
|
||||
}
|
||||
|
||||
poly_service_installed_check() {
|
||||
if [ -f "$SERVICE_DEST" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
poly_service_uninstall_directions() {
|
||||
cat <<EOF
|
||||
$1. Delete the rc.d service
|
||||
|
||||
sudo service nix-daemon stop
|
||||
sudo rm -f $SERVICE_DEST
|
||||
sudo sysrc -x nix_daemon_enable
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
poly_service_setup_note() {
|
||||
cat <<EOF
|
||||
- link the nix-daemon rc.d service to $SERVICE_DEST
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
poly_extra_try_me_commands() {
|
||||
cat <<EOF
|
||||
$ sudo service nix-daemon start
|
||||
EOF
|
||||
}
|
||||
|
||||
poly_configure_nix_daemon_service() {
|
||||
task "Setting up the nix-daemon rc.d service"
|
||||
|
||||
# Ensure the rc.d directory exists
|
||||
_sudo "to create the rc.d directory" \
|
||||
mkdir -p /usr/local/etc/rc.d
|
||||
|
||||
# Link the pre-installed rc.d script
|
||||
_sudo "to set up the nix-daemon service" \
|
||||
ln -sfn "/nix/var/nix/profiles/default$SERVICE_SRC" "$SERVICE_DEST"
|
||||
|
||||
_sudo "to enable the nix-daemon service" \
|
||||
sysrc nix_daemon_enable=YES
|
||||
|
||||
_sudo "to start the nix-daemon" \
|
||||
service nix-daemon start
|
||||
}
|
||||
|
||||
poly_group_exists() {
|
||||
pw group show "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
poly_group_id_get() {
|
||||
pw group show "$1" | cut -d: -f3
|
||||
}
|
||||
|
||||
poly_create_build_group() {
|
||||
_sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \
|
||||
pw groupadd -n "$NIX_BUILD_GROUP_NAME" -g "$NIX_BUILD_GROUP_ID" >&2
|
||||
}
|
||||
|
||||
poly_user_exists() {
|
||||
pw user show "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
poly_user_id_get() {
|
||||
pw user show "$1" | cut -d: -f3
|
||||
}
|
||||
|
||||
poly_user_hidden_get() {
|
||||
# FreeBSD doesn't have a concept of hidden users like macOS
|
||||
echo "0"
|
||||
}
|
||||
|
||||
poly_user_hidden_set() {
|
||||
# No-op on FreeBSD
|
||||
true
|
||||
}
|
||||
|
||||
poly_user_home_get() {
|
||||
pw user show "$1" | cut -d: -f9
|
||||
}
|
||||
|
||||
poly_user_home_set() {
|
||||
_sudo "in order to give $1 a safe home directory" \
|
||||
pw usermod -n "$1" -d "$2"
|
||||
}
|
||||
|
||||
poly_user_note_get() {
|
||||
pw user show "$1" | cut -d: -f8
|
||||
}
|
||||
|
||||
poly_user_note_set() {
|
||||
_sudo "in order to give $1 a useful comment" \
|
||||
pw usermod -n "$1" -c "$2"
|
||||
}
|
||||
|
||||
poly_user_shell_get() {
|
||||
pw user show "$1" | cut -d: -f10
|
||||
}
|
||||
|
||||
poly_user_shell_set() {
|
||||
_sudo "in order to prevent $1 from logging in" \
|
||||
pw usermod -n "$1" -s "$2"
|
||||
}
|
||||
|
||||
poly_user_in_group_check() {
|
||||
groups "$1" 2>/dev/null | grep -q "\<$2\>"
|
||||
}
|
||||
|
||||
poly_user_in_group_set() {
|
||||
_sudo "Add $1 to the $2 group" \
|
||||
pw groupmod -n "$2" -m "$1"
|
||||
}
|
||||
|
||||
poly_user_primary_group_get() {
|
||||
pw user show "$1" | cut -d: -f4
|
||||
}
|
||||
|
||||
poly_user_primary_group_set() {
|
||||
_sudo "to let the nix daemon use this user for builds" \
|
||||
pw usermod -n "$1" -g "$2"
|
||||
}
|
||||
|
||||
poly_create_build_user() {
|
||||
username=$1
|
||||
uid=$2
|
||||
builder_num=$3
|
||||
|
||||
_sudo "Creating the Nix build user, $username" \
|
||||
pw useradd \
|
||||
-n "$username" \
|
||||
-u "$uid" \
|
||||
-g "$NIX_BUILD_GROUP_NAME" \
|
||||
-G "$NIX_BUILD_GROUP_NAME" \
|
||||
-d /var/empty \
|
||||
-s /sbin/nologin \
|
||||
-c "Nix build user $builder_num"
|
||||
}
|
||||
|
||||
poly_prepare_to_install() {
|
||||
# FreeBSD-specific preparation steps
|
||||
:
|
||||
}
|
||||
|
||||
poly_configure_default_profile_targets() {
|
||||
# FreeBSD-specific profile locations
|
||||
# FreeBSD uses /usr/local/etc for third-party shell configurations
|
||||
# Include both profile (for login shells) and bashrc (for interactive shells)
|
||||
echo "/usr/local/etc/profile /usr/local/etc/bashrc /usr/local/etc/profile.d/nix.sh /usr/local/etc/zshrc"
|
||||
}
|
||||
@@ -33,7 +33,8 @@ readonly NIX_BUILD_GROUP_NAME="nixbld"
|
||||
readonly NIX_ROOT="/nix"
|
||||
readonly NIX_EXTRA_CONF=${NIX_EXTRA_CONF:-}
|
||||
|
||||
readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc")
|
||||
# PROFILE_TARGETS will be set later after OS-specific scripts are loaded
|
||||
PROFILE_TARGETS=()
|
||||
readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"
|
||||
readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
|
||||
|
||||
@@ -99,6 +100,14 @@ is_os_darwin() {
|
||||
fi
|
||||
}
|
||||
|
||||
is_os_freebsd() {
|
||||
if [ "$(uname -s)" = "FreeBSD" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
contact_us() {
|
||||
echo "You can open an issue at"
|
||||
echo "https://github.com/NixOS/nix/issues/new?labels=installer&template=installer.md"
|
||||
@@ -498,6 +507,10 @@ You have aborted the installation.
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
if is_os_freebsd; then
|
||||
ok "Detected FreeBSD, will set up rc.d service for nix-daemon"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_report() {
|
||||
@@ -834,7 +847,7 @@ install_from_extracted_nix() {
|
||||
(
|
||||
cd "$EXTRACTED_NIX_PATH"
|
||||
|
||||
if is_os_darwin; then
|
||||
if is_os_darwin || is_os_freebsd; then
|
||||
_sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \
|
||||
cp -RPp ./store/* "$NIX_ROOT/store/"
|
||||
else
|
||||
@@ -989,11 +1002,22 @@ main() {
|
||||
# shellcheck source=./install-systemd-multi-user.sh
|
||||
. "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh" # most of this works on non-systemd distros also
|
||||
check_required_system_specific_settings "install-systemd-multi-user.sh"
|
||||
elif is_os_freebsd; then
|
||||
# shellcheck source=./install-freebsd-multi-user.sh
|
||||
. "$EXTRACTED_NIX_PATH/install-freebsd-multi-user.sh"
|
||||
check_required_system_specific_settings "install-freebsd-multi-user.sh"
|
||||
else
|
||||
failure "Sorry, I don't know what to do on $(uname)"
|
||||
fi
|
||||
|
||||
|
||||
# Set profile targets after OS-specific scripts are loaded
|
||||
if command -v poly_configure_default_profile_targets > /dev/null 2>&1; then
|
||||
PROFILE_TARGETS=($(poly_configure_default_profile_targets))
|
||||
else
|
||||
PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc")
|
||||
fi
|
||||
|
||||
welcome_to_nix
|
||||
|
||||
if ! is_root; then
|
||||
|
||||
@@ -26,8 +26,10 @@ if [ -z "$HOME" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OS="$(uname -s)"
|
||||
|
||||
# macOS support for 10.12.6 or higher
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if [ "$OS" = "Darwin" ]; then
|
||||
IFS='.' read -r macos_major macos_minor macos_patch << EOF
|
||||
$(sw_vers -productVersion)
|
||||
EOF
|
||||
@@ -39,11 +41,11 @@ EOF
|
||||
fi
|
||||
|
||||
# Determine if we could use the multi-user installer or not
|
||||
if [ "$(uname -s)" = "Linux" ]; then
|
||||
if [ "$OS" = "Linux" ] || [ "$OS" = "FreeBSD" ]; then
|
||||
echo "Note: a multi-user installation is possible. See https://nix.dev/manual/nix/stable/installation/installing-binary.html#multi-user-installation" >&2
|
||||
fi
|
||||
|
||||
case "$(uname -s)" in
|
||||
case "$OS" in
|
||||
"Darwin")
|
||||
INSTALL_MODE=daemon;;
|
||||
*)
|
||||
@@ -60,7 +62,7 @@ while [ $# -gt 0 ]; do
|
||||
ACTION=install
|
||||
;;
|
||||
--no-daemon)
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if [ "$OS" = "Darwin" ]; then
|
||||
printf '\e[1;31mError: --no-daemon installs are no-longer supported on Darwin/macOS!\e[0m\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -123,6 +125,13 @@ while [ $# -gt 0 ]; do
|
||||
done
|
||||
|
||||
if [ "$INSTALL_MODE" = "daemon" ]; then
|
||||
# Check for bash on systems that don't have it by default
|
||||
if [ "$OS" = "FreeBSD" ] && ! command -v bash >/dev/null 2>&1; then
|
||||
printf '\e[1;31mError: bash is required for multi-user installation but was not found.\e[0m\n' >&2
|
||||
printf 'Please install bash first:\n' >&2
|
||||
printf ' pkg install bash\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
printf '\e[1;31mSwitching to the Multi-user Installer\e[0m\n'
|
||||
exec "$self/install-multi-user" $ACTION
|
||||
exit 0
|
||||
@@ -167,7 +176,7 @@ for i in $(cd "$self/store" >/dev/null && echo ./*); do
|
||||
rm -rf "$i_tmp"
|
||||
fi
|
||||
if ! [ -e "$dest/store/$i" ]; then
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if [ "$OS" = "Darwin" ] || [ "$OS" = "FreeBSD" ]; then
|
||||
cp -RPp "$self/store/$i" "$i_tmp"
|
||||
else
|
||||
cp -RP --preserve=ownership,timestamps "$self/store/$i" "$i_tmp"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "nix/fetchers/fetch-to-store.hh"
|
||||
#include "nix/cmd/compatibility-settings.hh"
|
||||
#include "nix/expr/eval-settings.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
|
||||
std::optional<NixInt::Inner> priority;
|
||||
|
||||
if (attr->maybeGetAttr(state->sOutputSpecified)) {
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
||||
if (attr->maybeGetAttr(state->s.outputSpecified)) {
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state->s.meta)) {
|
||||
if (auto aPriority = aMeta->maybeGetAttr("priority"))
|
||||
priority = aPriority->getInt().value;
|
||||
}
|
||||
@@ -119,12 +119,12 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
overloaded{
|
||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||
StringSet outputsToInstall;
|
||||
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
|
||||
if (auto aOutputSpecified = attr->maybeGetAttr(state->s.outputSpecified)) {
|
||||
if (aOutputSpecified->getBool()) {
|
||||
if (auto aOutputName = attr->maybeGetAttr("outputName"))
|
||||
outputsToInstall = {aOutputName->getString()};
|
||||
}
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state->s.meta)) {
|
||||
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
|
||||
for (auto & s : aOutputsToInstall->getListOfStrings())
|
||||
outputsToInstall.insert(s);
|
||||
|
||||
@@ -178,10 +178,16 @@ MixFlakeOptions::MixFlakeOptions()
|
||||
for (auto & [inputName, input] : flake.lockFile.root->inputs) {
|
||||
auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes
|
||||
if (auto input3 = std::dynamic_pointer_cast<const flake::LockedNode>(input2)) {
|
||||
fetchers::Attrs extraAttrs;
|
||||
|
||||
if (!input3->lockedRef.subdir.empty()) {
|
||||
extraAttrs["dir"] = input3->lockedRef.subdir;
|
||||
}
|
||||
|
||||
overrideRegistry(
|
||||
fetchers::Input::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", inputName}}),
|
||||
input3->lockedRef.input,
|
||||
{});
|
||||
extraAttrs);
|
||||
}
|
||||
}
|
||||
}},
|
||||
|
||||
@@ -37,9 +37,17 @@ static std::string doRenderMarkdownToTerminal(std::string_view markdown)
|
||||
.vmargin = 0,
|
||||
# endif
|
||||
.feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES,
|
||||
.oflags = LOWDOWN_TERM_NOLINK,
|
||||
.oflags =
|
||||
# if HAVE_LOWDOWN_1_4
|
||||
LOWDOWN_TERM_NORELLINK // To render full links while skipping relative ones
|
||||
# else
|
||||
LOWDOWN_TERM_NOLINK
|
||||
# endif
|
||||
};
|
||||
|
||||
if (!isTTY())
|
||||
opts.oflags |= LOWDOWN_TERM_NOANSI;
|
||||
|
||||
auto doc = lowdown_doc_new(&opts);
|
||||
if (!doc)
|
||||
throw Error("cannot allocate Markdown document");
|
||||
@@ -65,7 +73,7 @@ static std::string doRenderMarkdownToTerminal(std::string_view markdown)
|
||||
if (!rndr_res)
|
||||
throw Error("allocation error while rendering Markdown");
|
||||
|
||||
return filterANSIEscapes(std::string(buf->data, buf->size), !isTTY());
|
||||
return std::string(buf->data, buf->size);
|
||||
}
|
||||
|
||||
std::string renderMarkdownToTerminal(std::string_view markdown)
|
||||
|
||||
@@ -3,7 +3,7 @@ project(
|
||||
'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
|
||||
@@ -53,7 +53,8 @@ mkMesonLibrary (finalAttrs: {
|
||||
|
||||
buildInputs = [
|
||||
({ inherit editline readline; }.${readlineFlavor})
|
||||
] ++ lib.optional enableMarkdown lowdown;
|
||||
]
|
||||
++ lib.optional enableMarkdown lowdown;
|
||||
|
||||
propagatedBuildInputs = [
|
||||
nix-util
|
||||
|
||||
@@ -574,14 +574,15 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
for (auto & sub : subs) {
|
||||
auto * logSubP = dynamic_cast<LogStore *>(&*sub);
|
||||
if (!logSubP) {
|
||||
printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri());
|
||||
printInfo(
|
||||
"Skipped '%s' which does not support retrieving build logs", sub->config.getHumanReadableURI());
|
||||
continue;
|
||||
}
|
||||
auto & logSub = *logSubP;
|
||||
|
||||
auto log = logSub.getBuildLog(drvPath);
|
||||
if (log) {
|
||||
printInfo("got build log for '%s' from '%s'", drvPathRaw, logSub.getUri());
|
||||
printInfo("got build log for '%s' from '%s'", drvPathRaw, logSub.config.getHumanReadableURI());
|
||||
logger->writeToStdout(*log);
|
||||
foundLog = true;
|
||||
break;
|
||||
@@ -915,6 +916,7 @@ ReplExitStatus AbstractNixRepl::runSimple(ref<EvalState> evalState, const ValMap
|
||||
return values;
|
||||
};
|
||||
LookupPath lookupPath = {};
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDelete)
|
||||
auto repl = std::make_unique<NixRepl>(
|
||||
lookupPath,
|
||||
openStore(),
|
||||
|
||||
@@ -3,7 +3,7 @@ project(
|
||||
'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
|
||||
@@ -40,6 +40,8 @@ static T * unsafe_new_with_self(F && init)
|
||||
return new (p) T(init(static_cast<T *>(p)));
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
nix_err nix_libexpr_init(nix_c_context * context)
|
||||
{
|
||||
if (context)
|
||||
@@ -287,3 +289,5 @@ void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * o
|
||||
GC_REGISTER_FINALIZER(obj, finalizer, cd, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "nix_api_value.h"
|
||||
#include "nix/expr/search-path.hh"
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct nix_eval_state_builder
|
||||
{
|
||||
nix::ref<nix::Store> store;
|
||||
@@ -61,4 +63,6 @@ struct nix_realised_string
|
||||
std::vector<StorePath> storePaths;
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // NIX_API_EXPR_INTERNAL_H
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
extern "C" {
|
||||
|
||||
void nix_set_string_return(nix_string_return * str, const char * c)
|
||||
{
|
||||
str->str = c;
|
||||
@@ -40,6 +42,8 @@ nix_err nix_external_add_string_context(nix_c_context * context, nix_string_cont
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
class NixCExternalValue : public nix::ExternalValueBase
|
||||
{
|
||||
NixCExternalValueDesc & desc;
|
||||
@@ -170,6 +174,8 @@ public:
|
||||
virtual ~NixCExternalValue() override {};
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
ExternalValue * nix_create_external_value(nix_c_context * context, NixCExternalValueDesc * desc, void * v)
|
||||
{
|
||||
if (context)
|
||||
@@ -198,3 +204,5 @@ void * nix_get_external_value_content(nix_c_context * context, ExternalValue * b
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "nix/expr/attr-set.hh"
|
||||
#include "nix/expr/eval-error.hh"
|
||||
#include "nix/util/configuration.hh"
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
@@ -89,8 +90,13 @@ static void nix_c_primop_wrapper(
|
||||
f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp);
|
||||
|
||||
if (ctx.last_err_code != NIX_OK) {
|
||||
/* TODO: Throw different errors depending on the error code */
|
||||
state.error<nix::EvalError>("Error from custom function: %s", *ctx.last_err).atPos(pos).debugThrow();
|
||||
if (ctx.last_err_code == NIX_ERR_RECOVERABLE) {
|
||||
state.error<nix::RecoverableEvalError>("Recoverable error from custom function: %s", *ctx.last_err)
|
||||
.atPos(pos)
|
||||
.debugThrow();
|
||||
} else {
|
||||
state.error<nix::EvalError>("Error from custom function: %s", *ctx.last_err).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
|
||||
if (!vTmp.isValid()) {
|
||||
@@ -111,6 +117,8 @@ static void nix_c_primop_wrapper(
|
||||
v = vTmp;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
PrimOp * nix_alloc_primop(
|
||||
nix_c_context * context,
|
||||
PrimOpFun fun,
|
||||
@@ -175,6 +183,8 @@ ValueType nix_get_type(nix_c_context * context, const nix_value * value)
|
||||
switch (v.type()) {
|
||||
case nThunk:
|
||||
return NIX_TYPE_THUNK;
|
||||
case nFailed:
|
||||
return NIX_TYPE_FAILED;
|
||||
case nInt:
|
||||
return NIX_TYPE_INT;
|
||||
case nFloat:
|
||||
@@ -592,7 +602,7 @@ nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * b
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_not_null(value);
|
||||
nix::Symbol s = bb->builder.state.symbols.create(name);
|
||||
nix::Symbol s = bb->builder.state.get().symbols.create(name);
|
||||
bb->builder.insert(s, &v);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
@@ -651,3 +661,5 @@ const StorePath * nix_realised_string_get_store_path(nix_realised_string * s, si
|
||||
{
|
||||
return &s->storePaths[i];
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -32,7 +32,8 @@ typedef enum {
|
||||
NIX_TYPE_ATTRS,
|
||||
NIX_TYPE_LIST,
|
||||
NIX_TYPE_FUNCTION,
|
||||
NIX_TYPE_EXTERNAL
|
||||
NIX_TYPE_EXTERNAL,
|
||||
NIX_TYPE_FAILED,
|
||||
} ValueType;
|
||||
|
||||
// forward declarations
|
||||
|
||||
@@ -3,7 +3,7 @@ project(
|
||||
'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <exception> // Needed by rapidcheck on Darwin
|
||||
#include <rapidcheck.h>
|
||||
|
||||
#include "nix/store/tests/path.hh"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <exception> // Needed by rapidcheck on Darwin
|
||||
#include <rapidcheck/gtest.h>
|
||||
|
||||
#include "nix/store/tests/derived-path.hh"
|
||||
|
||||
@@ -54,7 +54,7 @@ TEST_F(JSONValueTest, IntNegative)
|
||||
TEST_F(JSONValueTest, String)
|
||||
{
|
||||
Value v;
|
||||
v.mkString("test");
|
||||
v.mkStringNoCopy("test");
|
||||
ASSERT_EQ(getJSONValue(v), "\"test\"");
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ TEST_F(JSONValueTest, StringQuotes)
|
||||
{
|
||||
Value v;
|
||||
|
||||
v.mkString("test\"");
|
||||
v.mkStringNoCopy("test\"");
|
||||
ASSERT_EQ(getJSONValue(v), "\"test\\\"\"");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ project(
|
||||
'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
@@ -55,6 +55,7 @@ sources = files(
|
||||
'nix_api_expr.cc',
|
||||
'nix_api_external.cc',
|
||||
'nix_api_value.cc',
|
||||
'nix_api_value_internal.cc',
|
||||
'primops.cc',
|
||||
'search-path.cc',
|
||||
'trivial.cc',
|
||||
@@ -75,6 +76,7 @@ this_exe = executable(
|
||||
# TODO: -lrapidcheck, see ../libutil-support/build.meson
|
||||
link_args : linker_export_flags + [ '-lrapidcheck' ],
|
||||
install : true,
|
||||
cpp_pch : do_pch ? [ 'pch/precompiled-headers.hh' ] : [],
|
||||
)
|
||||
|
||||
test(
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
|
||||
@@ -151,8 +149,8 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_value)
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
ASSERT_EQ(nullptr, r);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("cannot coerce")));
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("cannot coerce"));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
|
||||
@@ -168,8 +166,8 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
ASSERT_EQ(nullptr, r);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("failed with exit code 1")));
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("failed with exit code 1"));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context)
|
||||
@@ -381,12 +379,11 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_no_return)
|
||||
nix_value * result = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_value_call(ctx, state, primopValue, three, result);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(
|
||||
ctx->last_err,
|
||||
testing::Optional(
|
||||
testing::HasSubstr("Implementation error in custom function: return value was not initialized")));
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badNoReturn")));
|
||||
nix_err_msg(nullptr, ctx, nullptr),
|
||||
testing::HasSubstr("Implementation error in custom function: return value was not initialized"));
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badNoReturn"));
|
||||
}
|
||||
|
||||
static void primop_bad_return_thunk(
|
||||
@@ -419,12 +416,11 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_return_thunk)
|
||||
assert_ctx_ok();
|
||||
NIX_VALUE_CALL(ctx, state, result, primopValue, toString, four);
|
||||
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(
|
||||
ctx->last_err,
|
||||
testing::Optional(
|
||||
testing::HasSubstr("Implementation error in custom function: return value must not be a thunk")));
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badReturnThunk")));
|
||||
nix_err_msg(nullptr, ctx, nullptr),
|
||||
testing::HasSubstr("Implementation error in custom function: return value must not be a thunk"));
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badReturnThunk"));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)
|
||||
@@ -441,4 +437,105 @@ TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(3, rInt);
|
||||
}
|
||||
|
||||
// The following is a test case for retryable thunks.
|
||||
// This is a requirement for the current way in which NixOps4 evaluates its deployment expressions.
|
||||
// An alternative strategy could be implemented, but unwinding the stack may be a more efficient way to deal with many
|
||||
// suspensions/resumptions, compared to e.g. using a thread or coroutine stack for each suspended dependency. This test
|
||||
// models the essential bits of a deployment tool that uses such a strategy.
|
||||
|
||||
// State for the retryable primop - simulates deployment resource availability
|
||||
struct DeploymentResourceState
|
||||
{
|
||||
bool vm_created = false;
|
||||
};
|
||||
|
||||
static void primop_load_resource_input(
|
||||
void * user_data, nix_c_context * context, EvalState * state, nix_value ** args, nix_value * ret)
|
||||
{
|
||||
assert(context);
|
||||
assert(state);
|
||||
auto * resource_state = static_cast<DeploymentResourceState *>(user_data);
|
||||
|
||||
// Get the resource input name argument
|
||||
std::string input_name;
|
||||
if (nix_get_string(context, args[0], OBSERVE_STRING(input_name)) != NIX_OK)
|
||||
return;
|
||||
|
||||
// Only handle "vm_id" input - throw for anything else
|
||||
if (input_name != "vm_id") {
|
||||
std::string error_msg = "unknown resource input: " + input_name;
|
||||
nix_set_err_msg(context, NIX_ERR_NIX_ERROR, error_msg.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (resource_state->vm_created) {
|
||||
// VM has been created, return the ID
|
||||
nix_init_string(context, ret, "vm-12345");
|
||||
} else {
|
||||
// VM not created yet, fail with dependency error
|
||||
nix_set_err_msg(context, NIX_ERR_RECOVERABLE, "VM not yet created");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_thunk_re_evaluation_after_deployment)
|
||||
{
|
||||
// This test demonstrates NixOps4's requirement: a thunk calling a primop should be
|
||||
// re-evaluable when deployment resources become available that were not available initially.
|
||||
|
||||
DeploymentResourceState resource_state;
|
||||
|
||||
PrimOp * primop = nix_alloc_primop(
|
||||
ctx,
|
||||
primop_load_resource_input,
|
||||
1,
|
||||
"loadResourceInput",
|
||||
nullptr,
|
||||
"load a deployment resource input",
|
||||
&resource_state);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_value * primopValue = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_primop(ctx, primopValue, primop);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_value * inputName = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_string(ctx, inputName, "vm_id");
|
||||
assert_ctx_ok();
|
||||
|
||||
// Create a single thunk by using nix_init_apply instead of nix_value_call
|
||||
// This creates a lazy application that can be forced multiple times
|
||||
nix_value * thunk = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_apply(ctx, thunk, primopValue, inputName);
|
||||
assert_ctx_ok();
|
||||
|
||||
// First force: VM not created yet, should fail
|
||||
nix_value_force(ctx, state, thunk);
|
||||
ASSERT_EQ(NIX_ERR_NIX_ERROR, nix_err_code(ctx));
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("VM not yet created"));
|
||||
|
||||
// Clear the error context for the next attempt
|
||||
nix_c_context_free(ctx);
|
||||
ctx = nix_c_context_create();
|
||||
|
||||
// Simulate deployment process: VM gets created
|
||||
resource_state.vm_created = true;
|
||||
|
||||
// Second force of the SAME thunk: this is where the "failed" value issue appears
|
||||
// With failed value caching, this should fail because the thunk is marked as permanently failed
|
||||
// Without failed value caching (or with retryable failures), this should succeed
|
||||
nix_value_force(ctx, state, thunk);
|
||||
|
||||
// If we get here without error, the thunk was successfully re-evaluated
|
||||
assert_ctx_ok();
|
||||
|
||||
std::string result;
|
||||
nix_get_string(ctx, thunk, OBSERVE_STRING(result));
|
||||
assert_ctx_ok();
|
||||
ASSERT_STREQ("vm-12345", result.c_str());
|
||||
}
|
||||
|
||||
} // namespace nixC
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_expr_internal.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "nix_api_external.h"
|
||||
|
||||
@@ -39,7 +36,7 @@ private:
|
||||
std::string type_string = "nix-external<MyExternalValueDesc( ";
|
||||
type_string += std::to_string(obj->_x);
|
||||
type_string += " )>";
|
||||
res->str = &*type_string.begin();
|
||||
nix_set_string_return(res, &*type_string.begin());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "nix_api_expr_internal.h"
|
||||
|
||||
#include "nix/expr/tests/nix_api_expr.hh"
|
||||
#include "nix/util/tests/string_callback.hh"
|
||||
@@ -16,14 +13,6 @@
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_expr_test, as_nix_value_ptr)
|
||||
{
|
||||
// nix_alloc_value casts nix::Value to nix_value
|
||||
// It should be obvious from the decl that that works, but if it doesn't,
|
||||
// the whole implementation would be utterly broken.
|
||||
ASSERT_EQ(sizeof(nix::Value), sizeof(nix_value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_get_int_invalid)
|
||||
{
|
||||
ASSERT_EQ(0, nix_get_int(ctx, nullptr));
|
||||
@@ -320,8 +309,10 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_error)
|
||||
|
||||
// Evaluate it
|
||||
nix_value_force(ctx, state, v);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err.value(), testing::HasSubstr("attempt to call something which is not a function but"));
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(
|
||||
nix_err_msg(nullptr, ctx, nullptr),
|
||||
testing::HasSubstr("attempt to call something which is not a function but"));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, some_string);
|
||||
@@ -380,7 +371,9 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_lazy_arg)
|
||||
// nix_get_attr_byname isn't lazy (it could have been) so it will throw the exception
|
||||
nix_value * foo = nix_get_attr_byname(ctx, r, state, "foo");
|
||||
ASSERT_EQ(nullptr, foo);
|
||||
ASSERT_THAT(ctx->last_err.value(), testing::HasSubstr("error message for test case nix_value_init_apply_lazy_arg"));
|
||||
ASSERT_THAT(
|
||||
nix_err_msg(nullptr, ctx, nullptr),
|
||||
testing::HasSubstr("error message for test case nix_value_init_apply_lazy_arg"));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, f);
|
||||
|
||||
25
src/libexpr-tests/nix_api_value_internal.cc
Normal file
25
src/libexpr-tests/nix_api_value_internal.cc
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "nix_api_expr_internal.h"
|
||||
|
||||
#include "nix/expr/tests/nix_api_expr.hh"
|
||||
#include "nix/util/tests/string_callback.hh"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_expr_test, as_nix_value_ptr)
|
||||
{
|
||||
// nix_alloc_value casts nix::Value to nix_value
|
||||
// It should be obvious from the decl that that works, but if it doesn't,
|
||||
// the whole implementation would be utterly broken.
|
||||
ASSERT_EQ(sizeof(nix::Value), sizeof(nix_value));
|
||||
}
|
||||
|
||||
} // namespace nixC
|
||||
4
src/libexpr-tests/pch/precompiled-headers.hh
Normal file
4
src/libexpr-tests/pch/precompiled-headers.hh
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "nix/expr/tests/libexpr.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
@@ -35,14 +35,14 @@ TEST_F(ValuePrintingTests, tBool)
|
||||
TEST_F(ValuePrintingTests, tString)
|
||||
{
|
||||
Value vString;
|
||||
vString.mkString("some-string");
|
||||
vString.mkStringNoCopy("some-string");
|
||||
test(vString, "\"some-string\"");
|
||||
}
|
||||
|
||||
TEST_F(ValuePrintingTests, tPath)
|
||||
{
|
||||
Value vPath;
|
||||
vPath.mkString("/foo");
|
||||
vPath.mkStringNoCopy("/foo");
|
||||
test(vPath, "\"/foo\"");
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ TEST_F(ValuePrintingTests, tAttrs)
|
||||
Value vTwo;
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("one"), &vOne);
|
||||
builder.insert(state.symbols.create("two"), &vTwo);
|
||||
|
||||
@@ -196,11 +196,11 @@ TEST_F(ValuePrintingTests, depthAttrs)
|
||||
Value vTwo;
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builderEmpty(state, state.allocBindings(0));
|
||||
BindingsBuilder builderEmpty = state.buildBindings(0);
|
||||
Value vAttrsEmpty;
|
||||
vAttrsEmpty.mkAttrs(builderEmpty.finish());
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("one"), &vOne);
|
||||
builder.insert(state.symbols.create("two"), &vTwo);
|
||||
builder.insert(state.symbols.create("nested"), &vAttrsEmpty);
|
||||
@@ -208,7 +208,7 @@ TEST_F(ValuePrintingTests, depthAttrs)
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
|
||||
BindingsBuilder builder2(state, state.allocBindings(10));
|
||||
BindingsBuilder builder2 = state.buildBindings(10);
|
||||
builder2.insert(state.symbols.create("one"), &vOne);
|
||||
builder2.insert(state.symbols.create("two"), &vTwo);
|
||||
builder2.insert(state.symbols.create("nested"), &vAttrs);
|
||||
@@ -233,14 +233,14 @@ TEST_F(ValuePrintingTests, depthList)
|
||||
Value vTwo;
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("one"), &vOne);
|
||||
builder.insert(state.symbols.create("two"), &vTwo);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
|
||||
BindingsBuilder builder2(state, state.allocBindings(10));
|
||||
BindingsBuilder builder2 = state.buildBindings(10);
|
||||
builder2.insert(state.symbols.create("one"), &vOne);
|
||||
builder2.insert(state.symbols.create("two"), &vTwo);
|
||||
builder2.insert(state.symbols.create("nested"), &vAttrs);
|
||||
@@ -290,12 +290,12 @@ TEST_F(StringPrintingTests, maxLengthTruncation)
|
||||
TEST_F(ValuePrintingTests, attrsTypeFirst)
|
||||
{
|
||||
Value vType;
|
||||
vType.mkString("puppy");
|
||||
vType.mkStringNoCopy("puppy");
|
||||
|
||||
Value vApple;
|
||||
vApple.mkString("apple");
|
||||
vApple.mkStringNoCopy("apple");
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("type"), &vType);
|
||||
builder.insert(state.symbols.create("apple"), &vApple);
|
||||
|
||||
@@ -334,7 +334,7 @@ TEST_F(ValuePrintingTests, ansiColorsBool)
|
||||
TEST_F(ValuePrintingTests, ansiColorsString)
|
||||
{
|
||||
Value v;
|
||||
v.mkString("puppy");
|
||||
v.mkStringNoCopy("puppy");
|
||||
|
||||
test(v, ANSI_MAGENTA "\"puppy\"" ANSI_NORMAL, PrintOptions{.ansiColors = true});
|
||||
}
|
||||
@@ -342,7 +342,7 @@ TEST_F(ValuePrintingTests, ansiColorsString)
|
||||
TEST_F(ValuePrintingTests, ansiColorsStringElided)
|
||||
{
|
||||
Value v;
|
||||
v.mkString("puppy");
|
||||
v.mkStringNoCopy("puppy");
|
||||
|
||||
test(
|
||||
v,
|
||||
@@ -374,7 +374,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs)
|
||||
Value vTwo;
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("one"), &vOne);
|
||||
builder.insert(state.symbols.create("two"), &vTwo);
|
||||
|
||||
@@ -390,10 +390,10 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs)
|
||||
TEST_F(ValuePrintingTests, ansiColorsDerivation)
|
||||
{
|
||||
Value vDerivation;
|
||||
vDerivation.mkString("derivation");
|
||||
vDerivation.mkStringNoCopy("derivation");
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
builder.insert(state.sType, &vDerivation);
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.s.type, &vDerivation);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -413,7 +413,7 @@ TEST_F(ValuePrintingTests, ansiColorsError)
|
||||
{
|
||||
Value throw_ = state.getBuiltin("throw");
|
||||
Value message;
|
||||
message.mkString("uh oh!");
|
||||
message.mkStringNoCopy("uh oh!");
|
||||
Value vError;
|
||||
vError.mkApp(&throw_, &message);
|
||||
|
||||
@@ -430,16 +430,16 @@ TEST_F(ValuePrintingTests, ansiColorsDerivationError)
|
||||
{
|
||||
Value throw_ = state.getBuiltin("throw");
|
||||
Value message;
|
||||
message.mkString("uh oh!");
|
||||
message.mkStringNoCopy("uh oh!");
|
||||
Value vError;
|
||||
vError.mkApp(&throw_, &message);
|
||||
|
||||
Value vDerivation;
|
||||
vDerivation.mkString("derivation");
|
||||
vDerivation.mkStringNoCopy("derivation");
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
builder.insert(state.sType, &vDerivation);
|
||||
builder.insert(state.sDrvPath, &vError);
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.s.type, &vDerivation);
|
||||
builder.insert(state.s.drvPath, &vError);
|
||||
|
||||
Value vAttrs;
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
@@ -553,12 +553,12 @@ TEST_F(ValuePrintingTests, ansiColorsBlackhole)
|
||||
|
||||
TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
|
||||
{
|
||||
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
|
||||
BindingsBuilder emptyBuilder = state.buildBindings(1);
|
||||
|
||||
Value vEmpty;
|
||||
vEmpty.mkAttrs(emptyBuilder.finish());
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("a"), &vEmpty);
|
||||
builder.insert(state.symbols.create("b"), &vEmpty);
|
||||
|
||||
@@ -570,7 +570,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
|
||||
|
||||
TEST_F(ValuePrintingTests, ansiColorsListRepeated)
|
||||
{
|
||||
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
|
||||
BindingsBuilder emptyBuilder = state.buildBindings(1);
|
||||
|
||||
Value vEmpty;
|
||||
vEmpty.mkAttrs(emptyBuilder.finish());
|
||||
@@ -586,7 +586,7 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated)
|
||||
|
||||
TEST_F(ValuePrintingTests, listRepeated)
|
||||
{
|
||||
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
|
||||
BindingsBuilder emptyBuilder = state.buildBindings(1);
|
||||
|
||||
Value vEmpty;
|
||||
vEmpty.mkAttrs(emptyBuilder.finish());
|
||||
@@ -609,7 +609,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||
Value vTwo;
|
||||
vTwo.mkInt(2);
|
||||
|
||||
BindingsBuilder builder(state, state.allocBindings(10));
|
||||
BindingsBuilder builder = state.buildBindings(10);
|
||||
builder.insert(state.symbols.create("one"), &vOne);
|
||||
builder.insert(state.symbols.create("two"), &vTwo);
|
||||
|
||||
@@ -635,8 +635,6 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||
|
||||
TEST_F(ValuePrintingTests, ansiColorsListElided)
|
||||
{
|
||||
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
|
||||
|
||||
Value vOne;
|
||||
vOne.mkInt(1);
|
||||
|
||||
|
||||
@@ -16,19 +16,19 @@ Bindings * EvalState::allocBindings(size_t capacity)
|
||||
throw Error("attribute set of size %d is too big", capacity);
|
||||
nrAttrsets++;
|
||||
nrAttrsInAttrsets += capacity;
|
||||
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings((Bindings::size_t) capacity);
|
||||
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings();
|
||||
}
|
||||
|
||||
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
|
||||
{
|
||||
auto value = state.allocValue();
|
||||
auto value = state.get().allocValue();
|
||||
bindings->push_back(Attr(name, value, pos));
|
||||
return *value;
|
||||
}
|
||||
|
||||
Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
|
||||
{
|
||||
return alloc(state.symbols.create(name), pos);
|
||||
return alloc(state.get().symbols.create(name), pos);
|
||||
}
|
||||
|
||||
void Bindings::sort()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/expr/eval-inline.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
// Need specialization involving `SymbolStr` just in this one module.
|
||||
#include "nix/util/strings-inline.hh"
|
||||
|
||||
@@ -69,10 +70,10 @@ struct AttrDb
|
||||
{
|
||||
auto state(_state->lock());
|
||||
|
||||
Path cacheDir = getCacheDir() + "/eval-cache-v5";
|
||||
auto cacheDir = std::filesystem::path(getCacheDir()) / "eval-cache-v6";
|
||||
createDirs(cacheDir);
|
||||
|
||||
Path dbPath = cacheDir + "/" + fingerprint.to_string(HashFormat::Base16, false) + ".sqlite";
|
||||
auto dbPath = cacheDir / (fingerprint.to_string(HashFormat::Base16, false) + ".sqlite");
|
||||
|
||||
state->db = SQLite(dbPath);
|
||||
state->db.isCache();
|
||||
@@ -329,7 +330,7 @@ AttrCursor::AttrCursor(
|
||||
AttrKey AttrCursor::getKey()
|
||||
{
|
||||
if (!parent)
|
||||
return {0, root->state.sEpsilon};
|
||||
return {0, root->state.s.epsilon};
|
||||
if (!parent->first->cachedValue) {
|
||||
parent->first->cachedValue = root->db->getAttr(parent->first->getKey());
|
||||
assert(parent->first->cachedValue);
|
||||
@@ -701,7 +702,7 @@ bool AttrCursor::isDerivation()
|
||||
|
||||
StorePath AttrCursor::forceDerivation()
|
||||
{
|
||||
auto aDrvPath = getAttr(root->state.sDrvPath);
|
||||
auto aDrvPath = getAttr(root->state.s.drvPath);
|
||||
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
|
||||
drvPath.requireDerivation();
|
||||
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {
|
||||
|
||||
@@ -113,5 +113,6 @@ template class EvalErrorBuilder<MissingArgumentError>;
|
||||
template class EvalErrorBuilder<InfiniteRecursionError>;
|
||||
template class EvalErrorBuilder<InvalidPathError>;
|
||||
template class EvalErrorBuilder<IFDError>;
|
||||
template class EvalErrorBuilder<RecoverableEvalError>;
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# endif
|
||||
|
||||
# include <gc/gc_allocator.h>
|
||||
# include <gc/gc_tiny_fl.h> // For GC_GRANULE_BYTES
|
||||
|
||||
# include <boost/coroutine2/coroutine.hpp>
|
||||
# include <boost/coroutine2/protected_fixedsize_stack.hpp>
|
||||
@@ -23,6 +24,17 @@
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ensure that Boehm satisfies our alignment requirements. This is the default configuration [^]
|
||||
* and this assertion should never break for any platform. Let's assert it just in case.
|
||||
*
|
||||
* This alignment is particularly useful to be able to use aligned
|
||||
* load/store instructions for loading/writing Values.
|
||||
*
|
||||
* [^]: https://github.com/bdwgc/bdwgc/blob/54ac18ccbc5a833dd7edaff94a10ab9b65044d61/include/gc/gc_tiny_fl.h#L31-L33
|
||||
*/
|
||||
static_assert(sizeof(void *) * 2 == GC_GRANULE_BYTES, "Boehm GC must use GC_GRANULE_WORDS = 2");
|
||||
|
||||
namespace nix {
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "nix/expr/eval-profiler-settings.hh"
|
||||
#include "nix/util/configuration.hh"
|
||||
#include "nix/util/logging.hh" /* Needs to be included before config-impl.hh */
|
||||
#include "nix/util/config-impl.hh"
|
||||
#include "nix/util/abstract-setting-to-json.hh"
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ FrameInfo SampleStack::getPrimOpFrameInfo(const PrimOp & primOp, std::span<Value
|
||||
/* Error context strings don't actually matter, since we ignore all eval errors. */
|
||||
state.forceAttrs(*args[0], pos, "");
|
||||
auto attrs = args[0]->attrs();
|
||||
auto nameAttr = state.getAttr(state.sName, attrs, "");
|
||||
auto nameAttr = state.getAttr(state.s.name, attrs, "");
|
||||
auto drvName = std::string(state.forceStringNoCtx(*nameAttr->value, pos, ""));
|
||||
return DerivationStrictFrameInfo{.callPos = pos, .drvName = std::move(drvName)};
|
||||
} catch (...) {
|
||||
@@ -211,7 +211,7 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, std::span<Va
|
||||
/* Resolve primOp eagerly. Must not hold on to a reference to a Value. */
|
||||
return PrimOpFrameInfo{.expr = v.primOpAppPrimOp(), .callPos = pos};
|
||||
else if (state.isFunctor(v)) {
|
||||
const auto functor = v.attrs()->get(state.sFunctor);
|
||||
const auto functor = v.attrs()->get(state.s.functor);
|
||||
if (auto pos_ = posCache.lookup(pos); std::holds_alternative<std::monostate>(pos_.origin))
|
||||
/* HACK: In case callsite position is unresolved. */
|
||||
return FunctorFrameInfo{.pos = functor->pos};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/expr/eval-error.hh"
|
||||
#include "nix/expr/eval-settings.hh"
|
||||
#include "nix/expr/primops.hh"
|
||||
#include "nix/expr/print-options.hh"
|
||||
@@ -6,6 +7,7 @@
|
||||
#include "nix/util/exit.hh"
|
||||
#include "nix/util/types.hh"
|
||||
#include "nix/util/util.hh"
|
||||
#include "nix/util/environment-variables.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/store/derivations.hh"
|
||||
#include "nix/store/downstream-placeholder.hh"
|
||||
@@ -21,10 +23,12 @@
|
||||
#include "nix/fetchers/fetch-to-store.hh"
|
||||
#include "nix/fetchers/tarball.hh"
|
||||
#include "nix/fetchers/input-cache.hh"
|
||||
#include "nix/util/current-process.hh"
|
||||
|
||||
#include "parser-tab.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
@@ -37,10 +41,6 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#ifndef _WIN32 // TODO use portable implementation
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "nix/util/strings-inline.hh"
|
||||
|
||||
using json = nlohmann::json;
|
||||
@@ -126,6 +126,8 @@ std::string_view showType(ValueType type, bool withArticle)
|
||||
return WA("a", "float");
|
||||
case nThunk:
|
||||
return WA("a", "thunk");
|
||||
case nFailed:
|
||||
return WA("a", "failure");
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
@@ -202,124 +204,65 @@ EvalState::EvalState(
|
||||
std::shared_ptr<Store> buildStore)
|
||||
: fetchSettings{fetchSettings}
|
||||
, settings{settings}
|
||||
, sWith(symbols.create("<with>"))
|
||||
, sOutPath(symbols.create("outPath"))
|
||||
, sDrvPath(symbols.create("drvPath"))
|
||||
, sType(symbols.create("type"))
|
||||
, sMeta(symbols.create("meta"))
|
||||
, sName(symbols.create("name"))
|
||||
, sValue(symbols.create("value"))
|
||||
, sSystem(symbols.create("system"))
|
||||
, sOverrides(symbols.create("__overrides"))
|
||||
, sOutputs(symbols.create("outputs"))
|
||||
, sOutputName(symbols.create("outputName"))
|
||||
, sIgnoreNulls(symbols.create("__ignoreNulls"))
|
||||
, sFile(symbols.create("file"))
|
||||
, sLine(symbols.create("line"))
|
||||
, sColumn(symbols.create("column"))
|
||||
, sFunctor(symbols.create("__functor"))
|
||||
, sToString(symbols.create("__toString"))
|
||||
, sRight(symbols.create("right"))
|
||||
, sWrong(symbols.create("wrong"))
|
||||
, sStructuredAttrs(symbols.create("__structuredAttrs"))
|
||||
, sJson(symbols.create("__json"))
|
||||
, sAllowedReferences(symbols.create("allowedReferences"))
|
||||
, sAllowedRequisites(symbols.create("allowedRequisites"))
|
||||
, sDisallowedReferences(symbols.create("disallowedReferences"))
|
||||
, sDisallowedRequisites(symbols.create("disallowedRequisites"))
|
||||
, sMaxSize(symbols.create("maxSize"))
|
||||
, sMaxClosureSize(symbols.create("maxClosureSize"))
|
||||
, sBuilder(symbols.create("builder"))
|
||||
, sArgs(symbols.create("args"))
|
||||
, sContentAddressed(symbols.create("__contentAddressed"))
|
||||
, sImpure(symbols.create("__impure"))
|
||||
, sOutputHash(symbols.create("outputHash"))
|
||||
, sOutputHashAlgo(symbols.create("outputHashAlgo"))
|
||||
, sOutputHashMode(symbols.create("outputHashMode"))
|
||||
, sRecurseForDerivations(symbols.create("recurseForDerivations"))
|
||||
, sDescription(symbols.create("description"))
|
||||
, sSelf(symbols.create("self"))
|
||||
, sEpsilon(symbols.create(""))
|
||||
, sStartSet(symbols.create("startSet"))
|
||||
, sOperator(symbols.create("operator"))
|
||||
, sKey(symbols.create("key"))
|
||||
, sPath(symbols.create("path"))
|
||||
, sPrefix(symbols.create("prefix"))
|
||||
, sOutputSpecified(symbols.create("outputSpecified"))
|
||||
, exprSymbols{
|
||||
.sub = symbols.create("__sub"),
|
||||
.lessThan = symbols.create("__lessThan"),
|
||||
.mul = symbols.create("__mul"),
|
||||
.div = symbols.create("__div"),
|
||||
.or_ = symbols.create("or"),
|
||||
.findFile = symbols.create("__findFile"),
|
||||
.nixPath = symbols.create("__nixPath"),
|
||||
.body = symbols.create("body"),
|
||||
}
|
||||
, symbols(StaticEvalSymbols::staticSymbolTable())
|
||||
, repair(NoRepair)
|
||||
, emptyBindings(0)
|
||||
, storeFS(
|
||||
makeMountedSourceAccessor(
|
||||
{
|
||||
{CanonPath::root, makeEmptySourceAccessor()},
|
||||
/* In the pure eval case, we can simply require
|
||||
valid paths. However, in the *impure* eval
|
||||
case this gets in the way of the union
|
||||
mechanism, because an invalid access in the
|
||||
upper layer will *not* be caught by the union
|
||||
source accessor, but instead abort the entire
|
||||
lookup.
|
||||
, emptyBindings(Bindings())
|
||||
, storeFS(makeMountedSourceAccessor({
|
||||
{CanonPath::root, makeEmptySourceAccessor()},
|
||||
/* In the pure eval case, we can simply require
|
||||
valid paths. However, in the *impure* eval
|
||||
case this gets in the way of the union
|
||||
mechanism, because an invalid access in the
|
||||
upper layer will *not* be caught by the union
|
||||
source accessor, but instead abort the entire
|
||||
lookup.
|
||||
|
||||
This happens when the store dir in the
|
||||
ambient file system has a path (e.g. because
|
||||
another Nix store there), but the relocated
|
||||
store does not.
|
||||
This happens when the store dir in the
|
||||
ambient file system has a path (e.g. because
|
||||
another Nix store there), but the relocated
|
||||
store does not.
|
||||
|
||||
TODO make the various source accessors doing
|
||||
access control all throw the same type of
|
||||
exception, and make union source accessor
|
||||
catch it, so we don't need to do this hack.
|
||||
*/
|
||||
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
|
||||
}))
|
||||
, rootFS(
|
||||
({
|
||||
/* In pure eval mode, we provide a filesystem that only
|
||||
contains the Nix store.
|
||||
TODO make the various source accessors doing
|
||||
access control all throw the same type of
|
||||
exception, and make union source accessor
|
||||
catch it, so we don't need to do this hack.
|
||||
*/
|
||||
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
|
||||
}))
|
||||
, rootFS(({
|
||||
/* In pure eval mode, we provide a filesystem that only
|
||||
contains the Nix store.
|
||||
|
||||
If we have a chroot store and pure eval is not enabled,
|
||||
use a union accessor to make the chroot store available
|
||||
at its logical location while still having the
|
||||
underlying directory available. This is necessary for
|
||||
instance if we're evaluating a file from the physical
|
||||
/nix/store while using a chroot store. */
|
||||
auto accessor = getFSSourceAccessor();
|
||||
If we have a chroot store and pure eval is not enabled,
|
||||
use a union accessor to make the chroot store available
|
||||
at its logical location while still having the
|
||||
underlying directory available. This is necessary for
|
||||
instance if we're evaluating a file from the physical
|
||||
/nix/store while using a chroot store. */
|
||||
auto accessor = getFSSourceAccessor();
|
||||
|
||||
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
|
||||
if (settings.pureEval || store->storeDir != realStoreDir) {
|
||||
accessor = settings.pureEval
|
||||
? storeFS
|
||||
: makeUnionSourceAccessor({accessor, storeFS});
|
||||
}
|
||||
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
|
||||
if (settings.pureEval || store->storeDir != realStoreDir) {
|
||||
accessor = settings.pureEval ? storeFS : makeUnionSourceAccessor({accessor, storeFS});
|
||||
}
|
||||
|
||||
/* Apply access control if needed. */
|
||||
if (settings.restrictEval || settings.pureEval)
|
||||
accessor = AllowListSourceAccessor::create(accessor, {}, {},
|
||||
[&settings](const CanonPath & path) -> RestrictedPathError {
|
||||
auto modeInformation = settings.pureEval
|
||||
? "in pure evaluation mode (use '--impure' to override)"
|
||||
: "in restricted mode";
|
||||
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
|
||||
});
|
||||
/* Apply access control if needed. */
|
||||
if (settings.restrictEval || settings.pureEval)
|
||||
accessor = AllowListSourceAccessor::create(
|
||||
accessor, {}, {}, [&settings](const CanonPath & path) -> RestrictedPathError {
|
||||
auto modeInformation = settings.pureEval ? "in pure evaluation mode (use '--impure' to override)"
|
||||
: "in restricted mode";
|
||||
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
|
||||
});
|
||||
|
||||
accessor;
|
||||
}))
|
||||
accessor;
|
||||
}))
|
||||
, corepkgsFS(make_ref<MemorySourceAccessor>())
|
||||
, internalFS(make_ref<MemorySourceAccessor>())
|
||||
, derivationInternal{corepkgsFS->addFile(
|
||||
CanonPath("derivation-internal.nix"),
|
||||
CanonPath("derivation-internal.nix"),
|
||||
#include "primops/derivation.nix.gen.hh"
|
||||
)}
|
||||
)}
|
||||
, store(store)
|
||||
, buildStore(buildStore ? buildStore : store)
|
||||
, inputCache(fetchers::InputCache::create())
|
||||
@@ -350,10 +293,10 @@ EvalState::EvalState(
|
||||
vNull.mkNull();
|
||||
vTrue.mkBool(true);
|
||||
vFalse.mkBool(false);
|
||||
vStringRegular.mkString("regular");
|
||||
vStringDirectory.mkString("directory");
|
||||
vStringSymlink.mkString("symlink");
|
||||
vStringUnknown.mkString("unknown");
|
||||
vStringRegular.mkStringNoCopy("regular");
|
||||
vStringDirectory.mkStringNoCopy("directory");
|
||||
vStringSymlink.mkStringNoCopy("symlink");
|
||||
vStringUnknown.mkStringNoCopy("unknown");
|
||||
|
||||
/* Construct the Nix expression search path. */
|
||||
assert(lookupPath.elements.empty());
|
||||
@@ -653,7 +596,7 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||
}
|
||||
if (isFunctor(v)) {
|
||||
try {
|
||||
Value & functor = *v.attrs()->find(sFunctor)->value;
|
||||
Value & functor = *v.attrs()->find(s.functor)->value;
|
||||
Value * vp[] = {&v};
|
||||
Value partiallyApplied;
|
||||
// The first parameter is not user-provided, and may be
|
||||
@@ -882,7 +825,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t)
|
||||
|
||||
void Value::mkString(std::string_view s)
|
||||
{
|
||||
mkString(makeImmutableString(s));
|
||||
mkStringNoCopy(makeImmutableString(s));
|
||||
}
|
||||
|
||||
static const char ** encodeContext(const NixStringContext & context)
|
||||
@@ -901,12 +844,12 @@ static const char ** encodeContext(const NixStringContext & context)
|
||||
|
||||
void Value::mkString(std::string_view s, const NixStringContext & context)
|
||||
{
|
||||
mkString(makeImmutableString(s), encodeContext(context));
|
||||
mkStringNoCopy(makeImmutableString(s), encodeContext(context));
|
||||
}
|
||||
|
||||
void Value::mkStringMove(const char * s, const NixStringContext & context)
|
||||
{
|
||||
mkString(s, encodeContext(context));
|
||||
mkStringNoCopy(s, encodeContext(context));
|
||||
}
|
||||
|
||||
void Value::mkPath(const SourcePath & path)
|
||||
@@ -977,8 +920,8 @@ void EvalState::mkPos(Value & v, PosIdx p)
|
||||
auto origin = positions.originOf(p);
|
||||
if (auto path = std::get_if<SourcePath>(&origin)) {
|
||||
auto attrs = buildBindings(3);
|
||||
attrs.alloc(sFile).mkString(path->path.abs());
|
||||
makePositionThunks(*this, p, attrs.alloc(sLine), attrs.alloc(sColumn));
|
||||
attrs.alloc(s.file).mkString(path->path.abs());
|
||||
makePositionThunks(*this, p, attrs.alloc(s.line), attrs.alloc(s.column));
|
||||
v.mkAttrs(attrs);
|
||||
} else
|
||||
v.mkNull();
|
||||
@@ -1244,7 +1187,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
dynamicEnv = &env2;
|
||||
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env2) : nullptr;
|
||||
|
||||
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
|
||||
AttrDefs::iterator overrides = attrs.find(state.s.overrides);
|
||||
bool hasOverrides = overrides != attrs.end();
|
||||
|
||||
/* The recursive attributes are evaluated in the new
|
||||
@@ -1276,7 +1219,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
*vOverrides,
|
||||
[&]() { return vOverrides->determinePos(noPos); },
|
||||
"while evaluating the `__overrides` attribute");
|
||||
bindings.grow(state.allocBindings(bindings.capacity() + vOverrides->attrs()->size()));
|
||||
bindings.grow(state.buildBindings(bindings.capacity() + vOverrides->attrs()->size()));
|
||||
for (auto & i : *vOverrides->attrs()) {
|
||||
AttrDefs::iterator j = attrs.find(i.name);
|
||||
if (j != attrs.end()) {
|
||||
@@ -1716,7 +1659,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
|
||||
}
|
||||
}
|
||||
|
||||
else if (vCur.type() == nAttrs && (functor = vCur.attrs()->get(sFunctor))) {
|
||||
else if (vCur.type() == nAttrs && (functor = vCur.attrs()->get(s.functor))) {
|
||||
/* 'vCur' may be allocated on the stack of the calling
|
||||
function, but for functors we may keep a reference, so
|
||||
heap-allocate a copy and use that instead. */
|
||||
@@ -1778,7 +1721,7 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
|
||||
forceValue(fun, pos);
|
||||
|
||||
if (fun.type() == nAttrs) {
|
||||
auto found = fun.attrs()->find(sFunctor);
|
||||
auto found = fun.attrs()->find(s.functor);
|
||||
if (found != fun.attrs()->end()) {
|
||||
Value * v = allocValue();
|
||||
callFunction(*found->value, fun, *v, pos);
|
||||
@@ -2121,6 +2064,54 @@ void ExprBlackHole::eval(EvalState & state, [[maybe_unused]] Env & env, Value &
|
||||
// always force this to be separate, otherwise forceValue may inline it and take
|
||||
// a massive perf hit
|
||||
[[gnu::noinline]]
|
||||
void EvalState::handleEvalExceptionForThunk(Env * env, Expr * expr, Value & v, const PosIdx pos)
|
||||
{
|
||||
v.mkThunk(env, expr);
|
||||
tryFixupBlackHolePos(v, pos);
|
||||
|
||||
auto e = std::current_exception();
|
||||
Value * recovery = nullptr;
|
||||
try {
|
||||
std::rethrow_exception(e);
|
||||
} catch (const RecoverableEvalError & e) {
|
||||
recovery = allocValue();
|
||||
} catch (...) {
|
||||
}
|
||||
if (recovery) {
|
||||
recovery->mkThunk(env, expr);
|
||||
}
|
||||
v.mkFailed(e, recovery);
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void EvalState::handleEvalExceptionForApp(Value & v)
|
||||
{
|
||||
auto e = std::current_exception();
|
||||
Value * recovery = nullptr;
|
||||
try {
|
||||
std::rethrow_exception(e);
|
||||
} catch (const RecoverableEvalError & e) {
|
||||
recovery = allocValue();
|
||||
} catch (...) {
|
||||
}
|
||||
if (recovery) {
|
||||
*recovery = v;
|
||||
}
|
||||
v.mkFailed(e, recovery);
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void EvalState::handleEvalFailed(Value & v, const PosIdx pos)
|
||||
{
|
||||
assert(v.isFailed());
|
||||
if (auto recoveryValue = v.failed()->recoveryValue) {
|
||||
v = *recoveryValue;
|
||||
forceValue(v, pos);
|
||||
} else {
|
||||
std::rethrow_exception(v.failed()->ex);
|
||||
}
|
||||
}
|
||||
|
||||
void EvalState::tryFixupBlackHolePos(Value & v, PosIdx pos)
|
||||
{
|
||||
if (!v.isBlackhole())
|
||||
@@ -2129,7 +2120,8 @@ void EvalState::tryFixupBlackHolePos(Value & v, PosIdx pos)
|
||||
try {
|
||||
std::rethrow_exception(e);
|
||||
} catch (InfiniteRecursionError & e) {
|
||||
e.atPos(positions[pos]);
|
||||
if (!e.hasPos())
|
||||
e.atPos(positions[pos]);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
@@ -2240,7 +2232,7 @@ Bindings::const_iterator EvalState::getAttr(Symbol attrSym, const Bindings * att
|
||||
|
||||
bool EvalState::isFunctor(const Value & fun) const
|
||||
{
|
||||
return fun.type() == nAttrs && fun.attrs()->find(sFunctor) != fun.attrs()->end();
|
||||
return fun.type() == nAttrs && fun.attrs()->find(s.functor) != fun.attrs()->end();
|
||||
}
|
||||
|
||||
void EvalState::forceFunction(Value & v, const PosIdx pos, std::string_view errorCtx)
|
||||
@@ -2309,7 +2301,7 @@ bool EvalState::isDerivation(Value & v)
|
||||
{
|
||||
if (v.type() != nAttrs)
|
||||
return false;
|
||||
auto i = v.attrs()->get(sType);
|
||||
auto i = v.attrs()->get(s.type);
|
||||
if (!i)
|
||||
return false;
|
||||
forceValue(*i->value, i->pos);
|
||||
@@ -2321,7 +2313,7 @@ bool EvalState::isDerivation(Value & v)
|
||||
std::optional<std::string>
|
||||
EvalState::tryAttrsToString(const PosIdx pos, Value & v, NixStringContext & context, bool coerceMore, bool copyToStore)
|
||||
{
|
||||
auto i = v.attrs()->find(sToString);
|
||||
auto i = v.attrs()->find(s.toString);
|
||||
if (i != v.attrs()->end()) {
|
||||
Value v1;
|
||||
callFunction(*i->value, v, v1, pos);
|
||||
@@ -2367,7 +2359,7 @@ BackedStringView EvalState::coerceToString(
|
||||
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
|
||||
if (maybeString)
|
||||
return std::move(*maybeString);
|
||||
auto i = v.attrs()->find(sOutPath);
|
||||
auto i = v.attrs()->find(s.outPath);
|
||||
if (i == v.attrs()->end()) {
|
||||
error<TypeError>(
|
||||
"cannot coerce %1% to a string: %2%", showType(v), ValuePrinter(*this, v, errorPrintOptions))
|
||||
@@ -2474,7 +2466,7 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
|
||||
/* Similarly, handle __toString where the result may be a path
|
||||
value. */
|
||||
if (v.type() == nAttrs) {
|
||||
auto i = v.attrs()->find(sToString);
|
||||
auto i = v.attrs()->find(s.toString);
|
||||
if (i != v.attrs()->end()) {
|
||||
Value v1;
|
||||
callFunction(*i->value, v, v1, pos);
|
||||
@@ -2664,8 +2656,8 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
|
||||
|
||||
case nAttrs: {
|
||||
if (isDerivation(v1) && isDerivation(v2)) {
|
||||
auto i = v1.attrs()->get(sOutPath);
|
||||
auto j = v2.attrs()->get(sOutPath);
|
||||
auto i = v1.attrs()->get(s.outPath);
|
||||
auto j = v2.attrs()->get(s.outPath);
|
||||
if (i && j) {
|
||||
try {
|
||||
assertEqValues(*i->value, *j->value, pos, errorCtx);
|
||||
@@ -2754,8 +2746,11 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
|
||||
}
|
||||
return;
|
||||
|
||||
case nThunk: // Must not be left by forceValue
|
||||
assert(false);
|
||||
// Cannot be returned by forceValue().
|
||||
case nThunk:
|
||||
case nFailed:
|
||||
unreachable();
|
||||
|
||||
default: // Note that we pass compiler flags that should make `default:` unreachable.
|
||||
// Also note that this probably ran after `eqValues`, which implements
|
||||
// the same logic more efficiently (without having to unwind stacks),
|
||||
@@ -2818,8 +2813,8 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
/* If both sets denote a derivation (type = "derivation"),
|
||||
then compare their outPaths. */
|
||||
if (isDerivation(v1) && isDerivation(v2)) {
|
||||
auto i = v1.attrs()->get(sOutPath);
|
||||
auto j = v2.attrs()->get(sOutPath);
|
||||
auto i = v1.attrs()->get(s.outPath);
|
||||
auto j = v2.attrs()->get(s.outPath);
|
||||
if (i && j)
|
||||
return eqValues(*i->value, *j->value, pos, errorCtx);
|
||||
}
|
||||
@@ -2847,8 +2842,11 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||
// !!!
|
||||
return v1.fpoint() == v2.fpoint();
|
||||
|
||||
case nThunk: // Must not be left by forceValue
|
||||
assert(false);
|
||||
// Cannot be returned by forceValue().
|
||||
case nThunk:
|
||||
case nFailed:
|
||||
unreachable();
|
||||
|
||||
default: // Note that we pass compiler flags that should make `default:` unreachable.
|
||||
error<EvalError>("eqValues: cannot compare %1% with %2%", showType(v1), showType(v2))
|
||||
.withTrace(pos, errorCtx)
|
||||
@@ -2888,11 +2886,8 @@ void EvalState::maybePrintStats()
|
||||
|
||||
void EvalState::printStatistics()
|
||||
{
|
||||
#ifndef _WIN32 // TODO use portable implementation
|
||||
struct rusage buf;
|
||||
getrusage(RUSAGE_SELF, &buf);
|
||||
float cpuTime = buf.ru_utime.tv_sec + ((float) buf.ru_utime.tv_usec / 1000000);
|
||||
#endif
|
||||
std::chrono::microseconds cpuTimeDuration = getCpuUserTime();
|
||||
float cpuTime = std::chrono::duration_cast<std::chrono::duration<float>>(cpuTimeDuration).count();
|
||||
|
||||
uint64_t bEnvs = nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *);
|
||||
uint64_t bLists = nrListElems * sizeof(Value *);
|
||||
@@ -2914,18 +2909,12 @@ void EvalState::printStatistics()
|
||||
if (outPath != "-")
|
||||
fs.open(outPath, std::fstream::out);
|
||||
json topObj = json::object();
|
||||
#ifndef _WIN32 // TODO implement
|
||||
topObj["cpuTime"] = cpuTime;
|
||||
#endif
|
||||
topObj["time"] = {
|
||||
#ifndef _WIN32 // TODO implement
|
||||
{"cpu", cpuTime},
|
||||
#endif
|
||||
#if NIX_USE_BOEHMGC
|
||||
{GC_is_incremental_mode() ? "gcNonIncremental" : "gc", gcFullOnlyTime},
|
||||
# ifndef _WIN32 // TODO implement
|
||||
{GC_is_incremental_mode() ? "gcNonIncrementalFraction" : "gcFraction", gcFullOnlyTime / cpuTime},
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
topObj["envs"] = {
|
||||
@@ -3195,8 +3184,7 @@ Expr * EvalState::parse(
|
||||
docComments = &it->second;
|
||||
}
|
||||
|
||||
auto result = parseExprFromBuf(
|
||||
text, length, origin, basePath, symbols, settings, positions, *docComments, rootFS, exprSymbols);
|
||||
auto result = parseExprFromBuf(text, length, origin, basePath, symbols, settings, positions, *docComments, rootFS);
|
||||
|
||||
result->bindVars(*this, staticEnv);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ PackageInfo::PackageInfo(EvalState & state, ref<Store> store, const std::string
|
||||
std::string PackageInfo::queryName() const
|
||||
{
|
||||
if (name == "" && attrs) {
|
||||
auto i = attrs->find(state->sName);
|
||||
auto i = attrs->find(state->s.name);
|
||||
if (i == attrs->end())
|
||||
state->error<TypeError>("derivation name missing").debugThrow();
|
||||
name = state->forceStringNoCtx(*i->value, noPos, "while evaluating the 'name' attribute of a derivation");
|
||||
@@ -56,7 +56,7 @@ std::string PackageInfo::queryName() const
|
||||
std::string PackageInfo::querySystem() const
|
||||
{
|
||||
if (system == "" && attrs) {
|
||||
auto i = attrs->find(state->sSystem);
|
||||
auto i = attrs->find(state->s.system);
|
||||
system =
|
||||
i == attrs->end()
|
||||
? "unknown"
|
||||
@@ -68,7 +68,7 @@ std::string PackageInfo::querySystem() const
|
||||
std::optional<StorePath> PackageInfo::queryDrvPath() const
|
||||
{
|
||||
if (!drvPath && attrs) {
|
||||
if (auto i = attrs->get(state->sDrvPath)) {
|
||||
if (auto i = attrs->get(state->s.drvPath)) {
|
||||
NixStringContext context;
|
||||
auto found = state->coerceToStorePath(
|
||||
i->pos, *i->value, context, "while evaluating the 'drvPath' attribute of a derivation");
|
||||
@@ -95,7 +95,7 @@ StorePath PackageInfo::requireDrvPath() const
|
||||
StorePath PackageInfo::queryOutPath() const
|
||||
{
|
||||
if (!outPath && attrs) {
|
||||
auto i = attrs->find(state->sOutPath);
|
||||
auto i = attrs->find(state->s.outPath);
|
||||
NixStringContext context;
|
||||
if (i != attrs->end())
|
||||
outPath = state->coerceToStorePath(
|
||||
@@ -111,7 +111,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||
if (outputs.empty()) {
|
||||
/* Get the ‘outputs’ list. */
|
||||
const Attr * i;
|
||||
if (attrs && (i = attrs->get(state->sOutputs))) {
|
||||
if (attrs && (i = attrs->get(state->s.outputs))) {
|
||||
state->forceList(*i->value, i->pos, "while evaluating the 'outputs' attribute of a derivation");
|
||||
|
||||
/* For each output... */
|
||||
@@ -127,7 +127,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||
state->forceAttrs(*out->value, i->pos, "while evaluating an output of a derivation");
|
||||
|
||||
/* And evaluate its ‘outPath’ attribute. */
|
||||
auto outPath = out->value->attrs()->get(state->sOutPath);
|
||||
auto outPath = out->value->attrs()->get(state->s.outPath);
|
||||
if (!outPath)
|
||||
continue; // FIXME: throw error?
|
||||
NixStringContext context;
|
||||
@@ -146,7 +146,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||
return outputs;
|
||||
|
||||
const Attr * i;
|
||||
if (attrs && (i = attrs->get(state->sOutputSpecified))
|
||||
if (attrs && (i = attrs->get(state->s.outputSpecified))
|
||||
&& state->forceBool(*i->value, i->pos, "while evaluating the 'outputSpecified' attribute of a derivation")) {
|
||||
Outputs result;
|
||||
auto out = outputs.find(queryOutputName());
|
||||
@@ -181,7 +181,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
|
||||
std::string PackageInfo::queryOutputName() const
|
||||
{
|
||||
if (outputName == "" && attrs) {
|
||||
auto i = attrs->get(state->sOutputName);
|
||||
auto i = attrs->get(state->s.outputName);
|
||||
outputName =
|
||||
i ? state->forceStringNoCtx(*i->value, noPos, "while evaluating the output name of a derivation") : "";
|
||||
}
|
||||
@@ -194,7 +194,7 @@ const Bindings * PackageInfo::getMeta()
|
||||
return meta;
|
||||
if (!attrs)
|
||||
return 0;
|
||||
auto a = attrs->get(state->sMeta);
|
||||
auto a = attrs->get(state->s.meta);
|
||||
if (!a)
|
||||
return 0;
|
||||
state->forceAttrs(*a->value, a->pos, "while evaluating the 'meta' attribute of a derivation");
|
||||
@@ -221,7 +221,7 @@ bool PackageInfo::checkMeta(Value & v)
|
||||
return false;
|
||||
return true;
|
||||
} else if (v.type() == nAttrs) {
|
||||
if (v.attrs()->get(state->sOutPath))
|
||||
if (v.attrs()->get(state->s.outPath))
|
||||
return false;
|
||||
for (auto & i : *v.attrs())
|
||||
if (!checkMeta(*i.value))
|
||||
@@ -411,7 +411,7 @@ static void getDerivations(
|
||||
should we recurse into it? => Only if it has a
|
||||
`recurseForDerivations = true' attribute. */
|
||||
if (i->value->type() == nAttrs) {
|
||||
auto j = i->value->attrs()->get(state.sRecurseForDerivations);
|
||||
auto j = i->value->attrs()->get(state.s.recurseForDerivations);
|
||||
if (j
|
||||
&& state.forceBool(
|
||||
*j->value, j->pos, "while evaluating the attribute `recurseForDerivations`"))
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "nix/expr/symbol-table.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -22,7 +23,7 @@ struct Attr
|
||||
way we keep Attr size at two words with no wasted space. */
|
||||
Symbol name;
|
||||
PosIdx pos;
|
||||
Value * value;
|
||||
Value * value = nullptr;
|
||||
Attr(Symbol name, Value * value, PosIdx pos = noPos)
|
||||
: name(name)
|
||||
, pos(pos)
|
||||
@@ -54,16 +55,14 @@ public:
|
||||
PosIdx pos;
|
||||
|
||||
private:
|
||||
size_t size_, capacity_;
|
||||
size_t size_ = 0;
|
||||
Attr attrs[0];
|
||||
|
||||
Bindings(size_t capacity)
|
||||
: size_(0)
|
||||
, capacity_(capacity)
|
||||
{
|
||||
}
|
||||
|
||||
Bindings(const Bindings & bindings) = delete;
|
||||
Bindings() = default;
|
||||
Bindings(const Bindings &) = delete;
|
||||
Bindings(Bindings &&) = delete;
|
||||
Bindings & operator=(const Bindings &) = delete;
|
||||
Bindings & operator=(Bindings &&) = delete;
|
||||
|
||||
public:
|
||||
size_t size() const
|
||||
@@ -82,7 +81,6 @@ public:
|
||||
|
||||
void push_back(const Attr & attr)
|
||||
{
|
||||
assert(size_ < capacity_);
|
||||
attrs[size_++] = attr;
|
||||
}
|
||||
|
||||
@@ -136,11 +134,6 @@ public:
|
||||
|
||||
void sort();
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attributes in lexicographically sorted order.
|
||||
*/
|
||||
@@ -165,22 +158,29 @@ public:
|
||||
* order at the end. The only way to consume a BindingsBuilder is to
|
||||
* call finish(), which sorts the bindings.
|
||||
*/
|
||||
class BindingsBuilder
|
||||
class BindingsBuilder final
|
||||
{
|
||||
Bindings * bindings;
|
||||
|
||||
public:
|
||||
// needed by std::back_inserter
|
||||
using value_type = Attr;
|
||||
using size_type = Bindings::size_t;
|
||||
|
||||
EvalState & state;
|
||||
private:
|
||||
Bindings * bindings;
|
||||
Bindings::size_t capacity_;
|
||||
|
||||
BindingsBuilder(EvalState & state, Bindings * bindings)
|
||||
friend class EvalState;
|
||||
|
||||
BindingsBuilder(EvalState & state, Bindings * bindings, size_type capacity)
|
||||
: bindings(bindings)
|
||||
, capacity_(capacity)
|
||||
, state(state)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::reference_wrapper<EvalState> state;
|
||||
|
||||
void insert(Symbol name, Value * value, PosIdx pos = noPos)
|
||||
{
|
||||
insert(Attr(name, value, pos));
|
||||
@@ -193,6 +193,7 @@ public:
|
||||
|
||||
void push_back(const Attr & attr)
|
||||
{
|
||||
assert(bindings->size() < capacity_);
|
||||
bindings->push_back(attr);
|
||||
}
|
||||
|
||||
@@ -211,16 +212,16 @@ public:
|
||||
return bindings;
|
||||
}
|
||||
|
||||
size_t capacity()
|
||||
size_t capacity() const noexcept
|
||||
{
|
||||
return bindings->capacity();
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
void grow(Bindings * newBindings)
|
||||
void grow(BindingsBuilder newBindings)
|
||||
{
|
||||
for (auto & i : *bindings)
|
||||
newBindings->push_back(i);
|
||||
bindings = newBindings;
|
||||
newBindings.push_back(i);
|
||||
std::swap(*this, newBindings);
|
||||
}
|
||||
|
||||
friend struct ExprAttrs;
|
||||
|
||||
@@ -56,6 +56,14 @@ MakeError(MissingArgumentError, EvalError);
|
||||
MakeError(InfiniteRecursionError, EvalError);
|
||||
MakeError(IFDError, EvalBaseError);
|
||||
|
||||
/**
|
||||
* An evaluation error which should be retried instead of rethrown
|
||||
*
|
||||
* A RecoverableEvalError is not an EvalError, because we shouldn't cache it in the eval cache, as it should be retried
|
||||
* anyway.
|
||||
*/
|
||||
MakeError(RecoverableEvalError, EvalBaseError);
|
||||
|
||||
struct InvalidPathError : public EvalError
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/expr/eval-error.hh"
|
||||
#include "nix/expr/eval-settings.hh"
|
||||
#include <exception>
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -97,12 +98,19 @@ void EvalState::forceValue(Value & v, const PosIdx pos)
|
||||
else
|
||||
ExprBlackHole::throwInfiniteRecursionError(*this, v);
|
||||
} catch (...) {
|
||||
v.mkThunk(env, expr);
|
||||
tryFixupBlackHolePos(v, pos);
|
||||
handleEvalExceptionForThunk(env, expr, v, pos);
|
||||
throw;
|
||||
}
|
||||
} else if (v.isApp())
|
||||
callFunction(*v.app().left, *v.app().right, v, pos);
|
||||
} else if (v.isApp()) {
|
||||
try {
|
||||
callFunction(*v.app().left, *v.app().right, v, pos);
|
||||
} catch (...) {
|
||||
handleEvalExceptionForApp(v);
|
||||
throw;
|
||||
}
|
||||
} else if (v.isFailed()) {
|
||||
handleEvalFailed(v, pos);
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
|
||||
@@ -213,23 +213,100 @@ struct DebugTrace
|
||||
}
|
||||
};
|
||||
|
||||
struct StaticEvalSymbols
|
||||
{
|
||||
Symbol with, outPath, drvPath, type, meta, name, value, system, overrides, outputs, outputName, ignoreNulls, file,
|
||||
line, column, functor, toString, right, wrong, structuredAttrs, json, allowedReferences, allowedRequisites,
|
||||
disallowedReferences, disallowedRequisites, maxSize, maxClosureSize, builder, args, contentAddressed, impure,
|
||||
outputHash, outputHashAlgo, outputHashMode, recurseForDerivations, description, self, epsilon, startSet,
|
||||
operator_, key, path, prefix, outputSpecified;
|
||||
|
||||
Expr::AstSymbols exprSymbols;
|
||||
|
||||
static constexpr auto preallocate()
|
||||
{
|
||||
StaticSymbolTable alloc;
|
||||
|
||||
StaticEvalSymbols staticSymbols = {
|
||||
.with = alloc.create("<with>"),
|
||||
.outPath = alloc.create("outPath"),
|
||||
.drvPath = alloc.create("drvPath"),
|
||||
.type = alloc.create("type"),
|
||||
.meta = alloc.create("meta"),
|
||||
.name = alloc.create("name"),
|
||||
.value = alloc.create("value"),
|
||||
.system = alloc.create("system"),
|
||||
.overrides = alloc.create("__overrides"),
|
||||
.outputs = alloc.create("outputs"),
|
||||
.outputName = alloc.create("outputName"),
|
||||
.ignoreNulls = alloc.create("__ignoreNulls"),
|
||||
.file = alloc.create("file"),
|
||||
.line = alloc.create("line"),
|
||||
.column = alloc.create("column"),
|
||||
.functor = alloc.create("__functor"),
|
||||
.toString = alloc.create("__toString"),
|
||||
.right = alloc.create("right"),
|
||||
.wrong = alloc.create("wrong"),
|
||||
.structuredAttrs = alloc.create("__structuredAttrs"),
|
||||
.json = alloc.create("__json"),
|
||||
.allowedReferences = alloc.create("allowedReferences"),
|
||||
.allowedRequisites = alloc.create("allowedRequisites"),
|
||||
.disallowedReferences = alloc.create("disallowedReferences"),
|
||||
.disallowedRequisites = alloc.create("disallowedRequisites"),
|
||||
.maxSize = alloc.create("maxSize"),
|
||||
.maxClosureSize = alloc.create("maxClosureSize"),
|
||||
.builder = alloc.create("builder"),
|
||||
.args = alloc.create("args"),
|
||||
.contentAddressed = alloc.create("__contentAddressed"),
|
||||
.impure = alloc.create("__impure"),
|
||||
.outputHash = alloc.create("outputHash"),
|
||||
.outputHashAlgo = alloc.create("outputHashAlgo"),
|
||||
.outputHashMode = alloc.create("outputHashMode"),
|
||||
.recurseForDerivations = alloc.create("recurseForDerivations"),
|
||||
.description = alloc.create("description"),
|
||||
.self = alloc.create("self"),
|
||||
.epsilon = alloc.create(""),
|
||||
.startSet = alloc.create("startSet"),
|
||||
.operator_ = alloc.create("operator"),
|
||||
.key = alloc.create("key"),
|
||||
.path = alloc.create("path"),
|
||||
.prefix = alloc.create("prefix"),
|
||||
.outputSpecified = alloc.create("outputSpecified"),
|
||||
.exprSymbols = {
|
||||
.sub = alloc.create("__sub"),
|
||||
.lessThan = alloc.create("__lessThan"),
|
||||
.mul = alloc.create("__mul"),
|
||||
.div = alloc.create("__div"),
|
||||
.or_ = alloc.create("or"),
|
||||
.findFile = alloc.create("__findFile"),
|
||||
.nixPath = alloc.create("__nixPath"),
|
||||
.body = alloc.create("body"),
|
||||
}};
|
||||
|
||||
return std::pair{staticSymbols, alloc};
|
||||
}
|
||||
|
||||
static consteval StaticEvalSymbols create()
|
||||
{
|
||||
return preallocate().first;
|
||||
}
|
||||
|
||||
static constexpr StaticSymbolTable staticSymbolTable()
|
||||
{
|
||||
return preallocate().second;
|
||||
}
|
||||
};
|
||||
|
||||
class EvalState : public std::enable_shared_from_this<EvalState>
|
||||
{
|
||||
public:
|
||||
static constexpr StaticEvalSymbols s = StaticEvalSymbols::create();
|
||||
|
||||
const fetchers::Settings & fetchSettings;
|
||||
const EvalSettings & settings;
|
||||
SymbolTable symbols;
|
||||
PosTable positions;
|
||||
|
||||
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName,
|
||||
sIgnoreNulls, sFile, sLine, sColumn, sFunctor, sToString, sRight, sWrong, sStructuredAttrs, sJson,
|
||||
sAllowedReferences, sAllowedRequisites, sDisallowedReferences, sDisallowedRequisites, sMaxSize, sMaxClosureSize,
|
||||
sBuilder, sArgs, sContentAddressed, sImpure, sOutputHash, sOutputHashAlgo, sOutputHashMode,
|
||||
sRecurseForDerivations, sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, sPrefix,
|
||||
sOutputSpecified;
|
||||
|
||||
const Expr::AstSymbols exprSymbols;
|
||||
|
||||
/**
|
||||
* If set, force copying files to the Nix store even if they
|
||||
* already exist there.
|
||||
@@ -533,8 +610,28 @@ public:
|
||||
*/
|
||||
inline void forceValue(Value & v, const PosIdx pos);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Internal support function for forceValue
|
||||
*
|
||||
* This code is factored out so that it's not in the heavily inlined hot path.
|
||||
*/
|
||||
void handleEvalExceptionForThunk(Env * env, Expr * expr, Value & v, const PosIdx pos);
|
||||
|
||||
/**
|
||||
* Internal support function for forceValue
|
||||
*
|
||||
* This code is factored out so that it's not in the heavily inlined hot path.
|
||||
*/
|
||||
void handleEvalExceptionForApp(Value & v);
|
||||
|
||||
void handleEvalFailed(Value & v, PosIdx pos);
|
||||
|
||||
void tryFixupBlackHolePos(Value & v, PosIdx pos);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Force a value, then recursively force list elements and
|
||||
* attributes.
|
||||
@@ -802,7 +899,7 @@ public:
|
||||
|
||||
BindingsBuilder buildBindings(size_t capacity)
|
||||
{
|
||||
return BindingsBuilder(*this, allocBindings(capacity));
|
||||
return BindingsBuilder(*this, allocBindings(capacity), capacity);
|
||||
}
|
||||
|
||||
ListBuilder buildList(size_t size)
|
||||
|
||||
@@ -158,7 +158,7 @@ struct ExprString : Expr
|
||||
ExprString(std::string && s)
|
||||
: s(std::move(s))
|
||||
{
|
||||
v.mkString(this->s.data());
|
||||
v.mkStringNoCopy(this->s.data());
|
||||
};
|
||||
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
@@ -595,12 +595,17 @@ struct ExprOpNot : Expr
|
||||
{ \
|
||||
return pos; \
|
||||
} \
|
||||
};
|
||||
}
|
||||
|
||||
MakeBinOp(ExprOpEq, "==") MakeBinOp(ExprOpNEq, "!=") MakeBinOp(ExprOpAnd, "&&") MakeBinOp(ExprOpOr, "||")
|
||||
MakeBinOp(ExprOpImpl, "->") MakeBinOp(ExprOpUpdate, "//") MakeBinOp(ExprOpConcatLists, "++")
|
||||
MakeBinOp(ExprOpEq, "==");
|
||||
MakeBinOp(ExprOpNEq, "!=");
|
||||
MakeBinOp(ExprOpAnd, "&&");
|
||||
MakeBinOp(ExprOpOr, "||");
|
||||
MakeBinOp(ExprOpImpl, "->");
|
||||
MakeBinOp(ExprOpUpdate, "//");
|
||||
MakeBinOp(ExprOpConcatLists, "++");
|
||||
|
||||
struct ExprConcatStrings : Expr
|
||||
struct ExprConcatStrings : Expr
|
||||
{
|
||||
PosIdx pos;
|
||||
bool forceString;
|
||||
|
||||
@@ -88,7 +88,7 @@ struct ParserState
|
||||
SourcePath basePath;
|
||||
PosTable::Origin origin;
|
||||
const ref<SourceAccessor> rootFS;
|
||||
const Expr::AstSymbols & s;
|
||||
static constexpr Expr::AstSymbols s = StaticEvalSymbols::create().exprSymbols;
|
||||
const EvalSettings & settings;
|
||||
|
||||
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class StaticSymbolTable;
|
||||
|
||||
/**
|
||||
* Symbols have the property that they can be compared efficiently
|
||||
* (using an equality test), because the symbol table stores only one
|
||||
@@ -37,36 +39,38 @@ class Symbol
|
||||
{
|
||||
friend class SymbolStr;
|
||||
friend class SymbolTable;
|
||||
friend class StaticSymbolTable;
|
||||
|
||||
private:
|
||||
uint32_t id;
|
||||
|
||||
explicit Symbol(uint32_t id) noexcept
|
||||
explicit constexpr Symbol(uint32_t id) noexcept
|
||||
: id(id)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
Symbol() noexcept
|
||||
constexpr Symbol() noexcept
|
||||
: id(0)
|
||||
{
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
explicit operator bool() const noexcept
|
||||
constexpr explicit operator bool() const noexcept
|
||||
{
|
||||
return id > 0;
|
||||
}
|
||||
|
||||
auto operator<=>(const Symbol other) const noexcept
|
||||
/**
|
||||
* The ID is a private implementation detail that should generally not be observed. However, we expose here just for
|
||||
* sake of `switch...case`, which needs to dispatch on numbers. */
|
||||
[[gnu::always_inline]]
|
||||
constexpr uint32_t getId() const noexcept
|
||||
{
|
||||
return id <=> other.id;
|
||||
return id;
|
||||
}
|
||||
|
||||
bool operator==(const Symbol other) const noexcept
|
||||
{
|
||||
return id == other.id;
|
||||
}
|
||||
constexpr auto operator<=>(const Symbol & other) const noexcept = default;
|
||||
|
||||
friend class std::hash<Symbol>;
|
||||
};
|
||||
@@ -118,12 +122,12 @@ public:
|
||||
// for multi-threaded implementations: lock store and allocator here
|
||||
const auto & [v, idx] = key.store.add(SymbolValue{});
|
||||
if (size == 0) {
|
||||
v.mkString("", nullptr);
|
||||
v.mkStringNoCopy("", nullptr);
|
||||
} else {
|
||||
auto s = key.alloc.allocate(size + 1);
|
||||
memcpy(s, key.s.data(), size);
|
||||
s[size] = '\0';
|
||||
v.mkString(s, nullptr);
|
||||
v.mkStringNoCopy(s, nullptr);
|
||||
}
|
||||
v.size_ = size;
|
||||
v.idx = idx;
|
||||
@@ -210,6 +214,39 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
class SymbolTable;
|
||||
|
||||
/**
|
||||
* Convenience class to statically assign symbol identifiers at compile-time.
|
||||
*/
|
||||
class StaticSymbolTable
|
||||
{
|
||||
static constexpr std::size_t maxSize = 1024;
|
||||
|
||||
struct StaticSymbolInfo
|
||||
{
|
||||
std::string_view str;
|
||||
Symbol sym;
|
||||
};
|
||||
|
||||
std::array<StaticSymbolInfo, maxSize> symbols;
|
||||
std::size_t size = 0;
|
||||
|
||||
public:
|
||||
constexpr StaticSymbolTable() = default;
|
||||
|
||||
constexpr Symbol create(std::string_view str)
|
||||
{
|
||||
/* No need to check bounds because out of bounds access is
|
||||
a compilation error. */
|
||||
auto sym = Symbol(size + 1); //< +1 because Symbol with id = 0 is reserved
|
||||
symbols[size++] = {str, sym};
|
||||
return sym;
|
||||
}
|
||||
|
||||
void copyIntoSymbolTable(SymbolTable & symtab) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Symbol table used by the parser and evaluator to represent and look
|
||||
* up identifiers and attributes efficiently.
|
||||
@@ -232,6 +269,10 @@ private:
|
||||
boost::unordered_flat_set<SymbolStr, SymbolStr::Hash, SymbolStr::Equal> symbols{SymbolStr::chunkSize};
|
||||
|
||||
public:
|
||||
SymbolTable(const StaticSymbolTable & staticSymtab)
|
||||
{
|
||||
staticSymtab.copyIntoSymbolTable(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string into a symbol.
|
||||
@@ -276,6 +317,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline void StaticSymbolTable::copyIntoSymbolTable(SymbolTable & symtab) const
|
||||
{
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
auto [str, staticSym] = symbols[i];
|
||||
auto sym = symtab.create(str);
|
||||
if (sym != staticSym) [[unlikely]]
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
template<>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
///@file
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <concepts>
|
||||
@@ -35,6 +36,7 @@ typedef enum {
|
||||
tBool,
|
||||
tNull,
|
||||
tFloat,
|
||||
tFailed,
|
||||
tExternal,
|
||||
tPrimOp,
|
||||
tAttrs,
|
||||
@@ -57,6 +59,7 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
nThunk,
|
||||
nFailed,
|
||||
nInt,
|
||||
nFloat,
|
||||
nBool,
|
||||
@@ -265,6 +268,30 @@ struct ValueBase
|
||||
size_t size;
|
||||
Value * const * elems;
|
||||
};
|
||||
|
||||
/**
|
||||
Representation of an evaluation that previously failed.
|
||||
|
||||
`Value` references `Failed` by packed pointer, and its `new` is GC managed.
|
||||
|
||||
@see gc_cleanup std::exception_ptr
|
||||
*/
|
||||
class Failed : public gc_cleanup
|
||||
{
|
||||
public:
|
||||
std::exception_ptr ex;
|
||||
/**
|
||||
* Optional value for recovering `RecoverableEvalError`
|
||||
* Must be set iff `ex` is an instance of `RecoverableEvalError`.
|
||||
*/
|
||||
Value * recoveryValue;
|
||||
|
||||
Failed(std::exception_ptr ex, Value * recoveryValue)
|
||||
: ex(ex)
|
||||
, recoveryValue(recoveryValue)
|
||||
{
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -291,6 +318,7 @@ struct PayloadTypeToInternalType
|
||||
MACRO(PrimOp *, primOp, tPrimOp) \
|
||||
MACRO(ValueBase::PrimOpApplicationThunk, primOpApp, tPrimOpApp) \
|
||||
MACRO(ExternalValueBase *, external, tExternal) \
|
||||
MACRO(ValueBase::Failed *, failed, tFailed) \
|
||||
MACRO(NixFloat, fpoint, tFloat)
|
||||
|
||||
#define NIX_VALUE_PAYLOAD_TYPE(T, FIELD_NAME, DISCRIMINATOR) \
|
||||
@@ -369,7 +397,7 @@ namespace detail {
|
||||
/* Whether to use a specialization of ValueStorage that does bitpacking into
|
||||
alignment niches. */
|
||||
template<std::size_t ptrSize>
|
||||
inline constexpr bool useBitPackedValueStorage = (ptrSize == 8) && (__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 8);
|
||||
inline constexpr bool useBitPackedValueStorage = (ptrSize == 8) && (__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 16);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -378,7 +406,8 @@ inline constexpr bool useBitPackedValueStorage = (ptrSize == 8) && (__STDCPP_DEF
|
||||
* Packs discriminator bits into the pointer alignment niches.
|
||||
*/
|
||||
template<std::size_t ptrSize>
|
||||
class ValueStorage<ptrSize, std::enable_if_t<detail::useBitPackedValueStorage<ptrSize>>> : public detail::ValueBase
|
||||
class alignas(16) ValueStorage<ptrSize, std::enable_if_t<detail::useBitPackedValueStorage<ptrSize>>>
|
||||
: public detail::ValueBase
|
||||
{
|
||||
/* Needs a dependent type name in order for member functions (and
|
||||
* potentially ill-formed bit casts) to be SFINAE'd out.
|
||||
@@ -594,6 +623,11 @@ protected:
|
||||
path.path = std::bit_cast<const char *>(payload[1]);
|
||||
}
|
||||
|
||||
void getStorage(Failed *& failed) const noexcept
|
||||
{
|
||||
failed = std::bit_cast<Failed *>(payload[1]);
|
||||
}
|
||||
|
||||
void setStorage(NixInt integer) noexcept
|
||||
{
|
||||
setSingleDWordPayload<tInt>(integer.value);
|
||||
@@ -643,6 +677,11 @@ protected:
|
||||
{
|
||||
setUntaggablePayload<pdPath>(path.accessor, path.path);
|
||||
}
|
||||
|
||||
void setStorage(Failed * failed) noexcept
|
||||
{
|
||||
setSingleDWordPayload<tFailed>(std::bit_cast<PackedPointer>(failed));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -865,12 +904,12 @@ public:
|
||||
inline bool isThunk() const
|
||||
{
|
||||
return isa<tThunk>();
|
||||
};
|
||||
}
|
||||
|
||||
inline bool isApp() const
|
||||
{
|
||||
return isa<tApp>();
|
||||
};
|
||||
}
|
||||
|
||||
inline bool isBlackhole() const;
|
||||
|
||||
@@ -878,17 +917,22 @@ public:
|
||||
inline bool isLambda() const
|
||||
{
|
||||
return isa<tLambda>();
|
||||
};
|
||||
}
|
||||
|
||||
inline bool isPrimOp() const
|
||||
{
|
||||
return isa<tPrimOp>();
|
||||
};
|
||||
}
|
||||
|
||||
inline bool isPrimOpApp() const
|
||||
{
|
||||
return isa<tPrimOpApp>();
|
||||
};
|
||||
}
|
||||
|
||||
inline bool isFailed() const
|
||||
{
|
||||
return isa<tFailed>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normal type of a Value. This only returns nThunk if
|
||||
@@ -925,6 +969,8 @@ public:
|
||||
return nExternal;
|
||||
case tFloat:
|
||||
return nFloat;
|
||||
case tFailed:
|
||||
return nFailed;
|
||||
case tThunk:
|
||||
case tApp:
|
||||
return nThunk;
|
||||
@@ -960,7 +1006,7 @@ public:
|
||||
setStorage(b);
|
||||
}
|
||||
|
||||
inline void mkString(const char * s, const char ** context = 0) noexcept
|
||||
void mkStringNoCopy(const char * s, const char ** context = 0) noexcept
|
||||
{
|
||||
setStorage(StringWithContext{.c_str = s, .context = context});
|
||||
}
|
||||
@@ -972,7 +1018,6 @@ public:
|
||||
void mkStringMove(const char * s, const NixStringContext & context);
|
||||
|
||||
void mkPath(const SourcePath & path);
|
||||
void mkPath(std::string_view path);
|
||||
|
||||
inline void mkPath(SourceAccessor * accessor, const char * path) noexcept
|
||||
{
|
||||
@@ -993,12 +1038,20 @@ public:
|
||||
|
||||
void mkList(const ListBuilder & builder) noexcept
|
||||
{
|
||||
if (builder.size == 1)
|
||||
switch (builder.size) {
|
||||
case 0:
|
||||
setStorage(List{.size = 0, .elems = nullptr});
|
||||
break;
|
||||
case 1:
|
||||
setStorage(std::array<Value *, 2>{builder.inlineElems[0], nullptr});
|
||||
else if (builder.size == 2)
|
||||
break;
|
||||
case 2:
|
||||
setStorage(std::array<Value *, 2>{builder.inlineElems[0], builder.inlineElems[1]});
|
||||
else
|
||||
break;
|
||||
default:
|
||||
setStorage(List{.size = builder.size, .elems = builder.elems});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void mkThunk(Env * e, Expr * ex) noexcept
|
||||
@@ -1040,6 +1093,11 @@ public:
|
||||
setStorage(n);
|
||||
}
|
||||
|
||||
inline void mkFailed(std::exception_ptr e, Value * recovery) noexcept
|
||||
{
|
||||
setStorage(new Value::Failed(e, recovery));
|
||||
}
|
||||
|
||||
bool isList() const noexcept
|
||||
{
|
||||
return isa<tListSmall, tListN>();
|
||||
@@ -1143,6 +1201,11 @@ public:
|
||||
{
|
||||
return getStorage<Path>().accessor;
|
||||
}
|
||||
|
||||
Failed * failed() const noexcept
|
||||
{
|
||||
return getStorage<Failed *>();
|
||||
}
|
||||
};
|
||||
|
||||
extern ExprBlackHole eBlackHole;
|
||||
|
||||
@@ -3,7 +3,7 @@ project(
|
||||
'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
@@ -40,7 +40,10 @@ endforeach
|
||||
|
||||
boost = dependency(
|
||||
'boost',
|
||||
modules : [ 'container', 'context' ],
|
||||
modules : [
|
||||
'container',
|
||||
'context',
|
||||
],
|
||||
include_type : 'system',
|
||||
)
|
||||
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
|
||||
@@ -71,6 +74,12 @@ toml11 = dependency(
|
||||
method : 'cmake',
|
||||
include_type : 'system',
|
||||
)
|
||||
|
||||
configdata_priv.set(
|
||||
'HAVE_TOML11_4',
|
||||
toml11.version().version_compare('>= 4.0.0').to_int(),
|
||||
)
|
||||
|
||||
deps_other += toml11
|
||||
|
||||
config_priv_h = configure_file(
|
||||
|
||||
@@ -70,13 +70,15 @@ mkMesonLibrary (finalAttrs: {
|
||||
nix-util
|
||||
nix-store
|
||||
nix-fetchers
|
||||
] ++ finalAttrs.passthru.externalPropagatedBuildInputs;
|
||||
]
|
||||
++ finalAttrs.passthru.externalPropagatedBuildInputs;
|
||||
|
||||
# Hack for sake of the dev shell
|
||||
passthru.externalPropagatedBuildInputs = [
|
||||
boost
|
||||
nlohmann_json
|
||||
] ++ lib.optional enableGC boehmgc;
|
||||
]
|
||||
++ lib.optional enableGC boehmgc;
|
||||
|
||||
mesonFlags = [
|
||||
(lib.mesonEnable "gc" enableGC)
|
||||
|
||||
@@ -68,8 +68,7 @@ Expr * parseExprFromBuf(
|
||||
const EvalSettings & settings,
|
||||
PosTable & positions,
|
||||
DocCommentMap & docComments,
|
||||
const ref<SourceAccessor> rootFS,
|
||||
const Expr::AstSymbols & astSymbols);
|
||||
const ref<SourceAccessor> rootFS);
|
||||
|
||||
}
|
||||
|
||||
@@ -542,8 +541,7 @@ Expr * parseExprFromBuf(
|
||||
const EvalSettings & settings,
|
||||
PosTable & positions,
|
||||
DocCommentMap & docComments,
|
||||
const ref<SourceAccessor> rootFS,
|
||||
const Expr::AstSymbols & astSymbols)
|
||||
const ref<SourceAccessor> rootFS)
|
||||
{
|
||||
yyscan_t scanner;
|
||||
LexerState lexerState {
|
||||
@@ -558,7 +556,6 @@ Expr * parseExprFromBuf(
|
||||
.basePath = basePath,
|
||||
.origin = lexerState.origin,
|
||||
.rootFS = rootFS,
|
||||
.s = astSymbols,
|
||||
.settings = settings,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "nix/expr/eval-settings.hh"
|
||||
#include "nix/expr/gc-small-vector.hh"
|
||||
#include "nix/expr/json-to-value.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/names.hh"
|
||||
#include "nix/store/path-references.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
@@ -213,20 +214,20 @@ void derivationToValue(
|
||||
auto path2 = path.path.abs();
|
||||
Derivation drv = state.store->readDerivation(storePath);
|
||||
auto attrs = state.buildBindings(3 + drv.outputs.size());
|
||||
attrs.alloc(state.sDrvPath)
|
||||
attrs.alloc(state.s.drvPath)
|
||||
.mkString(
|
||||
path2,
|
||||
{
|
||||
NixStringContextElem::DrvDeep{.drvPath = storePath},
|
||||
});
|
||||
attrs.alloc(state.sName).mkString(drv.env["name"]);
|
||||
attrs.alloc(state.s.name).mkString(drv.env["name"]);
|
||||
|
||||
auto list = state.buildList(drv.outputs.size());
|
||||
for (const auto & [i, o] : enumerate(drv.outputs)) {
|
||||
mkOutputString(state, attrs, storePath, o);
|
||||
(list[i] = state.allocValue())->mkString(o.first);
|
||||
}
|
||||
attrs.alloc(state.sOutputs).mkList(list);
|
||||
attrs.alloc(state.s.outputs).mkList(list);
|
||||
|
||||
auto w = state.allocValue();
|
||||
w->mkAttrs(attrs);
|
||||
@@ -482,42 +483,41 @@ void prim_exec(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
static void prim_typeOf(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0], pos);
|
||||
std::string t;
|
||||
switch (args[0]->type()) {
|
||||
case nInt:
|
||||
t = "int";
|
||||
v.mkStringNoCopy("int");
|
||||
break;
|
||||
case nBool:
|
||||
t = "bool";
|
||||
v.mkStringNoCopy("bool");
|
||||
break;
|
||||
case nString:
|
||||
t = "string";
|
||||
v.mkStringNoCopy("string");
|
||||
break;
|
||||
case nPath:
|
||||
t = "path";
|
||||
v.mkStringNoCopy("path");
|
||||
break;
|
||||
case nNull:
|
||||
t = "null";
|
||||
v.mkStringNoCopy("null");
|
||||
break;
|
||||
case nAttrs:
|
||||
t = "set";
|
||||
v.mkStringNoCopy("set");
|
||||
break;
|
||||
case nList:
|
||||
t = "list";
|
||||
v.mkStringNoCopy("list");
|
||||
break;
|
||||
case nFunction:
|
||||
t = "lambda";
|
||||
v.mkStringNoCopy("lambda");
|
||||
break;
|
||||
case nExternal:
|
||||
t = args[0]->external()->typeOf();
|
||||
v.mkString(args[0]->external()->typeOf());
|
||||
break;
|
||||
case nFloat:
|
||||
t = "float";
|
||||
v.mkStringNoCopy("float");
|
||||
break;
|
||||
case nThunk:
|
||||
case nFailed:
|
||||
unreachable();
|
||||
}
|
||||
v.mkString(t);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_typeOf({
|
||||
@@ -730,7 +730,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value ** ar
|
||||
|
||||
/* Get the start set. */
|
||||
auto startSet = state.getAttr(
|
||||
state.sStartSet, args[0]->attrs(), "in the attrset passed as argument to builtins.genericClosure");
|
||||
state.s.startSet, args[0]->attrs(), "in the attrset passed as argument to builtins.genericClosure");
|
||||
|
||||
state.forceList(
|
||||
*startSet->value,
|
||||
@@ -748,7 +748,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value ** ar
|
||||
|
||||
/* Get the operator. */
|
||||
auto op = state.getAttr(
|
||||
state.sOperator, args[0]->attrs(), "in the attrset passed as argument to builtins.genericClosure");
|
||||
state.s.operator_, args[0]->attrs(), "in the attrset passed as argument to builtins.genericClosure");
|
||||
state.forceFunction(
|
||||
*op->value, noPos, "while evaluating the 'operator' attribute passed as argument to builtins.genericClosure");
|
||||
|
||||
@@ -770,7 +770,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value ** ar
|
||||
"while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure");
|
||||
|
||||
auto key = state.getAttr(
|
||||
state.sKey,
|
||||
state.s.key,
|
||||
e->attrs(),
|
||||
"in one of the attrsets generated by (or initially passed to) builtins.genericClosure");
|
||||
state.forceValue(*key->value, noPos);
|
||||
@@ -1075,11 +1075,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value ** args, Val
|
||||
|
||||
try {
|
||||
state.forceValue(*args[0], pos);
|
||||
attrs.insert(state.sValue, args[0]);
|
||||
attrs.insert(state.s.value, args[0]);
|
||||
attrs.insert(state.symbols.create("success"), &state.vTrue);
|
||||
} catch (AssertionError & e) {
|
||||
// `value = false;` is unfortunate but removing it is a breaking change.
|
||||
attrs.insert(state.sValue, &state.vFalse);
|
||||
attrs.insert(state.s.value, &state.vFalse);
|
||||
attrs.insert(state.symbols.create("success"), &state.vFalse);
|
||||
}
|
||||
|
||||
@@ -1291,7 +1291,8 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value **
|
||||
auto attrs = args[0]->attrs();
|
||||
|
||||
/* Figure out the name first (for stack backtraces). */
|
||||
auto nameAttr = state.getAttr(state.sName, attrs, "in the attrset passed as argument to builtins.derivationStrict");
|
||||
auto nameAttr =
|
||||
state.getAttr(state.s.name, attrs, "in the attrset passed as argument to builtins.derivationStrict");
|
||||
|
||||
std::string_view drvName;
|
||||
try {
|
||||
@@ -1365,7 +1366,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
using nlohmann::json;
|
||||
std::optional<StructuredAttrs> jsonObject;
|
||||
auto pos = v.determinePos(noPos);
|
||||
auto attr = attrs->find(state.sStructuredAttrs);
|
||||
auto attr = attrs->find(state.s.structuredAttrs);
|
||||
if (attr != attrs->end()
|
||||
&& state.forceBool(
|
||||
*attr->value,
|
||||
@@ -1376,7 +1377,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
|
||||
/* Check whether null attributes should be ignored. */
|
||||
bool ignoreNulls = false;
|
||||
attr = attrs->find(state.sIgnoreNulls);
|
||||
attr = attrs->find(state.s.ignoreNulls);
|
||||
if (attr != attrs->end())
|
||||
ignoreNulls = state.forceBool(
|
||||
*attr->value,
|
||||
@@ -1400,7 +1401,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
outputs.insert("out");
|
||||
|
||||
for (auto & i : attrs->lexicographicOrder(state.symbols)) {
|
||||
if (i->name == state.sIgnoreNulls)
|
||||
if (i->name == state.s.ignoreNulls)
|
||||
continue;
|
||||
auto key = state.symbols[i->name];
|
||||
vomit("processing attribute '%1%'", key);
|
||||
@@ -1452,19 +1453,22 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i->name == state.sContentAddressed && state.forceBool(*i->value, pos, context_below)) {
|
||||
contentAddressed = true;
|
||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||
}
|
||||
|
||||
else if (i->name == state.sImpure && state.forceBool(*i->value, pos, context_below)) {
|
||||
isImpure = true;
|
||||
experimentalFeatureSettings.require(Xp::ImpureDerivations);
|
||||
}
|
||||
|
||||
switch (i->name.getId()) {
|
||||
case EvalState::s.contentAddressed.getId():
|
||||
if (state.forceBool(*i->value, pos, context_below)) {
|
||||
contentAddressed = true;
|
||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||
}
|
||||
break;
|
||||
case EvalState::s.impure.getId():
|
||||
if (state.forceBool(*i->value, pos, context_below)) {
|
||||
isImpure = true;
|
||||
experimentalFeatureSettings.require(Xp::ImpureDerivations);
|
||||
}
|
||||
break;
|
||||
/* The `args' attribute is special: it supplies the
|
||||
command-line arguments to the builder. */
|
||||
else if (i->name == state.sArgs) {
|
||||
case EvalState::s.args.getId():
|
||||
state.forceList(*i->value, pos, context_below);
|
||||
for (auto elem : i->value->listView()) {
|
||||
auto s = state
|
||||
@@ -1473,86 +1477,116 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
.toOwned();
|
||||
drv.args.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
/* All other attributes are passed to the builder through
|
||||
the environment. */
|
||||
else {
|
||||
default:
|
||||
|
||||
if (jsonObject) {
|
||||
|
||||
if (i->name == state.sStructuredAttrs)
|
||||
if (i->name == state.s.structuredAttrs)
|
||||
continue;
|
||||
|
||||
jsonObject->structuredAttrs.emplace(key, printValueAsJSON(state, true, *i->value, pos, context));
|
||||
|
||||
if (i->name == state.sBuilder)
|
||||
switch (i->name.getId()) {
|
||||
case EvalState::s.builder.getId():
|
||||
drv.builder = state.forceString(*i->value, context, pos, context_below);
|
||||
else if (i->name == state.sSystem)
|
||||
break;
|
||||
case EvalState::s.system.getId():
|
||||
drv.platform = state.forceStringNoCtx(*i->value, pos, context_below);
|
||||
else if (i->name == state.sOutputHash)
|
||||
break;
|
||||
case EvalState::s.outputHash.getId():
|
||||
outputHash = state.forceStringNoCtx(*i->value, pos, context_below);
|
||||
else if (i->name == state.sOutputHashAlgo)
|
||||
break;
|
||||
case EvalState::s.outputHashAlgo.getId():
|
||||
outputHashAlgo = parseHashAlgoOpt(state.forceStringNoCtx(*i->value, pos, context_below));
|
||||
else if (i->name == state.sOutputHashMode)
|
||||
break;
|
||||
case EvalState::s.outputHashMode.getId():
|
||||
handleHashMode(state.forceStringNoCtx(*i->value, pos, context_below));
|
||||
else if (i->name == state.sOutputs) {
|
||||
/* Require ‘outputs’ to be a list of strings. */
|
||||
break;
|
||||
case EvalState::s.outputs.getId(): {
|
||||
/* Require 'outputs' to be a list of strings. */
|
||||
state.forceList(*i->value, pos, context_below);
|
||||
Strings ss;
|
||||
for (auto elem : i->value->listView())
|
||||
ss.emplace_back(state.forceStringNoCtx(*elem, pos, context_below));
|
||||
handleOutputs(ss);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (i->name == state.sAllowedReferences)
|
||||
switch (i->name.getId()) {
|
||||
case EvalState::s.allowedReferences.getId():
|
||||
warn(
|
||||
"In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'allowedReferences'; use 'outputChecks.<output>.allowedReferences' instead",
|
||||
drvName);
|
||||
if (i->name == state.sAllowedRequisites)
|
||||
break;
|
||||
case EvalState::s.allowedRequisites.getId():
|
||||
warn(
|
||||
"In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'allowedRequisites'; use 'outputChecks.<output>.allowedRequisites' instead",
|
||||
drvName);
|
||||
if (i->name == state.sDisallowedReferences)
|
||||
break;
|
||||
case EvalState::s.disallowedReferences.getId():
|
||||
warn(
|
||||
"In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedReferences'; use 'outputChecks.<output>.disallowedReferences' instead",
|
||||
drvName);
|
||||
if (i->name == state.sDisallowedRequisites)
|
||||
break;
|
||||
case EvalState::s.disallowedRequisites.getId():
|
||||
warn(
|
||||
"In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedRequisites'; use 'outputChecks.<output>.disallowedRequisites' instead",
|
||||
drvName);
|
||||
if (i->name == state.sMaxSize)
|
||||
break;
|
||||
case EvalState::s.maxSize.getId():
|
||||
warn(
|
||||
"In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'maxSize'; use 'outputChecks.<output>.maxSize' instead",
|
||||
drvName);
|
||||
if (i->name == state.sMaxClosureSize)
|
||||
break;
|
||||
case EvalState::s.maxClosureSize.getId():
|
||||
warn(
|
||||
"In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'maxClosureSize'; use 'outputChecks.<output>.maxClosureSize' instead",
|
||||
drvName);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
auto s = state.coerceToString(pos, *i->value, context, context_below, true).toOwned();
|
||||
if (i->name == state.sJson) {
|
||||
if (i->name == state.s.json) {
|
||||
warn(
|
||||
"In derivation '%s': setting structured attributes via '__json' is deprecated, and may be disallowed in future versions of Nix. Set '__structuredAttrs = true' instead.",
|
||||
drvName);
|
||||
drv.structuredAttrs = StructuredAttrs::parse(s);
|
||||
} else {
|
||||
drv.env.emplace(key, s);
|
||||
if (i->name == state.sBuilder)
|
||||
switch (i->name.getId()) {
|
||||
case EvalState::s.builder.getId():
|
||||
drv.builder = std::move(s);
|
||||
else if (i->name == state.sSystem)
|
||||
break;
|
||||
case EvalState::s.system.getId():
|
||||
drv.platform = std::move(s);
|
||||
else if (i->name == state.sOutputHash)
|
||||
break;
|
||||
case EvalState::s.outputHash.getId():
|
||||
outputHash = std::move(s);
|
||||
else if (i->name == state.sOutputHashAlgo)
|
||||
break;
|
||||
case EvalState::s.outputHashAlgo.getId():
|
||||
outputHashAlgo = parseHashAlgoOpt(s);
|
||||
else if (i->name == state.sOutputHashMode)
|
||||
break;
|
||||
case EvalState::s.outputHashMode.getId():
|
||||
handleHashMode(s);
|
||||
else if (i->name == state.sOutputs)
|
||||
break;
|
||||
case EvalState::s.outputs.getId():
|
||||
handleOutputs(tokenizeString<Strings>(s));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (Error & e) {
|
||||
@@ -1721,7 +1755,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
}
|
||||
|
||||
auto result = state.buildBindings(1 + drv.outputs.size());
|
||||
result.alloc(state.sDrvPath)
|
||||
result.alloc(state.s.drvPath)
|
||||
.mkString(
|
||||
drvPathS,
|
||||
{
|
||||
@@ -2005,14 +2039,14 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.findFile");
|
||||
|
||||
std::string prefix;
|
||||
auto i = v2->attrs()->find(state.sPrefix);
|
||||
auto i = v2->attrs()->find(state.s.prefix);
|
||||
if (i != v2->attrs()->end())
|
||||
prefix = state.forceStringNoCtx(
|
||||
*i->value,
|
||||
pos,
|
||||
"while evaluating the `prefix` attribute of an element of the list passed to builtins.findFile");
|
||||
|
||||
i = state.getAttr(state.sPath, v2->attrs(), "in an element of the __nixPath");
|
||||
i = state.getAttr(state.s.path, v2->attrs(), "in an element of the __nixPath");
|
||||
|
||||
NixStringContext context;
|
||||
auto path =
|
||||
@@ -2785,7 +2819,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value ** args, Value
|
||||
if (n == "path")
|
||||
path.emplace(state.coerceToPath(
|
||||
attr.pos, *attr.value, context, "while evaluating the 'path' attribute passed to 'builtins.path'"));
|
||||
else if (attr.name == state.sName)
|
||||
else if (attr.name == state.s.name)
|
||||
name = state.forceStringNoCtx(
|
||||
*attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.path");
|
||||
else if (n == "filter")
|
||||
@@ -3104,7 +3138,7 @@ static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value ** args,
|
||||
for (const auto & [n, v2] : enumerate(listView)) {
|
||||
state.forceAttrs(*v2, pos, "while evaluating an element of the list passed to builtins.listToAttrs");
|
||||
|
||||
auto j = state.getAttr(state.sName, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||
auto j = state.getAttr(state.s.name, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||
|
||||
auto name = state.forceStringNoCtx(
|
||||
*j->value,
|
||||
@@ -3131,7 +3165,7 @@ static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value ** args,
|
||||
// Note that .value is actually a Value * *; see earlier comments
|
||||
Value * v2 = *std::bit_cast<ElemPtr>(attr.value);
|
||||
|
||||
auto j = state.getAttr(state.sValue, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||
auto j = state.getAttr(state.s.value, v2->attrs(), "in a {name=...; value=...;} pair");
|
||||
prev = attr.name;
|
||||
bindings.push_back({prev, j->value, j->pos});
|
||||
}
|
||||
@@ -3947,13 +3981,13 @@ static void prim_partition(EvalState & state, const PosIdx pos, Value ** args, V
|
||||
auto rlist = state.buildList(rsize);
|
||||
if (rsize)
|
||||
memcpy(rlist.elems, right.data(), sizeof(Value *) * rsize);
|
||||
attrs.alloc(state.sRight).mkList(rlist);
|
||||
attrs.alloc(state.s.right).mkList(rlist);
|
||||
|
||||
auto wsize = wrong.size();
|
||||
auto wlist = state.buildList(wsize);
|
||||
if (wsize)
|
||||
memcpy(wlist.elems, wrong.data(), sizeof(Value *) * wsize);
|
||||
attrs.alloc(state.sWrong).mkList(wlist);
|
||||
attrs.alloc(state.s.wrong).mkList(wlist);
|
||||
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
@@ -4347,7 +4381,7 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value ** args, V
|
||||
if (len == 0) {
|
||||
state.forceValue(*args[2], pos);
|
||||
if (args[2]->type() == nString) {
|
||||
v.mkString("", args[2]->context());
|
||||
v.mkStringNoCopy("", args[2]->context());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4872,7 +4906,7 @@ static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value ** args
|
||||
state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.parseDrvName");
|
||||
DrvName parsed(name);
|
||||
auto attrs = state.buildBindings(2);
|
||||
attrs.alloc(state.sName).mkString(parsed.name);
|
||||
attrs.alloc(state.s.name).mkString(parsed.name);
|
||||
attrs.alloc("version").mkString(parsed.version);
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "nix/expr/eval-inline.hh"
|
||||
#include "nix/store/derivations.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -218,7 +219,7 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value ** args,
|
||||
auto list = state.buildList(info.second.outputs.size());
|
||||
for (const auto & [i, output] : enumerate(info.second.outputs))
|
||||
(list[i] = state.allocValue())->mkString(output);
|
||||
infoAttrs.alloc(state.sOutputs).mkList(list);
|
||||
infoAttrs.alloc(state.s.outputs).mkList(list);
|
||||
}
|
||||
attrs.alloc(state.store->printStorePath(info.first)).mkAttrs(infoAttrs);
|
||||
}
|
||||
@@ -299,7 +300,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value ** arg
|
||||
}
|
||||
}
|
||||
|
||||
if (auto attr = i.value->attrs()->get(state.sOutputs)) {
|
||||
if (auto attr = i.value->attrs()->get(state.s.outputs)) {
|
||||
state.forceList(*attr->value, attr->pos, "while evaluating the `outputs` attribute of a string context");
|
||||
if (attr->value->listSize() && !isDerivation(name)) {
|
||||
state
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "nix/store/realisation.hh"
|
||||
#include "nix/store/make-content-addressed.hh"
|
||||
#include "nix/util/url.hh"
|
||||
#include "nix/util/environment-variables.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -184,7 +185,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value ** args
|
||||
{.msg = HintFmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"),
|
||||
.pos = state.positions[pos]});
|
||||
|
||||
auto parsedURL = parseURL(*fromStoreUrl);
|
||||
auto parsedURL = parseURL(*fromStoreUrl, /*lenient=*/true);
|
||||
|
||||
if (parsedURL.scheme != "http" && parsedURL.scheme != "https"
|
||||
&& !(getEnv("_NIX_IN_TEST").has_value() && parsedURL.scheme == "file"))
|
||||
|
||||
@@ -84,7 +84,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value ** ar
|
||||
auto [storePath, input2] = input.fetchToStore(state.store);
|
||||
|
||||
auto attrs2 = state.buildBindings(8);
|
||||
state.mkStorePathString(storePath, attrs2.alloc(state.sOutPath));
|
||||
state.mkStorePathString(storePath, attrs2.alloc(state.s.outPath));
|
||||
if (input2.getRef())
|
||||
attrs2.alloc("branch").mkString(*input2.getRef());
|
||||
// Backward compatibility: set 'rev' to
|
||||
|
||||
@@ -29,7 +29,7 @@ void emitTreeAttrs(
|
||||
{
|
||||
auto attrs = state.buildBindings(100);
|
||||
|
||||
state.mkStorePathString(storePath, attrs.alloc(state.sOutPath));
|
||||
state.mkStorePathString(storePath, attrs.alloc(state.s.outPath));
|
||||
|
||||
// FIXME: support arbitrary input attributes.
|
||||
|
||||
@@ -95,7 +95,7 @@ static void fetchTree(
|
||||
|
||||
fetchers::Attrs attrs;
|
||||
|
||||
if (auto aType = args[0]->attrs()->get(state.sType)) {
|
||||
if (auto aType = args[0]->attrs()->get(state.s.type)) {
|
||||
if (type)
|
||||
state.error<EvalError>("unexpected argument 'type'").atPos(pos).debugThrow();
|
||||
type = state.forceStringNoCtx(
|
||||
@@ -106,14 +106,14 @@ static void fetchTree(
|
||||
attrs.emplace("type", type.value());
|
||||
|
||||
for (auto & attr : *args[0]->attrs()) {
|
||||
if (attr.name == state.sType)
|
||||
if (attr.name == state.s.type)
|
||||
continue;
|
||||
state.forceValue(*attr.value, attr.pos);
|
||||
if (attr.value->type() == nPath || attr.value->type() == nString) {
|
||||
auto s = state.coerceToString(attr.pos, *attr.value, context, "", false, false).toOwned();
|
||||
attrs.emplace(
|
||||
state.symbols[attr.name],
|
||||
params.isFetchGit && state.symbols[attr.name] == "url" ? fixGitURL(s) : s);
|
||||
params.isFetchGit && state.symbols[attr.name] == "url" ? fixGitURL(s).to_string() : s);
|
||||
} else if (attr.value->type() == nBool)
|
||||
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||
else if (attr.value->type() == nInt) {
|
||||
@@ -175,7 +175,7 @@ static void fetchTree(
|
||||
if (params.isFetchGit) {
|
||||
fetchers::Attrs attrs;
|
||||
attrs.emplace("type", "git");
|
||||
attrs.emplace("url", fixGitURL(url));
|
||||
attrs.emplace("url", fixGitURL(url).to_string());
|
||||
if (!attrs.contains("exportIgnore")
|
||||
&& (!attrs.contains("submodules") || !*fetchers::maybeGetBoolAttr(attrs, "submodules"))) {
|
||||
attrs.emplace("exportIgnore", Explicit<bool>{true});
|
||||
|
||||
@@ -1,75 +1,142 @@
|
||||
#include "nix/expr/primops.hh"
|
||||
#include "nix/expr/eval-inline.hh"
|
||||
|
||||
#include "expr-config-private.hh"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
#if HAVE_TOML11_4
|
||||
|
||||
/**
|
||||
* This is what toml11 < 4.0 did when choosing the subsecond precision.
|
||||
* TOML 1.0.0 spec doesn't define how sub-millisecond ranges should be handled and calls it
|
||||
* implementation defined behavior. For a lack of a better choice we stick with what older versions
|
||||
* of toml11 did [1].
|
||||
*
|
||||
* [1]: https://github.com/ToruNiina/toml11/blob/dcfe39a783a94e8d52c885e5883a6fbb21529019/toml/datetime.hpp#L282
|
||||
*/
|
||||
static size_t normalizeSubsecondPrecision(toml::local_time lt)
|
||||
{
|
||||
auto millis = lt.millisecond;
|
||||
auto micros = lt.microsecond;
|
||||
auto nanos = lt.nanosecond;
|
||||
if (millis != 0 || micros != 0 || nanos != 0) {
|
||||
if (micros != 0 || nanos != 0) {
|
||||
if (nanos != 0)
|
||||
return 9;
|
||||
return 6;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize date/time formats to serialize to the same strings as versions prior to toml11 4.0.
|
||||
*
|
||||
* Several things to consider:
|
||||
*
|
||||
* 1. Sub-millisecond range is represented the same way as in toml11 versions prior to 4.0. Precisioun is rounded
|
||||
* towards the next multiple of 3 or capped at 9 digits.
|
||||
* 2. Seconds must be specified. This may become optional in (yet unreleased) TOML 1.1.0, but 1.0.0 defined local time
|
||||
* in terms of RFC3339 [1].
|
||||
* 3. date-time separator (`t`, `T` or space ` `) is canonicalized to an upper T. This is compliant with RFC3339
|
||||
* [1] 5.6:
|
||||
* > Applications that generate this format SHOULD use upper case letters.
|
||||
*
|
||||
* [1]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
|
||||
*/
|
||||
static void normalizeDatetimeFormat(toml::value & t)
|
||||
{
|
||||
if (t.is_local_datetime()) {
|
||||
auto & ldt = t.as_local_datetime();
|
||||
t.as_local_datetime_fmt() = {
|
||||
.delimiter = toml::datetime_delimiter_kind::upper_T,
|
||||
// https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
|
||||
.has_seconds = true, // Mandated by TOML 1.0.0
|
||||
.subsecond_precision = normalizeSubsecondPrecision(ldt.time),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.is_offset_datetime()) {
|
||||
auto & odt = t.as_offset_datetime();
|
||||
t.as_offset_datetime_fmt() = {
|
||||
.delimiter = toml::datetime_delimiter_kind::upper_T,
|
||||
// https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
|
||||
.has_seconds = true, // Mandated by TOML 1.0.0
|
||||
.subsecond_precision = normalizeSubsecondPrecision(odt.time),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.is_local_time()) {
|
||||
auto & lt = t.as_local_time();
|
||||
t.as_local_time_fmt() = {
|
||||
.has_seconds = true, // Mandated by TOML 1.0.0
|
||||
.subsecond_precision = normalizeSubsecondPrecision(lt),
|
||||
};
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Value & val)
|
||||
{
|
||||
auto toml = state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.fromTOML");
|
||||
|
||||
std::istringstream tomlStream(std::string{toml});
|
||||
|
||||
std::function<void(Value &, toml::value)> visit;
|
||||
|
||||
visit = [&](Value & v, toml::value t) {
|
||||
auto visit = [&](auto & self, Value & v, toml::value t) -> void {
|
||||
switch (t.type()) {
|
||||
case toml::value_t::table: {
|
||||
auto table = toml::get<toml::table>(t);
|
||||
|
||||
size_t size = 0;
|
||||
for (auto & i : table) {
|
||||
(void) i;
|
||||
size++;
|
||||
}
|
||||
|
||||
auto attrs = state.buildBindings(size);
|
||||
auto attrs = state.buildBindings(table.size());
|
||||
|
||||
for (auto & elem : table) {
|
||||
forceNoNullByte(elem.first);
|
||||
visit(attrs.alloc(elem.first), elem.second);
|
||||
self(self, attrs.alloc(elem.first), elem.second);
|
||||
}
|
||||
|
||||
v.mkAttrs(attrs);
|
||||
} break;
|
||||
;
|
||||
case toml::value_t::array: {
|
||||
auto array = toml::get<std::vector<toml::value>>(t);
|
||||
|
||||
auto list = state.buildList(array.size());
|
||||
for (const auto & [n, v] : enumerate(list))
|
||||
visit(*(v = state.allocValue()), array[n]);
|
||||
self(self, *(v = state.allocValue()), array[n]);
|
||||
v.mkList(list);
|
||||
} break;
|
||||
;
|
||||
case toml::value_t::boolean:
|
||||
v.mkBool(toml::get<bool>(t));
|
||||
break;
|
||||
;
|
||||
case toml::value_t::integer:
|
||||
v.mkInt(toml::get<int64_t>(t));
|
||||
break;
|
||||
;
|
||||
case toml::value_t::floating:
|
||||
v.mkFloat(toml::get<NixFloat>(t));
|
||||
break;
|
||||
;
|
||||
case toml::value_t::string: {
|
||||
auto s = toml::get<std::string_view>(t);
|
||||
forceNoNullByte(s);
|
||||
v.mkString(s);
|
||||
} break;
|
||||
;
|
||||
case toml::value_t::local_datetime:
|
||||
case toml::value_t::offset_datetime:
|
||||
case toml::value_t::local_date:
|
||||
case toml::value_t::local_time: {
|
||||
if (experimentalFeatureSettings.isEnabled(Xp::ParseTomlTimestamps)) {
|
||||
#if HAVE_TOML11_4
|
||||
normalizeDatetimeFormat(t);
|
||||
#endif
|
||||
auto attrs = state.buildBindings(2);
|
||||
attrs.alloc("_type").mkString("timestamp");
|
||||
attrs.alloc("_type").mkStringNoCopy("timestamp");
|
||||
std::ostringstream s;
|
||||
s << t;
|
||||
auto str = toView(s);
|
||||
@@ -80,16 +147,24 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
throw std::runtime_error("Dates and times are not supported");
|
||||
}
|
||||
} break;
|
||||
;
|
||||
case toml::value_t::empty:
|
||||
v.mkNull();
|
||||
break;
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */));
|
||||
visit(
|
||||
visit,
|
||||
val,
|
||||
toml::parse(
|
||||
tomlStream,
|
||||
"fromTOML" /* the "filename" */
|
||||
#if HAVE_TOML11_4
|
||||
,
|
||||
toml::spec::v(1, 0, 0) // Be explicit that we are parsing TOML 1.0.0 without extensions
|
||||
#endif
|
||||
));
|
||||
} catch (std::exception & e) { // TODO: toml::syntax_error
|
||||
state.error<EvalError>("while parsing TOML: %s", e.what()).atPos(pos).debugThrow();
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ void printAmbiguous(
|
||||
str << "«potential infinite recursion»";
|
||||
}
|
||||
break;
|
||||
case nFailed:
|
||||
str << "«failed»";
|
||||
break;
|
||||
case nFunction:
|
||||
if (v.isLambda()) {
|
||||
str << "<LAMBDA>";
|
||||
|
||||
@@ -272,7 +272,7 @@ private:
|
||||
void printDerivation(Value & v)
|
||||
{
|
||||
std::optional<StorePath> storePath;
|
||||
if (auto i = v.attrs()->get(state.sDrvPath)) {
|
||||
if (auto i = v.attrs()->get(state.s.drvPath)) {
|
||||
NixStringContext context;
|
||||
storePath =
|
||||
state.coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation");
|
||||
@@ -508,6 +508,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void printFailed(Value & v)
|
||||
{
|
||||
output << "«failed»";
|
||||
}
|
||||
|
||||
void printExternal(Value & v)
|
||||
{
|
||||
v.external()->print(output);
|
||||
@@ -583,6 +588,10 @@ private:
|
||||
printThunk(v);
|
||||
break;
|
||||
|
||||
case nFailed:
|
||||
printFailed(v);
|
||||
break;
|
||||
|
||||
case nExternal:
|
||||
printExternal(v);
|
||||
break;
|
||||
|
||||
@@ -53,7 +53,7 @@ json printValueAsJSON(
|
||||
out = *maybeString;
|
||||
break;
|
||||
}
|
||||
if (auto i = v.attrs()->get(state.sOutPath))
|
||||
if (auto i = v.attrs()->get(state.s.outPath))
|
||||
return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
|
||||
else {
|
||||
out = json::object();
|
||||
@@ -96,6 +96,7 @@ json printValueAsJSON(
|
||||
break;
|
||||
|
||||
case nThunk:
|
||||
case nFailed:
|
||||
case nFunction:
|
||||
state.error<TypeError>("cannot convert %1% to JSON", showType(v)).atPos(v.determinePos(pos)).debugThrow();
|
||||
}
|
||||
|
||||
@@ -98,14 +98,14 @@ static void printValueAsXML(
|
||||
XMLAttrs xmlAttrs;
|
||||
|
||||
Path drvPath;
|
||||
if (auto a = v.attrs()->get(state.sDrvPath)) {
|
||||
if (auto a = v.attrs()->get(state.s.drvPath)) {
|
||||
if (strict)
|
||||
state.forceValue(*a->value, a->pos);
|
||||
if (a->value->type() == nString)
|
||||
xmlAttrs["drvPath"] = drvPath = a->value->c_str();
|
||||
}
|
||||
|
||||
if (auto a = v.attrs()->get(state.sOutPath)) {
|
||||
if (auto a = v.attrs()->get(state.s.outPath)) {
|
||||
if (strict)
|
||||
state.forceValue(*a->value, a->pos);
|
||||
if (a->value->type() == nString)
|
||||
@@ -170,6 +170,11 @@ static void printValueAsXML(
|
||||
|
||||
case nThunk:
|
||||
doc.writeEmptyElement("unevaluated");
|
||||
break;
|
||||
|
||||
case nFailed:
|
||||
doc.writeEmptyElement("failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ project(
|
||||
'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "nix_api_fetchers_internal.hh"
|
||||
#include "nix_api_util_internal.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context)
|
||||
{
|
||||
try {
|
||||
@@ -17,3 +19,5 @@ void nix_fetchers_settings_free(nix_fetchers_settings * settings)
|
||||
{
|
||||
delete settings;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -173,4 +173,58 @@ TEST_F(GitUtilsTest, peel_reference)
|
||||
git_repository_free(rawRepo);
|
||||
}
|
||||
|
||||
TEST(GitUtils, isLegalRefName)
|
||||
{
|
||||
ASSERT_TRUE(isLegalRefName("foox"));
|
||||
ASSERT_TRUE(isLegalRefName("1337"));
|
||||
ASSERT_TRUE(isLegalRefName("foo.baz"));
|
||||
ASSERT_TRUE(isLegalRefName("foo/bar/baz"));
|
||||
ASSERT_TRUE(isLegalRefName("foo./bar"));
|
||||
ASSERT_TRUE(isLegalRefName("heads/foo@bar"));
|
||||
ASSERT_TRUE(isLegalRefName("heads/fu\303\237"));
|
||||
ASSERT_TRUE(isLegalRefName("foo-bar-baz"));
|
||||
ASSERT_TRUE(isLegalRefName("branch#"));
|
||||
ASSERT_TRUE(isLegalRefName("$1"));
|
||||
ASSERT_TRUE(isLegalRefName("foo.locke"));
|
||||
|
||||
ASSERT_FALSE(isLegalRefName("refs///heads/foo"));
|
||||
ASSERT_FALSE(isLegalRefName("heads/foo/"));
|
||||
ASSERT_FALSE(isLegalRefName("///heads/foo"));
|
||||
ASSERT_FALSE(isLegalRefName(".foo"));
|
||||
ASSERT_FALSE(isLegalRefName("./foo"));
|
||||
ASSERT_FALSE(isLegalRefName("./foo/bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo/./bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo/bar/."));
|
||||
ASSERT_FALSE(isLegalRefName("foo bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo?bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo^bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo~bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo:bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo[bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo/bar/."));
|
||||
ASSERT_FALSE(isLegalRefName(".refs/foo"));
|
||||
ASSERT_FALSE(isLegalRefName("refs/heads/foo."));
|
||||
ASSERT_FALSE(isLegalRefName("heads/foo..bar"));
|
||||
ASSERT_FALSE(isLegalRefName("heads/foo?bar"));
|
||||
ASSERT_FALSE(isLegalRefName("heads/foo.lock"));
|
||||
ASSERT_FALSE(isLegalRefName("heads///foo.lock"));
|
||||
ASSERT_FALSE(isLegalRefName("foo.lock/bar"));
|
||||
ASSERT_FALSE(isLegalRefName("foo.lock///bar"));
|
||||
ASSERT_FALSE(isLegalRefName("heads/v@{ation"));
|
||||
ASSERT_FALSE(isLegalRefName("heads/foo\bar"));
|
||||
|
||||
ASSERT_FALSE(isLegalRefName("@"));
|
||||
ASSERT_FALSE(isLegalRefName("\37"));
|
||||
ASSERT_FALSE(isLegalRefName("\177"));
|
||||
|
||||
ASSERT_FALSE(isLegalRefName("foo/*"));
|
||||
ASSERT_FALSE(isLegalRefName("*/foo"));
|
||||
ASSERT_FALSE(isLegalRefName("foo/*/bar"));
|
||||
ASSERT_FALSE(isLegalRefName("*"));
|
||||
ASSERT_FALSE(isLegalRefName("foo/*/*"));
|
||||
ASSERT_FALSE(isLegalRefName("*/foo/*"));
|
||||
ASSERT_FALSE(isLegalRefName("/foo"));
|
||||
ASSERT_FALSE(isLegalRefName(""));
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
200
src/libfetchers-tests/git.cc
Normal file
200
src/libfetchers-tests/git.cc
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "nix/store/store-open.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/fetchers/fetch-settings.hh"
|
||||
#include "nix/fetchers/fetchers.hh"
|
||||
#include "nix/fetchers/git-utils.hh"
|
||||
|
||||
#include <git2.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace {
|
||||
|
||||
template<class T, void (*F)(T *)>
|
||||
struct Deleter
|
||||
{
|
||||
void operator()(T * p) const
|
||||
{
|
||||
if (p)
|
||||
F(p);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, void (*F)(T *)>
|
||||
using Handle = std::unique_ptr<T, Deleter<T, F>>;
|
||||
|
||||
using RepoHandle = Handle<git_repository, git_repository_free>;
|
||||
using IndexHandle = Handle<git_index, git_index_free>;
|
||||
using TreeHandle = Handle<git_tree, git_tree_free>;
|
||||
using SigHandle = Handle<git_signature, git_signature_free>;
|
||||
using RefHandle = Handle<git_reference, git_reference_free>;
|
||||
using CommitHandle = Handle<git_commit, git_commit_free>;
|
||||
using SubmoduleHandle = Handle<git_submodule, git_submodule_free>;
|
||||
|
||||
#define CHECK_LIBGIT(expr) ASSERT_TRUE((expr) >= 0) << git_error_last()
|
||||
|
||||
static void commitAll(git_repository * repo, const char * msg)
|
||||
{
|
||||
IndexHandle idx;
|
||||
{
|
||||
git_index * raw = nullptr;
|
||||
CHECK_LIBGIT(git_repository_index(&raw, repo));
|
||||
idx.reset(raw);
|
||||
}
|
||||
CHECK_LIBGIT(git_index_add_all(idx.get(), nullptr, 0, nullptr, nullptr));
|
||||
CHECK_LIBGIT(git_index_write(idx.get()));
|
||||
|
||||
git_oid treeId{};
|
||||
CHECK_LIBGIT(git_index_write_tree(&treeId, idx.get()));
|
||||
TreeHandle tree;
|
||||
{
|
||||
git_tree * raw = nullptr;
|
||||
CHECK_LIBGIT(git_tree_lookup(&raw, repo, &treeId));
|
||||
tree.reset(raw);
|
||||
}
|
||||
|
||||
SigHandle sig;
|
||||
{
|
||||
git_signature * raw = nullptr;
|
||||
CHECK_LIBGIT(git_signature_now(&raw, "you", "you@example.com"));
|
||||
sig.reset(raw);
|
||||
}
|
||||
|
||||
git_oid commitId{};
|
||||
if (git_repository_is_empty(repo) == 1) {
|
||||
CHECK_LIBGIT(git_commit_create_v(&commitId, repo, "HEAD", sig.get(), sig.get(), nullptr, msg, tree.get(), 0));
|
||||
CHECK_LIBGIT(git_reference_create(nullptr, repo, "refs/heads/main", &commitId, true, nullptr));
|
||||
CHECK_LIBGIT(git_repository_set_head(repo, "refs/heads/main"));
|
||||
} else {
|
||||
RefHandle head;
|
||||
{
|
||||
git_reference * raw = nullptr;
|
||||
CHECK_LIBGIT(git_repository_head(&raw, repo));
|
||||
head.reset(raw);
|
||||
}
|
||||
CommitHandle parent;
|
||||
{
|
||||
git_commit * raw = nullptr;
|
||||
CHECK_LIBGIT(git_commit_lookup(&raw, repo, git_reference_target(head.get())));
|
||||
parent.reset(raw);
|
||||
}
|
||||
const git_commit * parents[] = {parent.get()};
|
||||
CHECK_LIBGIT(git_commit_create(
|
||||
&commitId,
|
||||
repo,
|
||||
"HEAD",
|
||||
sig.get(),
|
||||
sig.get(),
|
||||
/*message_encoding=*/nullptr,
|
||||
msg,
|
||||
tree.get(),
|
||||
/*parent_count=*/1,
|
||||
&parents[0]));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace nix;
|
||||
|
||||
class GitTest : public ::testing::Test
|
||||
{
|
||||
std::unique_ptr<AutoDelete> delTmpDir;
|
||||
|
||||
protected:
|
||||
std::filesystem::path tmpDir;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
tmpDir = createTempDir();
|
||||
delTmpDir = std::make_unique<AutoDelete>(tmpDir, /*recursive=*/true);
|
||||
nix::initLibStore(/*loadConfig=*/false);
|
||||
git_libgit2_init();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
delTmpDir.reset();
|
||||
}
|
||||
};
|
||||
|
||||
// Regression test for https://github.com/NixOS/nix/issues/13215
|
||||
TEST_F(GitTest, submodulePeriodSupport)
|
||||
{
|
||||
auto storePath = tmpDir / "store";
|
||||
auto repoPath = tmpDir / "repo";
|
||||
auto submodulePath = tmpDir / "submodule";
|
||||
|
||||
// Set up our git directories: one top level and a submodule
|
||||
// the submodule in the .gitmodules has the branch listed as '.'
|
||||
|
||||
// 1) Create sub repo
|
||||
{
|
||||
git_repository * raw = nullptr;
|
||||
CHECK_LIBGIT(git_repository_init(&raw, submodulePath.string().c_str(), /*is_bare=*/0));
|
||||
RepoHandle sub(raw);
|
||||
writeFile(submodulePath / "lib.txt", "hello from submodule\n");
|
||||
commitAll(sub.get(), "init sub");
|
||||
}
|
||||
|
||||
// 2) Create super repo
|
||||
RepoHandle super;
|
||||
{
|
||||
git_repository * raw = nullptr;
|
||||
CHECK_LIBGIT(git_repository_init(&raw, repoPath.string().c_str(), /*is_bare=*/0));
|
||||
super.reset(raw);
|
||||
}
|
||||
|
||||
writeFile(repoPath / "README.md", "# super\n");
|
||||
commitAll(super.get(), "init super");
|
||||
|
||||
// 3) Add submodule at deps/sub
|
||||
{
|
||||
git_repository * raw = nullptr;
|
||||
git_clone_options cloneOpts = GIT_CLONE_OPTIONS_INIT;
|
||||
// clone from local subPath into superPath/deps/sub
|
||||
CHECK_LIBGIT(
|
||||
git_clone(&raw, submodulePath.string().c_str(), (repoPath / "deps" / "sub").string().c_str(), &cloneOpts));
|
||||
RepoHandle sub(raw);
|
||||
}
|
||||
|
||||
// 4) Add submodule and set branch="."
|
||||
SubmoduleHandle sm;
|
||||
{
|
||||
git_submodule * raw = nullptr;
|
||||
CHECK_LIBGIT(git_submodule_add_setup(
|
||||
&raw,
|
||||
super.get(),
|
||||
"../submodule",
|
||||
"deps/sub",
|
||||
/*use_gitlink=*/1));
|
||||
sm.reset(raw);
|
||||
}
|
||||
CHECK_LIBGIT(git_submodule_set_branch(super.get(), git_submodule_name(sm.get()), /*branch=*/"."));
|
||||
CHECK_LIBGIT(git_submodule_sync(sm.get()));
|
||||
|
||||
// 5) Finalize now that the worktree exists; libgit2 can read its HEAD OID
|
||||
CHECK_LIBGIT(git_submodule_add_finalize(sm.get()));
|
||||
// 6) Commit the addition in super
|
||||
commitAll(super.get(), "Add submodule with branch='.'");
|
||||
|
||||
// TODO: Use dummy:// store with MemorySourceAccessor.
|
||||
Path storeTmpDir = createTempDir();
|
||||
auto storeTmpDirAutoDelete = AutoDelete(storeTmpDir, true);
|
||||
ref<Store> store = openStore(storeTmpDir);
|
||||
|
||||
auto settings = fetchers::Settings{};
|
||||
auto input = fetchers::Input::fromAttrs(
|
||||
settings,
|
||||
{
|
||||
{"url", "file://" + repoPath.string()},
|
||||
{"submodules", Explicit{true}},
|
||||
{"type", "git"},
|
||||
{"ref", "main"},
|
||||
});
|
||||
|
||||
auto [accessor, i] = input.getAccessor(store);
|
||||
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("deps/sub/lib.txt")), "hello from submodule\n");
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user