mirror of
https://github.com/NixOS/nix
synced 2025-06-25 10:41:16 +02:00
Merge remote-tracking branch 'origin/master' into relative-flakes
This commit is contained in:
commit
cd0127f957
112 changed files with 2268 additions and 434 deletions
38
.github/workflows/ci.yml
vendored
38
.github/workflows/ci.yml
vendored
|
@ -8,7 +8,7 @@ permissions: read-all
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
eval:
|
eval:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
@ -20,8 +20,15 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
include:
|
||||||
runs-on: ${{ matrix.os }}
|
- scenario: on ubuntu
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
os: linux
|
||||||
|
- scenario: on macos
|
||||||
|
runs-on: macos-14
|
||||||
|
os: darwin
|
||||||
|
name: tests ${{ matrix.scenario }}
|
||||||
|
runs-on: ${{ matrix.runs-on }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -37,7 +44,7 @@ jobs:
|
||||||
# Since ubuntu 22.30, unprivileged usernamespaces are no longer allowed to map to the root user:
|
# 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
|
# https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
|
||||||
- run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
- run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'linux'
|
||||||
- run: scripts/build-checks
|
- run: scripts/build-checks
|
||||||
- run: scripts/prepare-installer-for-github-actions
|
- run: scripts/prepare-installer-for-github-actions
|
||||||
- name: Upload installer tarball
|
- name: Upload installer tarball
|
||||||
|
@ -51,8 +58,15 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
include:
|
||||||
runs-on: ${{ matrix.os }}
|
- scenario: on ubuntu
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
os: linux
|
||||||
|
- scenario: on macos
|
||||||
|
runs-on: macos-14
|
||||||
|
os: darwin
|
||||||
|
name: installer test ${{ matrix.scenario }}
|
||||||
|
runs-on: ${{ matrix.runs-on }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Download installer tarball
|
- name: Download installer tarball
|
||||||
|
@ -68,9 +82,9 @@ jobs:
|
||||||
install_url: 'http://localhost:8126/install'
|
install_url: 'http://localhost:8126/install'
|
||||||
install_options: "--tarball-url-prefix http://localhost:8126/"
|
install_options: "--tarball-url-prefix http://localhost:8126/"
|
||||||
- run: sudo apt install fish zsh
|
- run: sudo apt install fish zsh
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'linux'
|
||||||
- run: brew install fish
|
- run: brew install fish
|
||||||
if: matrix.os == 'macos-latest'
|
if: matrix.os == 'darwin'
|
||||||
- run: exec bash -c "nix-instantiate -E 'builtins.currentTime' --eval"
|
- run: exec bash -c "nix-instantiate -E 'builtins.currentTime' --eval"
|
||||||
- run: exec sh -c "nix-instantiate -E 'builtins.currentTime' --eval"
|
- run: exec sh -c "nix-instantiate -E 'builtins.currentTime' --eval"
|
||||||
- run: exec zsh -c "nix-instantiate -E 'builtins.currentTime' --eval"
|
- run: exec zsh -c "nix-instantiate -E 'builtins.currentTime' --eval"
|
||||||
|
@ -86,7 +100,7 @@ jobs:
|
||||||
permissions:
|
permissions:
|
||||||
contents: none
|
contents: none
|
||||||
name: Check Docker secrets present for installer tests
|
name: Check Docker secrets present for installer tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
outputs:
|
outputs:
|
||||||
docker: ${{ steps.secret.outputs.docker }}
|
docker: ${{ steps.secret.outputs.docker }}
|
||||||
steps:
|
steps:
|
||||||
|
@ -106,7 +120,7 @@ jobs:
|
||||||
needs.check_secrets.outputs.docker == 'true' &&
|
needs.check_secrets.outputs.docker == 'true' &&
|
||||||
github.event_name == 'push' &&
|
github.event_name == 'push' &&
|
||||||
github.ref_name == 'master'
|
github.ref_name == 'master'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Check for secrets
|
- name: Check for secrets
|
||||||
id: secret
|
id: secret
|
||||||
|
@ -158,7 +172,7 @@ jobs:
|
||||||
docker push $IMAGE_ID:master
|
docker push $IMAGE_ID:master
|
||||||
|
|
||||||
vm_tests:
|
vm_tests:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: DeterminateSystems/nix-installer-action@main
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
@ -173,7 +187,7 @@ jobs:
|
||||||
|
|
||||||
flake_regressions:
|
flake_regressions:
|
||||||
needs: vm_tests
|
needs: vm_tests
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout nix
|
- name: Checkout nix
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
2
.github/workflows/labels.yml
vendored
2
.github/workflows/labels.yml
vendored
|
@ -15,7 +15,7 @@ permissions:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labels:
|
labels:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
if: github.repository_owner == 'NixOS'
|
if: github.repository_owner == 'NixOS'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@v5
|
- uses: actions/labeler@v5
|
||||||
|
|
|
@ -2,10 +2,10 @@ queue_rules:
|
||||||
- name: default
|
- name: default
|
||||||
# all required tests need to go here
|
# all required tests need to go here
|
||||||
merge_conditions:
|
merge_conditions:
|
||||||
- check-success=tests (macos-latest)
|
- check-success=tests on macos
|
||||||
- check-success=tests (ubuntu-latest)
|
- check-success=tests on ubuntu
|
||||||
- check-success=installer_test (macos-latest)
|
- check-success=installer test on macos
|
||||||
- check-success=installer_test (ubuntu-latest)
|
- check-success=installer test on ubuntu
|
||||||
- check-success=vm_tests
|
- check-success=vm_tests
|
||||||
batch_size: 5
|
batch_size: 5
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
, meson
|
, meson
|
||||||
, ninja
|
, ninja
|
||||||
, lowdown
|
, lowdown-unsandboxed
|
||||||
, mdbook
|
, mdbook
|
||||||
, mdbook-linkcheck
|
, mdbook-linkcheck
|
||||||
, jq
|
, jq
|
||||||
|
@ -42,7 +42,7 @@ mkMesonDerivation (finalAttrs: {
|
||||||
passthru.externalNativeBuildInputs = [
|
passthru.externalNativeBuildInputs = [
|
||||||
meson
|
meson
|
||||||
ninja
|
ninja
|
||||||
(lib.getBin lowdown)
|
(lib.getBin lowdown-unsandboxed)
|
||||||
mdbook
|
mdbook
|
||||||
mdbook-linkcheck
|
mdbook-linkcheck
|
||||||
jq
|
jq
|
||||||
|
|
8
doc/manual/rl-next/nix-instantiate-raw.md
Normal file
8
doc/manual/rl-next/nix-instantiate-raw.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
synopsis: "`nix-instantiate --eval` now supports `--raw`"
|
||||||
|
prs: [12119]
|
||||||
|
---
|
||||||
|
|
||||||
|
The `nix-instantiate --eval` command now supports a `--raw` flag, when used
|
||||||
|
the evaluation result must be a string, which is printed verbatim without
|
||||||
|
quotation marks or escaping.
|
|
@ -62,6 +62,15 @@ These options are for deleting old [profiles] prior to deleting unreachable [sto
|
||||||
This is the equivalent of invoking [`nix-env --delete-generations <period>`](@docroot@/command-ref/nix-env/delete-generations.md#generations-time) on each found profile.
|
This is the equivalent of invoking [`nix-env --delete-generations <period>`](@docroot@/command-ref/nix-env/delete-generations.md#generations-time) on each found profile.
|
||||||
See the documentation of that command for additional information about the *period* argument.
|
See the documentation of that command for additional information about the *period* argument.
|
||||||
|
|
||||||
|
- <span id="opt-max-freed">[`--max-freed`](#opt-max-freed)</span> *bytes*
|
||||||
|
|
||||||
|
<!-- duplication from https://github.com/NixOS/nix/blob/442a2623e48357ff72c77bb11cf2cf06d94d2f90/doc/manual/source/command-ref/nix-store/gc.md?plain=1#L39-L44 -->
|
||||||
|
|
||||||
|
Keep deleting paths until at least *bytes* bytes have been deleted,
|
||||||
|
then stop. The argument *bytes* can be followed by the
|
||||||
|
multiplicative suffix `K`, `M`, `G` or `T`, denoting KiB, MiB, GiB
|
||||||
|
or TiB units.
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
{{#include ./env-common.md}}
|
{{#include ./env-common.md}}
|
||||||
|
|
|
@ -84,7 +84,7 @@ When using public key authentication, you can avoid typing the passphrase with `
|
||||||
> Copy GNU Hello from a remote machine using a known store path, and run it:
|
> Copy GNU Hello from a remote machine using a known store path, and run it:
|
||||||
>
|
>
|
||||||
> ```shell-session
|
> ```shell-session
|
||||||
> $ storePath="$(nix-instantiate --eval '<nixpkgs>' -I nixpkgs=channel:nixpkgs-unstable -A hello.outPath | tr -d '"')"
|
> $ storePath="$(nix-instantiate --eval --raw '<nixpkgs>' -I nixpkgs=channel:nixpkgs-unstable -A hello.outPath)"
|
||||||
> $ nix-copy-closure --from alice@itchy.example.org "$storePath"
|
> $ nix-copy-closure --from alice@itchy.example.org "$storePath"
|
||||||
> $ "$storePath"/bin/hello
|
> $ "$storePath"/bin/hello
|
||||||
> Hello, world!
|
> Hello, world!
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
# Synopsis
|
# Synopsis
|
||||||
|
|
||||||
`nix-instantiate`
|
`nix-instantiate`
|
||||||
[`--parse` | `--eval` [`--strict`] [`--json`] [`--xml`] ]
|
[`--parse` | `--eval` [`--strict`] [`--raw` | `--json` | `--xml`] ]
|
||||||
[`--read-write-mode`]
|
[`--read-write-mode`]
|
||||||
[`--arg` *name* *value*]
|
[`--arg` *name* *value*]
|
||||||
[{`--attr`| `-A`} *attrPath*]
|
[{`--attr`| `-A`} *attrPath*]
|
||||||
|
@ -102,6 +102,11 @@ standard input.
|
||||||
> This option can cause non-termination, because lazy data
|
> This option can cause non-termination, because lazy data
|
||||||
> structures can be infinitely large.
|
> structures can be infinitely large.
|
||||||
|
|
||||||
|
- `--raw`
|
||||||
|
|
||||||
|
When used with `--eval`, the evaluation result must be a string,
|
||||||
|
which is printed verbatim, without quoting, escaping or trailing newline.
|
||||||
|
|
||||||
- `--json`
|
- `--json`
|
||||||
|
|
||||||
When used with `--eval`, print the resulting value as an JSON
|
When used with `--eval`, print the resulting value as an JSON
|
||||||
|
|
|
@ -21,6 +21,9 @@ This operation has the following options:
|
||||||
Use recursive instead of flat hashing mode, used when adding
|
Use recursive instead of flat hashing mode, used when adding
|
||||||
directories to the store.
|
directories to the store.
|
||||||
|
|
||||||
|
*paths* that refer to symlinks are not dereferenced, but added to the store
|
||||||
|
as symlinks with the same target.
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
{{#include ../opt-common.md}}
|
{{#include ../opt-common.md}}
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
The operation `--add` adds the specified paths to the Nix store. It
|
The operation `--add` adds the specified paths to the Nix store. It
|
||||||
prints the resulting paths in the Nix store on standard output.
|
prints the resulting paths in the Nix store on standard output.
|
||||||
|
|
||||||
|
*paths* that refer to symlinks are not dereferenced, but added to the store
|
||||||
|
as symlinks with the same target.
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
{{#include ../opt-common.md}}
|
{{#include ../opt-common.md}}
|
||||||
|
|
|
@ -19,10 +19,11 @@ nix-build -E '(import ./.).packages.${builtins.currentSystem}.nix.doc'
|
||||||
or
|
or
|
||||||
|
|
||||||
```console
|
```console
|
||||||
nix build .#nix^doc
|
nix build .#nix-manual
|
||||||
```
|
```
|
||||||
|
|
||||||
and open `./result-doc/share/doc/nix/manual/index.html`.
|
and open `./result/share/doc/nix/manual/index.html`.
|
||||||
|
|
||||||
|
|
||||||
To build the manual incrementally, [enter the development shell](./building.md) and run:
|
To build the manual incrementally, [enter the development shell](./building.md) and run:
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ Creating a Cachix cache for your installer tests and adding its authorisation to
|
||||||
- `armv7l-linux`
|
- `armv7l-linux`
|
||||||
- `x86_64-darwin`
|
- `x86_64-darwin`
|
||||||
|
|
||||||
- The `installer_test` job (which runs on `ubuntu-latest` and `macos-latest`) will try to install Nix with the cached installer and run a trivial Nix command.
|
- The `installer_test` job (which runs on `ubuntu-24.04` and `macos-14`) will try to install Nix with the cached installer and run a trivial Nix command.
|
||||||
|
|
||||||
### One-time setup
|
### One-time setup
|
||||||
|
|
||||||
|
|
44
flake.lock
generated
44
flake.lock
generated
|
@ -3,11 +3,11 @@
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1696426674,
|
"lastModified": 1733328505,
|
||||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -23,11 +23,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1719994518,
|
"lastModified": 1733312601,
|
||||||
"narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=",
|
"narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7",
|
"rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -48,11 +48,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721042469,
|
"lastModified": 1734279981,
|
||||||
"narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=",
|
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "f451c19376071a90d8c58ab1a953c6e9840527fd",
|
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -61,35 +61,18 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libgit2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1715853528,
|
|
||||||
"narHash": "sha256-J2rCxTecyLbbDdsyBWn9w7r3pbKRMkI9E7RvRgAqBdY=",
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"rev": "36f7e21ad757a3dacc58cf7944329da6bc1d6e96",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "libgit2",
|
|
||||||
"ref": "v1.8.1",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1723688146,
|
"lastModified": 1734359947,
|
||||||
"narHash": "sha256-sqLwJcHYeWLOeP/XoLwAtYjr01TISlkOfz+NG82pbdg=",
|
"narHash": "sha256-1Noao/H+N8nFB4Beoy8fgwrcOQLVm9o4zKW1ODaqK9E=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c3d4ac725177c030b1e289015989da2ad9d56af0",
|
"rev": "48d12d5e70ee91fe8481378e540433a7303dbf6a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-24.05",
|
"ref": "release-24.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -131,7 +114,6 @@
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"git-hooks-nix": "git-hooks-nix",
|
"git-hooks-nix": "git-hooks-nix",
|
||||||
"libgit2": "libgit2",
|
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs-23-11": "nixpkgs-23-11",
|
"nixpkgs-23-11": "nixpkgs-23-11",
|
||||||
"nixpkgs-regression": "nixpkgs-regression"
|
"nixpkgs-regression": "nixpkgs-regression"
|
||||||
|
|
10
flake.nix
10
flake.nix
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
description = "The purely functional package manager";
|
description = "The purely functional package manager";
|
||||||
|
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.11";
|
||||||
|
|
||||||
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
||||||
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
|
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
|
||||||
inputs.flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
inputs.flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||||
inputs.libgit2 = { url = "github:libgit2/libgit2/v1.8.1"; flake = false; };
|
|
||||||
|
|
||||||
# dev tooling
|
# dev tooling
|
||||||
inputs.flake-parts.url = "github:hercules-ci/flake-parts";
|
inputs.flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
inputs.git-hooks-nix.inputs.flake-compat.follows = "";
|
inputs.git-hooks-nix.inputs.flake-compat.follows = "";
|
||||||
inputs.git-hooks-nix.inputs.gitignore.follows = "";
|
inputs.git-hooks-nix.inputs.gitignore.follows = "";
|
||||||
|
|
||||||
outputs = inputs@{ self, nixpkgs, nixpkgs-regression, libgit2, ... }:
|
outputs = inputs@{ self, nixpkgs, nixpkgs-regression, ... }:
|
||||||
|
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -36,7 +36,8 @@
|
||||||
"armv6l-unknown-linux-gnueabihf"
|
"armv6l-unknown-linux-gnueabihf"
|
||||||
"armv7l-unknown-linux-gnueabihf"
|
"armv7l-unknown-linux-gnueabihf"
|
||||||
"riscv64-unknown-linux-gnu"
|
"riscv64-unknown-linux-gnu"
|
||||||
"x86_64-unknown-netbsd"
|
# Disabled because of https://github.com/NixOS/nixpkgs/issues/344423
|
||||||
|
# "x86_64-unknown-netbsd"
|
||||||
"x86_64-unknown-freebsd"
|
"x86_64-unknown-freebsd"
|
||||||
"x86_64-w64-mingw32"
|
"x86_64-w64-mingw32"
|
||||||
];
|
];
|
||||||
|
@ -163,7 +164,6 @@
|
||||||
if prev.stdenv.hostPlatform.system == "i686-linux"
|
if prev.stdenv.hostPlatform.system == "i686-linux"
|
||||||
then (prev.pre-commit.override (o: { dotnet-sdk = ""; })).overridePythonAttrs (o: { doCheck = false; })
|
then (prev.pre-commit.override (o: { dotnet-sdk = ""; })).overridePythonAttrs (o: { doCheck = false; })
|
||||||
else prev.pre-commit;
|
else prev.pre-commit;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
# Ensure that this bug is not present in the C++ toolchain we are using.
|
|
||||||
#
|
|
||||||
# URL for bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80431
|
|
||||||
#
|
|
||||||
# The test program is from that issue, with only a slight modification
|
|
||||||
# to set an exit status instead of printing strings.
|
|
||||||
AC_DEFUN([ENSURE_NO_GCC_BUG_80431],
|
|
||||||
[
|
|
||||||
AC_MSG_CHECKING([that GCC bug 80431 is fixed])
|
|
||||||
AC_LANG_PUSH(C++)
|
|
||||||
AC_RUN_IFELSE(
|
|
||||||
[AC_LANG_PROGRAM(
|
|
||||||
[[
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
static bool a = true;
|
|
||||||
static bool b = true;
|
|
||||||
|
|
||||||
struct Options { };
|
|
||||||
|
|
||||||
struct Option
|
|
||||||
{
|
|
||||||
Option(Options * options)
|
|
||||||
{
|
|
||||||
a = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Option()
|
|
||||||
{
|
|
||||||
b = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MyOptions : Options { };
|
|
||||||
|
|
||||||
struct MyOptions2 : virtual MyOptions
|
|
||||||
{
|
|
||||||
Option foo{this};
|
|
||||||
};
|
|
||||||
]],
|
|
||||||
[[
|
|
||||||
{
|
|
||||||
MyOptions2 opts;
|
|
||||||
}
|
|
||||||
return (a << 1) | b;
|
|
||||||
]])],
|
|
||||||
[status_80431=0],
|
|
||||||
[status_80431=$?],
|
|
||||||
[status_80431=''])
|
|
||||||
AC_LANG_POP(C++)
|
|
||||||
AS_CASE([$status_80431],
|
|
||||||
[''],[
|
|
||||||
AC_MSG_RESULT(cannot check because cross compiling)
|
|
||||||
AC_MSG_NOTICE(assume we are bug free)
|
|
||||||
],
|
|
||||||
[0],[
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
],
|
|
||||||
[2],[
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
AC_MSG_ERROR(Cannot build Nix with C++ compiler with this bug)
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT(unexpected result $status_80431: not expected failure with bug, ignoring)
|
|
||||||
])
|
|
||||||
])
|
|
|
@ -10,6 +10,27 @@
|
||||||
# https://flake.parts/options/git-hooks-nix#options
|
# https://flake.parts/options/git-hooks-nix#options
|
||||||
pre-commit.settings = {
|
pre-commit.settings = {
|
||||||
hooks = {
|
hooks = {
|
||||||
|
# Conflicts are usually found by other checks, but not those in docs,
|
||||||
|
# and potentially other places.
|
||||||
|
check-merge-conflicts.enable = true;
|
||||||
|
# built-in check-merge-conflicts seems ineffective against those produced by mergify backports
|
||||||
|
check-merge-conflicts-2 = {
|
||||||
|
enable = true;
|
||||||
|
entry = "${pkgs.writeScript "check-merge-conflicts" ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
conflicts=false
|
||||||
|
for file in "$@"; do
|
||||||
|
if grep --with-filename --line-number -E '^>>>>>>> ' -- "$file"; then
|
||||||
|
conflicts=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if $conflicts; then
|
||||||
|
echo "ERROR: found merge/patch conflicts in files"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
touch $out
|
||||||
|
''}";
|
||||||
|
};
|
||||||
clang-format = {
|
clang-format = {
|
||||||
enable = true;
|
enable = true;
|
||||||
# https://github.com/cachix/git-hooks.nix/pull/532
|
# https://github.com/cachix/git-hooks.nix/pull/532
|
||||||
|
@ -356,6 +377,7 @@
|
||||||
''^src/libutil/util\.cc$''
|
''^src/libutil/util\.cc$''
|
||||||
''^src/libutil/util\.hh$''
|
''^src/libutil/util\.hh$''
|
||||||
''^src/libutil/variant-wrapper\.hh$''
|
''^src/libutil/variant-wrapper\.hh$''
|
||||||
|
''^src/libutil/widecharwidth/widechar_width\.h$'' # vendored source
|
||||||
''^src/libutil/windows/file-descriptor\.cc$''
|
''^src/libutil/windows/file-descriptor\.cc$''
|
||||||
''^src/libutil/windows/file-path\.cc$''
|
''^src/libutil/windows/file-path\.cc$''
|
||||||
''^src/libutil/windows/processes\.cc$''
|
''^src/libutil/windows/processes\.cc$''
|
||||||
|
|
|
@ -16,7 +16,3 @@ add_project_arguments(
|
||||||
'-Wno-deprecated-declarations',
|
'-Wno-deprecated-declarations',
|
||||||
language : 'cpp',
|
language : 'cpp',
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_option('buildtype') not in ['debug']
|
|
||||||
add_project_arguments('-O3', language : 'cpp')
|
|
||||||
endif
|
|
||||||
|
|
|
@ -66,6 +66,21 @@ let
|
||||||
|
|
||||||
mesonLayer = finalAttrs: prevAttrs:
|
mesonLayer = finalAttrs: prevAttrs:
|
||||||
{
|
{
|
||||||
|
# NOTE:
|
||||||
|
# As of https://github.com/NixOS/nixpkgs/blob/8baf8241cea0c7b30e0b8ae73474cb3de83c1a30/pkgs/by-name/me/meson/setup-hook.sh#L26,
|
||||||
|
# `mesonBuildType` defaults to `plain` if not specified. We want our Nix-built binaries to be optimized by default.
|
||||||
|
# More on build types here: https://mesonbuild.com/Builtin-options.html#details-for-buildtype.
|
||||||
|
mesonBuildType = "release";
|
||||||
|
# NOTE:
|
||||||
|
# Users who are debugging Nix builds are expected to set the environment variable `mesonBuildType`, per the
|
||||||
|
# guidance in https://github.com/NixOS/nix/blob/8a3fc27f1b63a08ac983ee46435a56cf49ebaf4a/doc/manual/source/development/debugging.md?plain=1#L10.
|
||||||
|
# For this reason, we don't want to refer to `finalAttrs.mesonBuildType` here, but rather use the environment variable.
|
||||||
|
preConfigure = prevAttrs.preConfigure or "" + ''
|
||||||
|
case "$mesonBuildType" in
|
||||||
|
release|minsize) appendToVar mesonFlags "-Db_lto=true" ;;
|
||||||
|
*) appendToVar mesonFlags "-Db_lto=false" ;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
pkgs.buildPackages.meson
|
pkgs.buildPackages.meson
|
||||||
pkgs.buildPackages.ninja
|
pkgs.buildPackages.ninja
|
||||||
|
@ -114,14 +129,6 @@ scope: {
|
||||||
requiredSystemFeatures = [ ];
|
requiredSystemFeatures = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
libseccomp = pkgs.libseccomp.overrideAttrs (_: rec {
|
|
||||||
version = "2.5.5";
|
|
||||||
src = pkgs.fetchurl {
|
|
||||||
url = "https://github.com/seccomp/libseccomp/releases/download/v${version}/libseccomp-${version}.tar.gz";
|
|
||||||
hash = "sha256-JIosik2bmFiqa69ScSw0r+/PnJ6Ut23OAsHJqiX7M3U=";
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
boehmgc = pkgs.boehmgc.override {
|
boehmgc = pkgs.boehmgc.override {
|
||||||
enableLargeConfig = true;
|
enableLargeConfig = true;
|
||||||
};
|
};
|
||||||
|
@ -140,8 +147,6 @@ scope: {
|
||||||
});
|
});
|
||||||
|
|
||||||
libgit2 = pkgs.libgit2.overrideAttrs (attrs: {
|
libgit2 = pkgs.libgit2.overrideAttrs (attrs: {
|
||||||
src = inputs.libgit2;
|
|
||||||
version = inputs.libgit2.lastModifiedDate;
|
|
||||||
cmakeFlags = attrs.cmakeFlags or []
|
cmakeFlags = attrs.cmakeFlags or []
|
||||||
++ [ "-DUSE_SSH=exec" ];
|
++ [ "-DUSE_SSH=exec" ];
|
||||||
nativeBuildInputs = attrs.nativeBuildInputs or []
|
nativeBuildInputs = attrs.nativeBuildInputs or []
|
||||||
|
@ -169,36 +174,6 @@ scope: {
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
busybox-sandbox-shell = pkgs.busybox-sandbox-shell or (pkgs.busybox.override {
|
|
||||||
useMusl = true;
|
|
||||||
enableStatic = true;
|
|
||||||
enableMinimal = true;
|
|
||||||
extraConfig = ''
|
|
||||||
CONFIG_FEATURE_FANCY_ECHO y
|
|
||||||
CONFIG_FEATURE_SH_MATH y
|
|
||||||
CONFIG_FEATURE_SH_MATH_64 y
|
|
||||||
|
|
||||||
CONFIG_ASH y
|
|
||||||
CONFIG_ASH_OPTIMIZE_FOR_SIZE y
|
|
||||||
|
|
||||||
CONFIG_ASH_ALIAS y
|
|
||||||
CONFIG_ASH_BASH_COMPAT y
|
|
||||||
CONFIG_ASH_CMDCMD y
|
|
||||||
CONFIG_ASH_ECHO y
|
|
||||||
CONFIG_ASH_GETOPTS y
|
|
||||||
CONFIG_ASH_INTERNAL_GLOB y
|
|
||||||
CONFIG_ASH_JOB_CONTROL y
|
|
||||||
CONFIG_ASH_PRINTF y
|
|
||||||
CONFIG_ASH_TEST y
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
# TODO change in Nixpkgs, Windows works fine. First commit of
|
|
||||||
# https://github.com/NixOS/nixpkgs/pull/322977 backported will fix.
|
|
||||||
toml11 = pkgs.toml11.overrideAttrs (old: {
|
|
||||||
meta.platforms = lib.platforms.all;
|
|
||||||
});
|
|
||||||
|
|
||||||
inherit resolvePath filesetToSource;
|
inherit resolvePath filesetToSource;
|
||||||
|
|
||||||
mkMesonDerivation =
|
mkMesonDerivation =
|
||||||
|
|
|
@ -145,13 +145,28 @@ poly_user_id_get() {
|
||||||
dsclattr "/Users/$1" "UniqueID"
|
dsclattr "/Users/$1" "UniqueID"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dscl_create() {
|
||||||
|
# workaround a bug in dscl where it sometimes fails with eNotYetImplemented:
|
||||||
|
# https://github.com/NixOS/nix/issues/12140
|
||||||
|
while ! _sudo "$1" /usr/bin/dscl . -create "$2" "$3" "$4" 2> "$SCRATCH/dscl.err"; do
|
||||||
|
local err=$?
|
||||||
|
if [[ $err -eq 140 ]] && grep -q "-14988 (eNotYetImplemented)" "$SCRATCH/dscl.err"; then
|
||||||
|
echo "dscl failed with eNotYetImplemented, retrying..."
|
||||||
|
sleep 1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
cat "$SCRATCH/dscl.err"
|
||||||
|
return $err
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
poly_user_hidden_get() {
|
poly_user_hidden_get() {
|
||||||
dsclattr "/Users/$1" "IsHidden"
|
dsclattr "/Users/$1" "IsHidden"
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_hidden_set() {
|
poly_user_hidden_set() {
|
||||||
_sudo "in order to make $1 a hidden user" \
|
dscl_create "in order to make $1 a hidden user" \
|
||||||
/usr/bin/dscl . -create "/Users/$1" "IsHidden" "1"
|
"/Users/$1" "IsHidden" "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_home_get() {
|
poly_user_home_get() {
|
||||||
|
@ -161,8 +176,8 @@ poly_user_home_get() {
|
||||||
poly_user_home_set() {
|
poly_user_home_set() {
|
||||||
# This can trigger a permission prompt now:
|
# This can trigger a permission prompt now:
|
||||||
# "Terminal" would like to administer your computer. Administration can include modifying passwords, networking, and system settings.
|
# "Terminal" would like to administer your computer. Administration can include modifying passwords, networking, and system settings.
|
||||||
_sudo "in order to give $1 a safe home directory" \
|
dscl_create "in order to give $1 a safe home directory" \
|
||||||
/usr/bin/dscl . -create "/Users/$1" "NFSHomeDirectory" "$2"
|
"/Users/$1" "NFSHomeDirectory" "$2"
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_note_get() {
|
poly_user_note_get() {
|
||||||
|
@ -170,8 +185,8 @@ poly_user_note_get() {
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_note_set() {
|
poly_user_note_set() {
|
||||||
_sudo "in order to give $username a useful note" \
|
dscl_create "in order to give $1 a useful note" \
|
||||||
/usr/bin/dscl . -create "/Users/$1" "RealName" "$2"
|
"/Users/$1" "RealName" "$2"
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_shell_get() {
|
poly_user_shell_get() {
|
||||||
|
@ -179,8 +194,8 @@ poly_user_shell_get() {
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_shell_set() {
|
poly_user_shell_set() {
|
||||||
_sudo "in order to give $1 a safe shell" \
|
dscl_create "in order to give $1 a safe shell" \
|
||||||
/usr/bin/dscl . -create "/Users/$1" "UserShell" "$2"
|
"/Users/$1" "UserShell" "$2"
|
||||||
}
|
}
|
||||||
|
|
||||||
poly_user_in_group_check() {
|
poly_user_in_group_check() {
|
||||||
|
|
|
@ -16,13 +16,25 @@ static std::string doRenderMarkdownToTerminal(std::string_view markdown)
|
||||||
{
|
{
|
||||||
int windowWidth = getWindowSize().second;
|
int windowWidth = getWindowSize().second;
|
||||||
|
|
||||||
struct lowdown_opts opts
|
#if HAVE_LOWDOWN_1_4
|
||||||
{
|
struct lowdown_opts_term opts_term {
|
||||||
.type = LOWDOWN_TERM,
|
|
||||||
.maxdepth = 20,
|
|
||||||
.cols = (size_t) std::max(windowWidth - 5, 60),
|
.cols = (size_t) std::max(windowWidth - 5, 60),
|
||||||
.hmargin = 0,
|
.hmargin = 0,
|
||||||
.vmargin = 0,
|
.vmargin = 0,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
struct lowdown_opts opts
|
||||||
|
{
|
||||||
|
.type = LOWDOWN_TERM,
|
||||||
|
#if HAVE_LOWDOWN_1_4
|
||||||
|
.term = opts_term,
|
||||||
|
#endif
|
||||||
|
.maxdepth = 20,
|
||||||
|
#if !HAVE_LOWDOWN_1_4
|
||||||
|
.cols = (size_t) std::max(windowWidth - 5, 60),
|
||||||
|
.hmargin = 0,
|
||||||
|
.vmargin = 0,
|
||||||
|
#endif
|
||||||
.feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES,
|
.feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES,
|
||||||
.oflags = LOWDOWN_TERM_NOLINK,
|
.oflags = LOWDOWN_TERM_NOLINK,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-cmd', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
@ -36,6 +34,8 @@ deps_public += nlohmann_json
|
||||||
lowdown = dependency('lowdown', version : '>= 0.9.0', required : get_option('markdown'))
|
lowdown = dependency('lowdown', version : '>= 0.9.0', required : get_option('markdown'))
|
||||||
deps_private += lowdown
|
deps_private += lowdown
|
||||||
configdata.set('HAVE_LOWDOWN', lowdown.found().to_int())
|
configdata.set('HAVE_LOWDOWN', lowdown.found().to_int())
|
||||||
|
# The API changed slightly around terminal initialization.
|
||||||
|
configdata.set('HAVE_LOWDOWN_1_4', lowdown.version().version_compare('>= 1.4.0').to_int())
|
||||||
|
|
||||||
readline_flavor = get_option('readline-flavor')
|
readline_flavor = get_option('readline-flavor')
|
||||||
if readline_flavor == 'editline'
|
if readline_flavor == 'editline'
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-expr-c', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-expr-test-support', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-expr-tests', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -3185,12 +3185,16 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) {
|
||||||
return v.print(str);
|
return v.print(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void forceNoNullByte(std::string_view s)
|
void forceNoNullByte(std::string_view s, std::function<Pos()> pos)
|
||||||
{
|
{
|
||||||
if (s.find('\0') != s.npos) {
|
if (s.find('\0') != s.npos) {
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
auto str = replaceStrings(std::string(s), "\0"sv, "␀"sv);
|
auto str = replaceStrings(std::string(s), "\0"sv, "␀"sv);
|
||||||
throw Error("input string '%s' cannot be represented as Nix string because it contains null bytes", str);
|
Error error("input string '%s' cannot be represented as Nix string because it contains null bytes", str);
|
||||||
|
if (pos) {
|
||||||
|
error.atPos(pos());
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,16 +41,18 @@ namespace nix {
|
||||||
|
|
||||||
// we make use of the fact that the parser receives a private copy of the input
|
// we make use of the fact that the parser receives a private copy of the input
|
||||||
// string and can munge around in it.
|
// string and can munge around in it.
|
||||||
static StringToken unescapeStr(SymbolTable & symbols, char * s, size_t length)
|
// getting the position is expensive and thus it is implemented lazily.
|
||||||
|
static StringToken unescapeStr(char * const s, size_t length, std::function<Pos()> && pos)
|
||||||
{
|
{
|
||||||
char * result = s;
|
bool noNullByte = true;
|
||||||
char * t = s;
|
char * t = s;
|
||||||
char c;
|
|
||||||
// the input string is terminated with *two* NULs, so we can safely take
|
// the input string is terminated with *two* NULs, so we can safely take
|
||||||
// *one* character after the one being checked against.
|
// *one* character after the one being checked against.
|
||||||
while ((c = *s++)) {
|
for (size_t i = 0; i < length; t++) {
|
||||||
|
char c = s[i++];
|
||||||
|
noNullByte &= c != '\0';
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
c = *s++;
|
c = s[i++];
|
||||||
if (c == 'n') *t = '\n';
|
if (c == 'n') *t = '\n';
|
||||||
else if (c == 'r') *t = '\r';
|
else if (c == 'r') *t = '\r';
|
||||||
else if (c == 't') *t = '\t';
|
else if (c == 't') *t = '\t';
|
||||||
|
@ -59,12 +61,14 @@ static StringToken unescapeStr(SymbolTable & symbols, char * s, size_t length)
|
||||||
else if (c == '\r') {
|
else if (c == '\r') {
|
||||||
/* Normalise CR and CR/LF into LF. */
|
/* Normalise CR and CR/LF into LF. */
|
||||||
*t = '\n';
|
*t = '\n';
|
||||||
if (*s == '\n') s++; /* cr/lf */
|
if (s[i] == '\n') i++; /* cr/lf */
|
||||||
}
|
}
|
||||||
else *t = c;
|
else *t = c;
|
||||||
t++;
|
|
||||||
}
|
}
|
||||||
return {result, size_t(t - result)};
|
if (!noNullByte) {
|
||||||
|
forceNoNullByte({s, size_t(t - s)}, std::move(pos));
|
||||||
|
}
|
||||||
|
return {s, size_t(t - s)};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void requireExperimentalFeature(const ExperimentalFeature & feature, const Pos & pos)
|
static void requireExperimentalFeature(const ExperimentalFeature & feature, const Pos & pos)
|
||||||
|
@ -175,7 +179,7 @@ or { return OR_KW; }
|
||||||
/* It is impossible to match strings ending with '$' with one
|
/* It is impossible to match strings ending with '$' with one
|
||||||
regex because trailing contexts are only valid at the end
|
regex because trailing contexts are only valid at the end
|
||||||
of a rule. (A sane but undocumented limitation.) */
|
of a rule. (A sane but undocumented limitation.) */
|
||||||
yylval->str = unescapeStr(state->symbols, yytext, yyleng);
|
yylval->str = unescapeStr(yytext, yyleng, [&]() { return state->positions[CUR_POS]; });
|
||||||
return STR;
|
return STR;
|
||||||
}
|
}
|
||||||
<STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
|
<STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
|
||||||
|
@ -191,6 +195,7 @@ or { return OR_KW; }
|
||||||
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
|
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
|
||||||
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
||||||
yylval->str = {yytext, (size_t) yyleng, true};
|
yylval->str = {yytext, (size_t) yyleng, true};
|
||||||
|
forceNoNullByte(yylval->str, [&]() { return state->positions[CUR_POS]; });
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\'\'\$ |
|
<IND_STRING>\'\'\$ |
|
||||||
|
@ -203,7 +208,7 @@ or { return OR_KW; }
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\'\'\\{ANY} {
|
<IND_STRING>\'\'\\{ANY} {
|
||||||
yylval->str = unescapeStr(state->symbols, yytext + 2, yyleng - 2);
|
yylval->str = unescapeStr(yytext + 2, yyleng - 2, [&]() { return state->positions[CUR_POS]; });
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
|
<IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-expr', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -2045,7 +2045,7 @@ static RegisterPrimOp primop_readFileType({
|
||||||
.args = {"p"},
|
.args = {"p"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Determine the directory entry type of a filesystem node, being
|
Determine the directory entry type of a filesystem node, being
|
||||||
one of "directory", "regular", "symlink", or "unknown".
|
one of `"directory"`, `"regular"`, `"symlink"`, or `"unknown"`.
|
||||||
)",
|
)",
|
||||||
.fun = prim_readFileType,
|
.fun = prim_readFileType,
|
||||||
});
|
});
|
||||||
|
@ -4059,7 +4059,7 @@ static RegisterPrimOp primop_toString({
|
||||||
});
|
});
|
||||||
|
|
||||||
/* `substring start len str' returns the substring of `str' starting
|
/* `substring start len str' returns the substring of `str' starting
|
||||||
at character position `min(start, stringLength str)' inclusive and
|
at byte position `min(start, stringLength str)' inclusive and
|
||||||
ending at `min(start + len, stringLength str)'. `start' must be
|
ending at `min(start + len, stringLength str)'. `start' must be
|
||||||
non-negative. */
|
non-negative. */
|
||||||
static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
|
@ -4098,7 +4098,7 @@ static RegisterPrimOp primop_substring({
|
||||||
.name = "__substring",
|
.name = "__substring",
|
||||||
.args = {"start", "len", "s"},
|
.args = {"start", "len", "s"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Return the substring of *s* from character position *start*
|
Return the substring of *s* from byte position *start*
|
||||||
(zero-based) up to but not including *start + len*. If *start* is
|
(zero-based) up to but not including *start + len*. If *start* is
|
||||||
greater than the length of the string, an empty string is returned.
|
greater than the length of the string, an empty string is returned.
|
||||||
If *start + len* lies beyond the end of the string or *len* is `-1`,
|
If *start + len* lies beyond the end of the string or *len* is `-1`,
|
||||||
|
|
|
@ -108,7 +108,11 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore)
|
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore)
|
||||||
{
|
{
|
||||||
str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
|
try {
|
||||||
|
str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
|
||||||
|
} catch (nlohmann::json::exception & e) {
|
||||||
|
throw JSONSerializationError("JSON serialization error: %s", e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
|
|
@ -16,4 +16,7 @@ nlohmann::json printValueAsJSON(EvalState & state, bool strict,
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore = true);
|
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore = true);
|
||||||
|
|
||||||
|
|
||||||
|
MakeError(JSONSerializationError, Error);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,6 +510,6 @@ typedef std::shared_ptr<Value *> RootValue;
|
||||||
|
|
||||||
RootValue allocRootValue(Value * v);
|
RootValue allocRootValue(Value * v);
|
||||||
|
|
||||||
void forceNoNullByte(std::string_view s);
|
void forceNoNullByte(std::string_view s, std::function<Pos()> = nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-fetchers-tests', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -66,7 +66,7 @@ Input Input::fromURL(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error("input '%s' is unsupported", url.url);
|
throw Error("input '%s' is unsupported", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
Input Input::fromAttrs(const Settings & settings, Attrs && attrs)
|
Input Input::fromAttrs(const Settings & settings, Attrs && attrs)
|
||||||
|
|
|
@ -426,7 +426,7 @@ struct GitInputScheme : InputScheme
|
||||||
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
||||||
bool isBareRepository = url.scheme == "file" && !pathExists(url.path + "/.git");
|
bool isBareRepository = url.scheme == "file" && !pathExists(url.path + "/.git");
|
||||||
repoInfo.isLocal = url.scheme == "file" && !forceHttp && !isBareRepository;
|
repoInfo.isLocal = url.scheme == "file" && !forceHttp && !isBareRepository;
|
||||||
repoInfo.url = repoInfo.isLocal ? url.path : url.base;
|
repoInfo.url = repoInfo.isLocal ? url.path : url.to_string();
|
||||||
|
|
||||||
// If this is a local directory and no ref or revision is
|
// If this is a local directory and no ref or revision is
|
||||||
// given, then allow the use of an unclean working tree.
|
// given, then allow the use of an unclean working tree.
|
||||||
|
|
|
@ -50,7 +50,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
else if (std::regex_match(path[2], refRegex))
|
else if (std::regex_match(path[2], refRegex))
|
||||||
ref = path[2];
|
ref = path[2];
|
||||||
else
|
else
|
||||||
throw BadURL("in URL '%s', '%s' is not a commit hash or branch/tag name", url.url, path[2]);
|
throw BadURL("in URL '%s', '%s' is not a commit hash or branch/tag name", url, path[2]);
|
||||||
} else if (size > 3) {
|
} else if (size > 3) {
|
||||||
std::string rs;
|
std::string rs;
|
||||||
for (auto i = std::next(path.begin(), 2); i != path.end(); i++) {
|
for (auto i = std::next(path.begin(), 2); i != path.end(); i++) {
|
||||||
|
@ -63,34 +63,34 @@ struct GitArchiveInputScheme : InputScheme
|
||||||
if (std::regex_match(rs, refRegex)) {
|
if (std::regex_match(rs, refRegex)) {
|
||||||
ref = rs;
|
ref = rs;
|
||||||
} else {
|
} else {
|
||||||
throw BadURL("in URL '%s', '%s' is not a branch/tag name", url.url, rs);
|
throw BadURL("in URL '%s', '%s' is not a branch/tag name", url, rs);
|
||||||
}
|
}
|
||||||
} else if (size < 2)
|
} else if (size < 2)
|
||||||
throw BadURL("URL '%s' is invalid", url.url);
|
throw BadURL("URL '%s' is invalid", url);
|
||||||
|
|
||||||
for (auto &[name, value] : url.query) {
|
for (auto &[name, value] : url.query) {
|
||||||
if (name == "rev") {
|
if (name == "rev") {
|
||||||
if (rev)
|
if (rev)
|
||||||
throw BadURL("URL '%s' contains multiple commit hashes", url.url);
|
throw BadURL("URL '%s' contains multiple commit hashes", url);
|
||||||
rev = Hash::parseAny(value, HashAlgorithm::SHA1);
|
rev = Hash::parseAny(value, HashAlgorithm::SHA1);
|
||||||
}
|
}
|
||||||
else if (name == "ref") {
|
else if (name == "ref") {
|
||||||
if (!std::regex_match(value, refRegex))
|
if (!std::regex_match(value, refRegex))
|
||||||
throw BadURL("URL '%s' contains an invalid branch/tag name", url.url);
|
throw BadURL("URL '%s' contains an invalid branch/tag name", url);
|
||||||
if (ref)
|
if (ref)
|
||||||
throw BadURL("URL '%s' contains multiple branch/tag names", url.url);
|
throw BadURL("URL '%s' contains multiple branch/tag names", url);
|
||||||
ref = value;
|
ref = value;
|
||||||
}
|
}
|
||||||
else if (name == "host") {
|
else if (name == "host") {
|
||||||
if (!std::regex_match(value, hostRegex))
|
if (!std::regex_match(value, hostRegex))
|
||||||
throw BadURL("URL '%s' contains an invalid instance host", url.url);
|
throw BadURL("URL '%s' contains an invalid instance host", url);
|
||||||
host_url = value;
|
host_url = value;
|
||||||
}
|
}
|
||||||
// FIXME: barf on unsupported attributes
|
// FIXME: barf on unsupported attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref && rev)
|
if (ref && rev)
|
||||||
throw BadURL("URL '%s' contains both a commit hash and a branch/tag name %s %s", url.url, *ref, rev->gitRev());
|
throw BadURL("URL '%s' contains both a commit hash and a branch/tag name %s %s", url, *ref, rev->gitRev());
|
||||||
|
|
||||||
Input input{settings};
|
Input input{settings};
|
||||||
input.attrs.insert_or_assign("type", std::string { schemeName() });
|
input.attrs.insert_or_assign("type", std::string { schemeName() });
|
||||||
|
|
|
@ -26,16 +26,16 @@ struct IndirectInputScheme : InputScheme
|
||||||
else if (std::regex_match(path[1], refRegex))
|
else if (std::regex_match(path[1], refRegex))
|
||||||
ref = path[1];
|
ref = path[1];
|
||||||
else
|
else
|
||||||
throw BadURL("in flake URL '%s', '%s' is not a commit hash or branch/tag name", url.url, path[1]);
|
throw BadURL("in flake URL '%s', '%s' is not a commit hash or branch/tag name", url, path[1]);
|
||||||
} else if (path.size() == 3) {
|
} else if (path.size() == 3) {
|
||||||
if (!std::regex_match(path[1], refRegex))
|
if (!std::regex_match(path[1], refRegex))
|
||||||
throw BadURL("in flake URL '%s', '%s' is not a branch/tag name", url.url, path[1]);
|
throw BadURL("in flake URL '%s', '%s' is not a branch/tag name", url, path[1]);
|
||||||
ref = path[1];
|
ref = path[1];
|
||||||
if (!std::regex_match(path[2], revRegex))
|
if (!std::regex_match(path[2], revRegex))
|
||||||
throw BadURL("in flake URL '%s', '%s' is not a commit hash", url.url, path[2]);
|
throw BadURL("in flake URL '%s', '%s' is not a commit hash", url, path[2]);
|
||||||
rev = Hash::parseAny(path[2], HashAlgorithm::SHA1);
|
rev = Hash::parseAny(path[2], HashAlgorithm::SHA1);
|
||||||
} else
|
} else
|
||||||
throw BadURL("GitHub URL '%s' is invalid", url.url);
|
throw BadURL("GitHub URL '%s' is invalid", url);
|
||||||
|
|
||||||
std::string id = path[0];
|
std::string id = path[0];
|
||||||
if (!std::regex_match(id, flakeRegex))
|
if (!std::regex_match(id, flakeRegex))
|
||||||
|
|
|
@ -161,7 +161,7 @@ struct MercurialInputScheme : InputScheme
|
||||||
{
|
{
|
||||||
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
auto url = parseURL(getStrAttr(input.attrs, "url"));
|
||||||
bool isLocal = url.scheme == "file";
|
bool isLocal = url.scheme == "file";
|
||||||
return {isLocal, isLocal ? url.path : url.base};
|
return {isLocal, isLocal ? url.path : url.to_string()};
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePath fetchToStore(ref<Store> store, Input & input) const
|
StorePath fetchToStore(ref<Store> store, Input & input) const
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-fetchers', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct PathInputScheme : InputScheme
|
||||||
if (url.scheme != "path") return {};
|
if (url.scheme != "path") return {};
|
||||||
|
|
||||||
if (url.authority && *url.authority != "")
|
if (url.authority && *url.authority != "")
|
||||||
throw Error("path URL '%s' should not have an authority ('%s')", url.url, *url.authority);
|
throw Error("path URL '%s' should not have an authority ('%s')", url, *url.authority);
|
||||||
|
|
||||||
Input input{settings};
|
Input input{settings};
|
||||||
input.attrs.insert_or_assign("type", "path");
|
input.attrs.insert_or_assign("type", "path");
|
||||||
|
@ -27,10 +27,10 @@ struct PathInputScheme : InputScheme
|
||||||
if (auto n = string2Int<uint64_t>(value))
|
if (auto n = string2Int<uint64_t>(value))
|
||||||
input.attrs.insert_or_assign(name, *n);
|
input.attrs.insert_or_assign(name, *n);
|
||||||
else
|
else
|
||||||
throw Error("path URL '%s' has invalid parameter '%s'", url.to_string(), name);
|
throw Error("path URL '%s' has invalid parameter '%s'", url, name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error("path URL '%s' has unsupported parameter '%s'", url.to_string(), name);
|
throw Error("path URL '%s' has unsupported parameter '%s'", url, name);
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-flake-c', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -7,18 +7,60 @@ namespace nix {
|
||||||
|
|
||||||
/* ----------- tests for flake/flakeref.hh --------------------------------------------------*/
|
/* ----------- tests for flake/flakeref.hh --------------------------------------------------*/
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
TEST(parseFlakeRef, path) {
|
||||||
* to_string
|
experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes);
|
||||||
* --------------------------------------------------------------------------*/
|
|
||||||
|
fetchers::Settings fetchSettings;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = "/foo/bar";
|
||||||
|
auto flakeref = parseFlakeRef(fetchSettings, s);
|
||||||
|
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = "/foo/bar?revCount=123&rev=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||||
|
auto flakeref = parseFlakeRef(fetchSettings, s);
|
||||||
|
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar?rev=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&revCount=123");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = "/foo/bar?xyzzy=123";
|
||||||
|
EXPECT_THROW(
|
||||||
|
parseFlakeRef(fetchSettings, s),
|
||||||
|
Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = "/foo/bar#bla";
|
||||||
|
EXPECT_THROW(
|
||||||
|
parseFlakeRef(fetchSettings, s),
|
||||||
|
Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = "/foo/bar#bla";
|
||||||
|
auto [flakeref, fragment] = parseFlakeRefWithFragment(fetchSettings, s);
|
||||||
|
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar");
|
||||||
|
ASSERT_EQ(fragment, "bla");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = "/foo/bar?revCount=123#bla";
|
||||||
|
auto [flakeref, fragment] = parseFlakeRefWithFragment(fetchSettings, s);
|
||||||
|
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar?revCount=123");
|
||||||
|
ASSERT_EQ(fragment, "bla");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(to_string, doesntReencodeUrl) {
|
TEST(to_string, doesntReencodeUrl) {
|
||||||
fetchers::Settings fetchSettings;
|
fetchers::Settings fetchSettings;
|
||||||
auto s = "http://localhost:8181/test/+3d.tar.gz";
|
auto s = "http://localhost:8181/test/+3d.tar.gz";
|
||||||
auto flakeref = parseFlakeRef(fetchSettings, s);
|
auto flakeref = parseFlakeRef(fetchSettings, s);
|
||||||
auto parsed = flakeref.to_string();
|
auto unparsed = flakeref.to_string();
|
||||||
auto expected = "http://localhost:8181/test/%2B3d.tar.gz";
|
auto expected = "http://localhost:8181/test/%2B3d.tar.gz";
|
||||||
|
|
||||||
ASSERT_EQ(parsed, expected);
|
ASSERT_EQ(unparsed, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-flake-tests', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -91,23 +91,16 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
|
||||||
bool isFlake,
|
bool isFlake,
|
||||||
bool preserveRelativePaths)
|
bool preserveRelativePaths)
|
||||||
{
|
{
|
||||||
std::string path = url;
|
static std::regex pathFlakeRegex(
|
||||||
std::string fragment = "";
|
R"(([^?#]*)(\?([^#]*))?(#(.*))?)",
|
||||||
std::map<std::string, std::string> query;
|
std::regex::ECMAScript);
|
||||||
auto pathEnd = url.find_first_of("#?");
|
|
||||||
auto fragmentStart = pathEnd;
|
std::smatch match;
|
||||||
if (pathEnd != std::string::npos && url[pathEnd] == '?') {
|
auto succeeds = std::regex_match(url, match, pathFlakeRegex);
|
||||||
fragmentStart = url.find("#");
|
assert(succeeds);
|
||||||
}
|
auto path = match[1].str();
|
||||||
if (pathEnd != std::string::npos) {
|
auto query = decodeQuery(match[3]);
|
||||||
path = url.substr(0, pathEnd);
|
auto fragment = percentDecode(match[5].str());
|
||||||
}
|
|
||||||
if (fragmentStart != std::string::npos) {
|
|
||||||
fragment = percentDecode(url.substr(fragmentStart+1));
|
|
||||||
}
|
|
||||||
if (pathEnd != std::string::npos && fragmentStart != std::string::npos && url[pathEnd] == '?') {
|
|
||||||
query = decodeQuery(url.substr(pathEnd + 1, fragmentStart - pathEnd - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseDir) {
|
if (baseDir) {
|
||||||
/* Check if 'url' is a path (either absolute or relative
|
/* Check if 'url' is a path (either absolute or relative
|
||||||
|
@ -161,11 +154,7 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
|
||||||
|
|
||||||
while (flakeRoot != "/") {
|
while (flakeRoot != "/") {
|
||||||
if (pathExists(flakeRoot + "/.git")) {
|
if (pathExists(flakeRoot + "/.git")) {
|
||||||
auto base = std::string("git+file://") + flakeRoot;
|
|
||||||
|
|
||||||
auto parsedURL = ParsedURL{
|
auto parsedURL = ParsedURL{
|
||||||
.url = base, // FIXME
|
|
||||||
.base = base,
|
|
||||||
.scheme = "git+file",
|
.scheme = "git+file",
|
||||||
.authority = "",
|
.authority = "",
|
||||||
.path = flakeRoot,
|
.path = flakeRoot,
|
||||||
|
@ -196,8 +185,6 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
|
||||||
}
|
}
|
||||||
|
|
||||||
return fromParsedURL(fetchSettings, {
|
return fromParsedURL(fetchSettings, {
|
||||||
.url = path,
|
|
||||||
.base = path,
|
|
||||||
.scheme = "path",
|
.scheme = "path",
|
||||||
.authority = "",
|
.authority = "",
|
||||||
.path = path,
|
.path = path,
|
||||||
|
@ -224,8 +211,6 @@ static std::optional<std::pair<FlakeRef, std::string>> parseFlakeIdRef(
|
||||||
|
|
||||||
if (std::regex_match(url, match, flakeRegex)) {
|
if (std::regex_match(url, match, flakeRegex)) {
|
||||||
auto parsedURL = ParsedURL{
|
auto parsedURL = ParsedURL{
|
||||||
.url = url,
|
|
||||||
.base = "flake:" + match.str(1),
|
|
||||||
.scheme = "flake",
|
.scheme = "flake",
|
||||||
.authority = "",
|
.authority = "",
|
||||||
.path = match[1],
|
.path = match[1],
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-flake', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-main-c', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-main', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-store-c', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-store-test-support', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-store-tests', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -701,6 +701,7 @@ Goal::Co DerivationGoal::tryToBuild()
|
||||||
if (buildMode != bmCheck && allValid) {
|
if (buildMode != bmCheck && allValid) {
|
||||||
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
|
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
|
||||||
outputLocks.setDeletion(true);
|
outputLocks.setDeletion(true);
|
||||||
|
outputLocks.unlock();
|
||||||
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -767,7 +767,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
auto s3Res = s3Helper.getObject(bucketName, key);
|
auto s3Res = s3Helper.getObject(bucketName, key);
|
||||||
FileTransferResult res;
|
FileTransferResult res;
|
||||||
if (!s3Res.data)
|
if (!s3Res.data)
|
||||||
throw FileTransferError(NotFound, "S3 object '%s' does not exist", request.uri);
|
throw FileTransferError(NotFound, {}, "S3 object '%s' does not exist", request.uri);
|
||||||
res.data = std::move(*s3Res.data);
|
res.data = std::move(*s3Res.data);
|
||||||
res.urls.push_back(request.uri);
|
res.urls.push_back(request.uri);
|
||||||
callback(std::move(res));
|
callback(std::move(res));
|
||||||
|
|
|
@ -455,7 +455,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
bool gcKeepOutputs = settings.gcKeepOutputs;
|
bool gcKeepOutputs = settings.gcKeepOutputs;
|
||||||
bool gcKeepDerivations = settings.gcKeepDerivations;
|
bool gcKeepDerivations = settings.gcKeepDerivations;
|
||||||
|
|
||||||
StorePathSet roots, dead, alive;
|
std::unordered_set<StorePath> roots, dead, alive;
|
||||||
|
|
||||||
struct Shared
|
struct Shared
|
||||||
{
|
{
|
||||||
|
@ -661,7 +661,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<StorePath, StorePathSet> referrersCache;
|
std::unordered_map<StorePath, StorePathSet> referrersCache;
|
||||||
|
|
||||||
/* Helper function that visits all paths reachable from `start`
|
/* Helper function that visits all paths reachable from `start`
|
||||||
via the referrers edges and optionally derivers and derivation
|
via the referrers edges and optionally derivers and derivation
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-store', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
'localstatedir=/nix/var',
|
'localstatedir=/nix/var',
|
||||||
],
|
],
|
||||||
|
|
|
@ -291,7 +291,11 @@ json listNar(ref<SourceAccessor> accessor, const CanonPath & path, bool recurse)
|
||||||
obj["type"] = "symlink";
|
obj["type"] = "symlink";
|
||||||
obj["target"] = accessor->readLink(path);
|
obj["target"] = accessor->readLink(path);
|
||||||
break;
|
break;
|
||||||
case SourceAccessor::Type::tMisc:
|
case SourceAccessor::Type::tBlock:
|
||||||
|
case SourceAccessor::Type::tChar:
|
||||||
|
case SourceAccessor::Type::tSocket:
|
||||||
|
case SourceAccessor::Type::tFifo:
|
||||||
|
case SourceAccessor::Type::tUnknown:
|
||||||
assert(false); // cannot happen for NARs
|
assert(false); // cannot happen for NARs
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -246,9 +246,7 @@ void Store::addMultipleToStore(
|
||||||
act.progress(nrDone, pathsToCopy.size(), nrRunning, nrFailed);
|
act.progress(nrDone, pathsToCopy.size(), nrRunning, nrFailed);
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadPool pool;
|
processGraph<StorePath>(
|
||||||
|
|
||||||
processGraph<StorePath>(pool,
|
|
||||||
storePathsToAdd,
|
storePathsToAdd,
|
||||||
|
|
||||||
[&](const StorePath & path) {
|
[&](const StorePath & path) {
|
||||||
|
@ -1028,12 +1026,10 @@ std::map<StorePath, StorePath> copyPaths(
|
||||||
}
|
}
|
||||||
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
||||||
|
|
||||||
ThreadPool pool;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Copy the realisation closure
|
// Copy the realisation closure
|
||||||
processGraph<Realisation>(
|
processGraph<Realisation>(
|
||||||
pool, Realisation::closure(srcStore, toplevelRealisations),
|
Realisation::closure(srcStore, toplevelRealisations),
|
||||||
[&](const Realisation & current) -> std::set<Realisation> {
|
[&](const Realisation & current) -> std::set<Realisation> {
|
||||||
std::set<Realisation> children;
|
std::set<Realisation> children;
|
||||||
for (const auto & [drvOutput, _] : current.dependentRealisations) {
|
for (const auto & [drvOutput, _] : current.dependentRealisations) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "signals.hh"
|
#include "signals.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
# include <errhandlingapi.h>
|
# include <errhandlingapi.h>
|
||||||
# include <fileapi.h>
|
# include <fileapi.h>
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-util-c', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-util-test-support', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -261,4 +261,18 @@ TEST(pathExists, bogusPathDoesNotExist)
|
||||||
{
|
{
|
||||||
ASSERT_FALSE(pathExists("/schnitzel/darmstadt/pommes"));
|
ASSERT_FALSE(pathExists("/schnitzel/darmstadt/pommes"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* makeParentCanonical
|
||||||
|
* --------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
TEST(makeParentCanonical, noParent)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(makeParentCanonical("file"), absPath(std::filesystem::path("file")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(makeParentCanonical, root)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(makeParentCanonical("/"), "/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-util-tests', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
|
|
@ -55,6 +55,10 @@ TEST(filterANSIEscapes, utf8)
|
||||||
ASSERT_EQ(filterANSIEscapes("fóóbär", true, 3), "fóó");
|
ASSERT_EQ(filterANSIEscapes("fóóbär", true, 3), "fóó");
|
||||||
ASSERT_EQ(filterANSIEscapes("f€€bär", true, 4), "f€€b");
|
ASSERT_EQ(filterANSIEscapes("f€€bär", true, 4), "f€€b");
|
||||||
ASSERT_EQ(filterANSIEscapes("f𐍈𐍈bär", true, 4), "f𐍈𐍈b");
|
ASSERT_EQ(filterANSIEscapes("f𐍈𐍈bär", true, 4), "f𐍈𐍈b");
|
||||||
|
ASSERT_EQ(filterANSIEscapes("f🔍bar", true, 6), "f🔍bar");
|
||||||
|
ASSERT_EQ(filterANSIEscapes("f🔍bar", true, 3), "f🔍");
|
||||||
|
ASSERT_EQ(filterANSIEscapes("f🔍bar", true, 2), "f");
|
||||||
|
ASSERT_EQ(filterANSIEscapes("foo\u0301", true, 3), "foó");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(filterANSIEscapes, osc8)
|
TEST(filterANSIEscapes, osc8)
|
||||||
|
|
|
@ -20,24 +20,11 @@ namespace nix {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const ParsedURL& p) {
|
|
||||||
return os << "\n"
|
|
||||||
<< "url: " << p.url << "\n"
|
|
||||||
<< "base: " << p.base << "\n"
|
|
||||||
<< "scheme: " << p.scheme << "\n"
|
|
||||||
<< "authority: " << p.authority.value() << "\n"
|
|
||||||
<< "path: " << p.path << "\n"
|
|
||||||
<< "query: " << print_map(p.query) << "\n"
|
|
||||||
<< "fragment: " << p.fragment << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(parseURL, parsesSimpleHttpUrl) {
|
TEST(parseURL, parsesSimpleHttpUrl) {
|
||||||
auto s = "http://www.example.org/file.tar.gz";
|
auto s = "http://www.example.org/file.tar.gz";
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "http://www.example.org/file.tar.gz",
|
|
||||||
.base = "http://www.example.org/file.tar.gz",
|
|
||||||
.scheme = "http",
|
.scheme = "http",
|
||||||
.authority = "www.example.org",
|
.authority = "www.example.org",
|
||||||
.path = "/file.tar.gz",
|
.path = "/file.tar.gz",
|
||||||
|
@ -53,8 +40,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "https://www.example.org/file.tar.gz",
|
|
||||||
.base = "https://www.example.org/file.tar.gz",
|
|
||||||
.scheme = "https",
|
.scheme = "https",
|
||||||
.authority = "www.example.org",
|
.authority = "www.example.org",
|
||||||
.path = "/file.tar.gz",
|
.path = "/file.tar.gz",
|
||||||
|
@ -70,8 +55,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "https://www.example.org/file.tar.gz",
|
|
||||||
.base = "https://www.example.org/file.tar.gz",
|
|
||||||
.scheme = "https",
|
.scheme = "https",
|
||||||
.authority = "www.example.org",
|
.authority = "www.example.org",
|
||||||
.path = "/file.tar.gz",
|
.path = "/file.tar.gz",
|
||||||
|
@ -87,8 +70,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "http://www.example.org/file.tar.gz",
|
|
||||||
.base = "http://www.example.org/file.tar.gz",
|
|
||||||
.scheme = "http",
|
.scheme = "http",
|
||||||
.authority = "www.example.org",
|
.authority = "www.example.org",
|
||||||
.path = "/file.tar.gz",
|
.path = "/file.tar.gz",
|
||||||
|
@ -104,8 +85,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "file+https://www.example.org/video.mp4",
|
|
||||||
.base = "https://www.example.org/video.mp4",
|
|
||||||
.scheme = "file+https",
|
.scheme = "file+https",
|
||||||
.authority = "www.example.org",
|
.authority = "www.example.org",
|
||||||
.path = "/video.mp4",
|
.path = "/video.mp4",
|
||||||
|
@ -126,8 +105,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "http://127.0.0.1:8080/file.tar.gz",
|
|
||||||
.base = "https://127.0.0.1:8080/file.tar.gz",
|
|
||||||
.scheme = "http",
|
.scheme = "http",
|
||||||
.authority = "127.0.0.1:8080",
|
.authority = "127.0.0.1:8080",
|
||||||
.path = "/file.tar.gz",
|
.path = "/file.tar.gz",
|
||||||
|
@ -143,8 +120,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
|
||||||
.base = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
|
||||||
.scheme = "http",
|
.scheme = "http",
|
||||||
.authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
.authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
||||||
.path = "",
|
.path = "",
|
||||||
|
@ -161,8 +136,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
|
|
||||||
.base = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
|
|
||||||
.scheme = "http",
|
.scheme = "http",
|
||||||
.authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
|
.authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
|
||||||
.path = "",
|
.path = "",
|
||||||
|
@ -185,8 +158,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "http://user:pass@www.example.org/file.tar.gz",
|
|
||||||
.base = "http://user:pass@www.example.org/file.tar.gz",
|
|
||||||
.scheme = "http",
|
.scheme = "http",
|
||||||
.authority = "user:pass@www.example.org:8080",
|
.authority = "user:pass@www.example.org:8080",
|
||||||
.path = "/file.tar.gz",
|
.path = "/file.tar.gz",
|
||||||
|
@ -203,8 +174,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "",
|
|
||||||
.base = "",
|
|
||||||
.scheme = "file",
|
.scheme = "file",
|
||||||
.authority = "",
|
.authority = "",
|
||||||
.path = "/none/of//your/business",
|
.path = "/none/of//your/business",
|
||||||
|
@ -228,8 +197,6 @@ namespace nix {
|
||||||
auto parsed = parseURL(s);
|
auto parsed = parseURL(s);
|
||||||
|
|
||||||
ParsedURL expected {
|
ParsedURL expected {
|
||||||
.url = "ftp://ftp.nixos.org/downloads/nixos.iso",
|
|
||||||
.base = "ftp://ftp.nixos.org/downloads/nixos.iso",
|
|
||||||
.scheme = "ftp",
|
.scheme = "ftp",
|
||||||
.authority = "ftp.nixos.org",
|
.authority = "ftp.nixos.org",
|
||||||
.path = "/downloads/nixos.iso",
|
.path = "/downloads/nixos.iso",
|
||||||
|
|
|
@ -262,6 +262,7 @@ public:
|
||||||
operator const T &() const { return value; }
|
operator const T &() const { return value; }
|
||||||
operator T &() { return value; }
|
operator T &() { return value; }
|
||||||
const T & get() const { return value; }
|
const T & get() const { return value; }
|
||||||
|
T & get() { return value; }
|
||||||
template<typename U>
|
template<typename U>
|
||||||
bool operator ==(const U & v2) const { return value == v2; }
|
bool operator ==(const U & v2) const { return value == v2; }
|
||||||
template<typename U>
|
template<typename U>
|
||||||
|
|
|
@ -331,7 +331,7 @@ void syncParent(const Path & path)
|
||||||
|
|
||||||
void recursiveSync(const Path & path)
|
void recursiveSync(const Path & path)
|
||||||
{
|
{
|
||||||
/* If it's a file, just fsync and return. */
|
/* If it's a file or symlink, just fsync and return. */
|
||||||
auto st = lstat(path);
|
auto st = lstat(path);
|
||||||
if (S_ISREG(st.st_mode)) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY, 0));
|
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY, 0));
|
||||||
|
@ -339,7 +339,8 @@ void recursiveSync(const Path & path)
|
||||||
throw SysError("opening file '%1%'", path);
|
throw SysError("opening file '%1%'", path);
|
||||||
fd.fsync();
|
fd.fsync();
|
||||||
return;
|
return;
|
||||||
}
|
} else if (S_ISLNK(st.st_mode))
|
||||||
|
return;
|
||||||
|
|
||||||
/* Otherwise, perform a depth-first traversal of the directory and
|
/* Otherwise, perform a depth-first traversal of the directory and
|
||||||
fsync all the files. */
|
fsync all the files. */
|
||||||
|
@ -384,7 +385,7 @@ static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & b
|
||||||
if (fstatat(parentfd, name.c_str(), &st,
|
if (fstatat(parentfd, name.c_str(), &st,
|
||||||
AT_SYMLINK_NOFOLLOW) == -1) {
|
AT_SYMLINK_NOFOLLOW) == -1) {
|
||||||
if (errno == ENOENT) return;
|
if (errno == ENOENT) return;
|
||||||
throw SysError("getting status of '%1%'", path);
|
throw SysError("getting status of %1%", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S_ISDIR(st.st_mode)) {
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
@ -416,15 +417,15 @@ static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & b
|
||||||
const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
|
const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
|
||||||
if ((st.st_mode & PERM_MASK) != PERM_MASK) {
|
if ((st.st_mode & PERM_MASK) != PERM_MASK) {
|
||||||
if (fchmodat(parentfd, name.c_str(), st.st_mode | PERM_MASK, 0) == -1)
|
if (fchmodat(parentfd, name.c_str(), st.st_mode | PERM_MASK, 0) == -1)
|
||||||
throw SysError("chmod '%1%'", path);
|
throw SysError("chmod %1%", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = openat(parentfd, path.c_str(), O_RDONLY);
|
int fd = openat(parentfd, path.c_str(), O_RDONLY);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
throw SysError("opening directory '%1%'", path);
|
throw SysError("opening directory %1%", path);
|
||||||
AutoCloseDir dir(fdopendir(fd));
|
AutoCloseDir dir(fdopendir(fd));
|
||||||
if (!dir)
|
if (!dir)
|
||||||
throw SysError("opening directory '%1%'", path);
|
throw SysError("opening directory %1%", path);
|
||||||
|
|
||||||
struct dirent * dirent;
|
struct dirent * dirent;
|
||||||
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
|
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
|
||||||
|
@ -433,13 +434,13 @@ static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & b
|
||||||
if (childName == "." || childName == "..") continue;
|
if (childName == "." || childName == "..") continue;
|
||||||
_deletePath(dirfd(dir.get()), path + "/" + childName, bytesFreed);
|
_deletePath(dirfd(dir.get()), path + "/" + childName, bytesFreed);
|
||||||
}
|
}
|
||||||
if (errno) throw SysError("reading directory '%1%'", path);
|
if (errno) throw SysError("reading directory %1%", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
|
int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
|
||||||
if (unlinkat(parentfd, name.c_str(), flags) == -1) {
|
if (unlinkat(parentfd, name.c_str(), flags) == -1) {
|
||||||
if (errno == ENOENT) return;
|
if (errno == ENOENT) return;
|
||||||
throw SysError("cannot unlink '%1%'", path);
|
throw SysError("cannot unlink %1%", path);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// TODO implement
|
// TODO implement
|
||||||
|
@ -765,4 +766,19 @@ bool isExecutableFileAmbient(const fs::path & exe) {
|
||||||
) == 0;
|
) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path makeParentCanonical(const std::filesystem::path & rawPath)
|
||||||
|
{
|
||||||
|
std::filesystem::path path(absPath(rawPath));;
|
||||||
|
try {
|
||||||
|
auto parent = path.parent_path();
|
||||||
|
if (parent == path) {
|
||||||
|
// `path` is a root directory => trivially canonical
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
return std::filesystem::canonical(parent) / path.filename();
|
||||||
|
} catch (fs::filesystem_error & e) {
|
||||||
|
throw SysError("canonicalising parent path of '%1%'", path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace nix
|
||||||
|
|
|
@ -143,6 +143,23 @@ inline bool symlink_exists(const std::filesystem::path & path) {
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canonicalize a path except for the last component.
|
||||||
|
*
|
||||||
|
* This is useful for getting the canonical location of a symlink.
|
||||||
|
*
|
||||||
|
* Consider the case where `foo/l` is a symlink. `canonical("foo/l")` will
|
||||||
|
* resolve the symlink `l` to its target.
|
||||||
|
* `makeParentCanonical("foo/l")` will not resolve the symlink `l` to its target,
|
||||||
|
* but does ensure that the returned parent part of the path, `foo` is resolved
|
||||||
|
* to `canonical("foo")`, and can therefore be retrieved without traversing any
|
||||||
|
* symlinks.
|
||||||
|
*
|
||||||
|
* If a relative path is passed, it will be made absolute, so that the parent
|
||||||
|
* can always be canonicalized.
|
||||||
|
*/
|
||||||
|
std::filesystem::path makeParentCanonical(const std::filesystem::path & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A version of pathExists that returns false on a permission error.
|
* A version of pathExists that returns false on a permission error.
|
||||||
* Useful for inferring default paths across directories that might not
|
* Useful for inferring default paths across directories that might not
|
||||||
|
|
|
@ -49,11 +49,13 @@ void copyRecursive(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SourceAccessor::tMisc:
|
case SourceAccessor::tChar:
|
||||||
throw Error("file '%1%' has an unsupported type", from);
|
case SourceAccessor::tBlock:
|
||||||
|
case SourceAccessor::tSocket:
|
||||||
|
case SourceAccessor::tFifo:
|
||||||
|
case SourceAccessor::tUnknown:
|
||||||
default:
|
default:
|
||||||
unreachable();
|
throw Error("file '%1%' has an unsupported type of %2%", from, stat.typeString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,11 @@ std::optional<Mode> convertMode(SourceAccessor::Type type)
|
||||||
case SourceAccessor::tSymlink: return Mode::Symlink;
|
case SourceAccessor::tSymlink: return Mode::Symlink;
|
||||||
case SourceAccessor::tRegular: return Mode::Regular;
|
case SourceAccessor::tRegular: return Mode::Regular;
|
||||||
case SourceAccessor::tDirectory: return Mode::Directory;
|
case SourceAccessor::tDirectory: return Mode::Directory;
|
||||||
case SourceAccessor::tMisc: return std::nullopt;
|
case SourceAccessor::tChar:
|
||||||
|
case SourceAccessor::tBlock:
|
||||||
|
case SourceAccessor::tSocket:
|
||||||
|
case SourceAccessor::tFifo: return std::nullopt;
|
||||||
|
case SourceAccessor::tUnknown:
|
||||||
default: unreachable();
|
default: unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,9 +318,13 @@ Mode dump(
|
||||||
return Mode::Symlink;
|
return Mode::Symlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SourceAccessor::tMisc:
|
case SourceAccessor::tChar:
|
||||||
|
case SourceAccessor::tBlock:
|
||||||
|
case SourceAccessor::tSocket:
|
||||||
|
case SourceAccessor::tFifo:
|
||||||
|
case SourceAccessor::tUnknown:
|
||||||
default:
|
default:
|
||||||
throw Error("file '%1%' has an unsupported type", path);
|
throw Error("file '%1%' has an unsupported type of %2%", path, st.typeString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix-util', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
],
|
],
|
||||||
meson_version : '>= 1.1',
|
meson_version : '>= 1.1',
|
||||||
|
@ -108,6 +106,8 @@ deps_private += cpuid
|
||||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||||
deps_public += nlohmann_json
|
deps_public += nlohmann_json
|
||||||
|
|
||||||
|
cxx = meson.get_compiler('cpp')
|
||||||
|
|
||||||
config_h = configure_file(
|
config_h = configure_file(
|
||||||
configuration : configdata,
|
configuration : configdata,
|
||||||
output : 'config-util.hh',
|
output : 'config-util.hh',
|
||||||
|
@ -168,6 +168,10 @@ sources = files(
|
||||||
)
|
)
|
||||||
|
|
||||||
include_dirs = [include_directories('.')]
|
include_dirs = [include_directories('.')]
|
||||||
|
if not cxx.has_header('widechar_width.h', required : false)
|
||||||
|
# use vendored widechar_width.h
|
||||||
|
include_dirs += include_directories('./widecharwidth')
|
||||||
|
endif
|
||||||
|
|
||||||
headers = [config_h] + files(
|
headers = [config_h] + files(
|
||||||
'abstract-setting-to-json.hh',
|
'abstract-setting-to-json.hh',
|
||||||
|
|
|
@ -29,6 +29,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
./nix-meson-build-support
|
./nix-meson-build-support
|
||||||
../../.version
|
../../.version
|
||||||
./.version
|
./.version
|
||||||
|
./widecharwidth
|
||||||
./meson.build
|
./meson.build
|
||||||
./meson.options
|
./meson.options
|
||||||
./linux/meson.build
|
./linux/meson.build
|
||||||
|
|
|
@ -122,7 +122,11 @@ std::optional<SourceAccessor::Stat> PosixSourceAccessor::maybeLstat(const CanonP
|
||||||
S_ISREG(st->st_mode) ? tRegular :
|
S_ISREG(st->st_mode) ? tRegular :
|
||||||
S_ISDIR(st->st_mode) ? tDirectory :
|
S_ISDIR(st->st_mode) ? tDirectory :
|
||||||
S_ISLNK(st->st_mode) ? tSymlink :
|
S_ISLNK(st->st_mode) ? tSymlink :
|
||||||
tMisc,
|
S_ISCHR(st->st_mode) ? tChar :
|
||||||
|
S_ISBLK(st->st_mode) ? tBlock :
|
||||||
|
S_ISSOCK(st->st_mode) ? tSocket :
|
||||||
|
S_ISFIFO(st->st_mode) ? tFifo :
|
||||||
|
tUnknown,
|
||||||
.fileSize = S_ISREG(st->st_mode) ? std::optional<uint64_t>(st->st_size) : std::nullopt,
|
.fileSize = S_ISREG(st->st_mode) ? std::optional<uint64_t>(st->st_size) : std::nullopt,
|
||||||
.isExecutable = S_ISREG(st->st_mode) && st->st_mode & S_IXUSR,
|
.isExecutable = S_ISREG(st->st_mode) && st->st_mode & S_IXUSR,
|
||||||
};
|
};
|
||||||
|
@ -156,7 +160,11 @@ SourceAccessor::DirEntries PosixSourceAccessor::readDirectory(const CanonPath &
|
||||||
case std::filesystem::file_type::regular: return Type::tRegular; break;
|
case std::filesystem::file_type::regular: return Type::tRegular; break;
|
||||||
case std::filesystem::file_type::symlink: return Type::tSymlink; break;
|
case std::filesystem::file_type::symlink: return Type::tSymlink; break;
|
||||||
case std::filesystem::file_type::directory: return Type::tDirectory; break;
|
case std::filesystem::file_type::directory: return Type::tDirectory; break;
|
||||||
default: return tMisc;
|
case std::filesystem::file_type::character: return Type::tChar; break;
|
||||||
|
case std::filesystem::file_type::block: return Type::tBlock; break;
|
||||||
|
case std::filesystem::file_type::fifo: return Type::tFifo; break;
|
||||||
|
case std::filesystem::file_type::socket: return Type::tSocket; break;
|
||||||
|
default: return tUnknown;
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -43,13 +43,25 @@ struct PosixSourceAccessor : virtual SourceAccessor
|
||||||
std::optional<std::filesystem::path> getPhysicalPath(const CanonPath & path) override;
|
std::optional<std::filesystem::path> getPhysicalPath(const CanonPath & path) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a `PosixSourceAccessor` and `CanonPath` corresponding to
|
* Create a `PosixSourceAccessor` and `SourcePath` corresponding to
|
||||||
* some native path.
|
* some native path.
|
||||||
*
|
*
|
||||||
* The `PosixSourceAccessor` is rooted as far up the tree as
|
* The `PosixSourceAccessor` is rooted as far up the tree as
|
||||||
* possible, (e.g. on Windows it could scoped to a drive like
|
* possible, (e.g. on Windows it could scoped to a drive like
|
||||||
* `C:\`). This allows more `..` parent accessing to work.
|
* `C:\`). This allows more `..` parent accessing to work.
|
||||||
*
|
*
|
||||||
|
* @note When `path` is trusted user input, canonicalize it using
|
||||||
|
* `std::filesystem::canonical`, `makeParentCanonical`, `std::filesystem::weakly_canonical`, etc,
|
||||||
|
* as appropriate for the use case. At least weak canonicalization is
|
||||||
|
* required for the `SourcePath` to do anything useful at the location it
|
||||||
|
* points to.
|
||||||
|
*
|
||||||
|
* @note A canonicalizing behavior is not built in `createAtRoot` so that
|
||||||
|
* callers do not accidentally introduce symlink-related security vulnerabilities.
|
||||||
|
* Furthermore, `createAtRoot` does not know whether the file pointed to by
|
||||||
|
* `path` should be resolved if it is itself a symlink. In other words,
|
||||||
|
* `createAtRoot` can not decide between aforementioned `canonical`, `makeParentCanonical`, etc. for its callers.
|
||||||
|
*
|
||||||
* See
|
* See
|
||||||
* [`std::filesystem::path::root_path`](https://en.cppreference.com/w/cpp/filesystem/path/root_path)
|
* [`std::filesystem::path::root_path`](https://en.cppreference.com/w/cpp/filesystem/path/root_path)
|
||||||
* and
|
* and
|
||||||
|
|
|
@ -5,6 +5,26 @@ namespace nix {
|
||||||
|
|
||||||
static std::atomic<size_t> nextNumber{0};
|
static std::atomic<size_t> nextNumber{0};
|
||||||
|
|
||||||
|
bool SourceAccessor::Stat::isNotNARSerialisable()
|
||||||
|
{
|
||||||
|
return this->type != tRegular && this->type != tSymlink && this->type != tDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SourceAccessor::Stat::typeString() {
|
||||||
|
switch (this->type) {
|
||||||
|
case tRegular: return "regular";
|
||||||
|
case tSymlink: return "symlink";
|
||||||
|
case tDirectory: return "directory";
|
||||||
|
case tChar: return "character device";
|
||||||
|
case tBlock: return "block device";
|
||||||
|
case tSocket: return "socket";
|
||||||
|
case tFifo: return "fifo";
|
||||||
|
case tUnknown:
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
SourceAccessor::SourceAccessor()
|
SourceAccessor::SourceAccessor()
|
||||||
: number(++nextNumber)
|
: number(++nextNumber)
|
||||||
, displayPrefix{"«unknown»"}
|
, displayPrefix{"«unknown»"}
|
||||||
|
|
|
@ -88,12 +88,13 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
|
||||||
|
|
||||||
Unlike `DT_UNKNOWN`, this must not be used for deferring the lookup of types.
|
Unlike `DT_UNKNOWN`, this must not be used for deferring the lookup of types.
|
||||||
*/
|
*/
|
||||||
tMisc
|
tChar, tBlock, tSocket, tFifo,
|
||||||
|
tUnknown
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stat
|
struct Stat
|
||||||
{
|
{
|
||||||
Type type = tMisc;
|
Type type = tUnknown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For regular files only: the size of the file. Not all
|
* For regular files only: the size of the file. Not all
|
||||||
|
@ -112,6 +113,9 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
|
||||||
* file in the NAR. Only returned by NAR accessors.
|
* file in the NAR. Only returned by NAR accessors.
|
||||||
*/
|
*/
|
||||||
std::optional<uint64_t> narOffset;
|
std::optional<uint64_t> narOffset;
|
||||||
|
|
||||||
|
bool isNotNARSerialisable();
|
||||||
|
std::string typeString();
|
||||||
};
|
};
|
||||||
|
|
||||||
Stat lstat(const CanonPath & path);
|
Stat lstat(const CanonPath & path);
|
||||||
|
|
|
@ -11,6 +11,53 @@
|
||||||
# include <sys/ioctl.h>
|
# include <sys/ioctl.h>
|
||||||
#endif
|
#endif
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <widechar_width.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline std::pair<int, size_t> charWidthUTF8Helper(std::string_view s)
|
||||||
|
{
|
||||||
|
size_t bytes = 1;
|
||||||
|
uint32_t ch = s[0];
|
||||||
|
uint32_t max = 1U << 7;
|
||||||
|
if ((ch & 0x80U) == 0U) {
|
||||||
|
} else if ((ch & 0xe0U) == 0xc0U) {
|
||||||
|
ch &= 0x1fU;
|
||||||
|
bytes = 2;
|
||||||
|
max = 1U << 11;
|
||||||
|
} else if ((ch & 0xf0U) == 0xe0U) {
|
||||||
|
ch &= 0x0fU;
|
||||||
|
bytes = 3;
|
||||||
|
max = 1U << 16;
|
||||||
|
} else if ((ch & 0xf8U) == 0xf0U) {
|
||||||
|
ch &= 0x07U;
|
||||||
|
bytes = 4;
|
||||||
|
max = 0x110000U;
|
||||||
|
} else {
|
||||||
|
return {bytes, bytes}; // invalid UTF-8 start byte
|
||||||
|
}
|
||||||
|
for (size_t i = 1; i < bytes; i++) {
|
||||||
|
if (i < s.size() && (s[i] & 0xc0) == 0x80) {
|
||||||
|
ch = (ch << 6) | (s[i] & 0x3f);
|
||||||
|
} else {
|
||||||
|
return {i, i}; // invalid UTF-8 encoding; assume one character per byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int width = bytes; // in case of overlong encoding
|
||||||
|
if (ch < max) {
|
||||||
|
width = widechar_wcwidth(ch);
|
||||||
|
if (width == widechar_ambiguous) {
|
||||||
|
width = 1; // just a guess...
|
||||||
|
} else if (width == widechar_widened_in_9) {
|
||||||
|
width = 2;
|
||||||
|
} else if (width < 0) {
|
||||||
|
width = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {width, bytes};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -30,7 +77,7 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w
|
||||||
size_t w = 0;
|
size_t w = 0;
|
||||||
auto i = s.begin();
|
auto i = s.begin();
|
||||||
|
|
||||||
while (w < (size_t) width && i != s.end()) {
|
while (i != s.end()) {
|
||||||
|
|
||||||
if (*i == '\e') {
|
if (*i == '\e') {
|
||||||
std::string e;
|
std::string e;
|
||||||
|
@ -61,10 +108,12 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (*i == '\t') {
|
else if (*i == '\t') {
|
||||||
i++; t += ' '; w++;
|
do {
|
||||||
while (w < (size_t) width && w % 8) {
|
if (++w > (size_t) width)
|
||||||
t += ' '; w++;
|
return t;
|
||||||
}
|
t += ' ';
|
||||||
|
} while (w % 8);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (*i == '\r' || *i == '\a')
|
else if (*i == '\r' || *i == '\a')
|
||||||
|
@ -72,35 +121,18 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
w++;
|
auto [chWidth, bytes] = charWidthUTF8Helper({i, s.end()});
|
||||||
// Copy one UTF-8 character.
|
w += chWidth;
|
||||||
if ((*i & 0xe0) == 0xc0) {
|
if (w > (size_t) width) {
|
||||||
t += *i++;
|
break;
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
}
|
||||||
} else if ((*i & 0xf0) == 0xe0) {
|
t += {i, i + bytes};
|
||||||
t += *i++;
|
i += bytes;
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
|
||||||
}
|
|
||||||
} else if ((*i & 0xf8) == 0xf0) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
t += *i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
||||||
|
|
|
@ -83,7 +83,6 @@ private:
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void processGraph(
|
void processGraph(
|
||||||
ThreadPool & pool,
|
|
||||||
const std::set<T> & nodes,
|
const std::set<T> & nodes,
|
||||||
std::function<std::set<T>(const T &)> getEdges,
|
std::function<std::set<T>(const T &)> getEdges,
|
||||||
std::function<void(const T &)> processNode)
|
std::function<void(const T &)> processNode)
|
||||||
|
@ -97,6 +96,10 @@ void processGraph(
|
||||||
|
|
||||||
std::function<void(const T &)> worker;
|
std::function<void(const T &)> worker;
|
||||||
|
|
||||||
|
/* Create pool last to ensure threads are stopped before other destructors
|
||||||
|
* run */
|
||||||
|
ThreadPool pool;
|
||||||
|
|
||||||
worker = [&](const T & node) {
|
worker = [&](const T & node) {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,6 @@ ParsedURL parseURL(const std::string & url)
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
|
|
||||||
if (std::regex_match(url, match, uriRegex)) {
|
if (std::regex_match(url, match, uriRegex)) {
|
||||||
auto & base = match[1];
|
|
||||||
std::string scheme = match[2];
|
std::string scheme = match[2];
|
||||||
auto authority = match[3].matched
|
auto authority = match[3].matched
|
||||||
? std::optional<std::string>(match[3]) : std::nullopt;
|
? std::optional<std::string>(match[3]) : std::nullopt;
|
||||||
|
@ -40,8 +39,6 @@ ParsedURL parseURL(const std::string & url)
|
||||||
path = "/";
|
path = "/";
|
||||||
|
|
||||||
return ParsedURL{
|
return ParsedURL{
|
||||||
.url = url,
|
|
||||||
.base = base,
|
|
||||||
.scheme = scheme,
|
.scheme = scheme,
|
||||||
.authority = authority,
|
.authority = authority,
|
||||||
.path = percentDecode(path),
|
.path = percentDecode(path),
|
||||||
|
@ -136,6 +133,12 @@ std::string ParsedURL::to_string() const
|
||||||
+ (fragment.empty() ? "" : "#" + percentEncode(fragment));
|
+ (fragment.empty() ? "" : "#" + percentEncode(fragment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream & operator << (std::ostream & os, const ParsedURL & url)
|
||||||
|
{
|
||||||
|
os << url.to_string();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
bool ParsedURL::operator ==(const ParsedURL & other) const noexcept
|
bool ParsedURL::operator ==(const ParsedURL & other) const noexcept
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,9 +7,6 @@ namespace nix {
|
||||||
|
|
||||||
struct ParsedURL
|
struct ParsedURL
|
||||||
{
|
{
|
||||||
std::string url;
|
|
||||||
/// URL without query/fragment
|
|
||||||
std::string base;
|
|
||||||
std::string scheme;
|
std::string scheme;
|
||||||
std::optional<std::string> authority;
|
std::optional<std::string> authority;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -26,6 +23,8 @@ struct ParsedURL
|
||||||
ParsedURL canonicalise();
|
ParsedURL canonicalise();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream & operator << (std::ostream & os, const ParsedURL & url);
|
||||||
|
|
||||||
MakeError(BadURL, Error);
|
MakeError(BadURL, Error);
|
||||||
|
|
||||||
std::string percentDecode(std::string_view in);
|
std::string percentDecode(std::string_view in);
|
||||||
|
|
4
src/libutil/widecharwidth/LICENSE
Normal file
4
src/libutil/widecharwidth/LICENSE
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
widecharwidth - wcwidth implementation
|
||||||
|
Written in 2018 by ridiculous_fish
|
||||||
|
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
|
||||||
|
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
1559
src/libutil/widecharwidth/widechar_width.h
Normal file
1559
src/libutil/widecharwidth/widechar_width.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
#include "environment-variables.hh"
|
#include "environment-variables.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
# include "processenv.h"
|
# include "processenv.h"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "windows-error.hh"
|
#include "windows-error.hh"
|
||||||
#include "file-path.hh"
|
#include "file-path.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#include <fileapi.h>
|
#include <fileapi.h>
|
||||||
#include <error.h>
|
#include <error.h>
|
||||||
#include <namedpipeapi.h>
|
#include <namedpipeapi.h>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "file-system.hh"
|
#include "file-system.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Descriptor openDirectory(const std::filesystem::path & path)
|
Descriptor openDirectory(const std::filesystem::path & path)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
# include <ioapiset.h>
|
# include <ioapiset.h>
|
||||||
# include "windows-error.hh"
|
# include "windows-error.hh"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "file-path-impl.hh"
|
#include "file-path-impl.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "file-system.hh"
|
#include "file-system.hh"
|
||||||
#include "windows-error.hh"
|
#include "windows-error.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "windows-async-pipe.hh"
|
#include "windows-async-pipe.hh"
|
||||||
#include "windows-error.hh"
|
#include "windows-error.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
namespace nix::windows {
|
namespace nix::windows {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "file-descriptor.hh"
|
#include "file-descriptor.hh"
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
namespace nix::windows {
|
namespace nix::windows {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "windows-error.hh"
|
#include "windows-error.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#include <error.h>
|
#include <error.h>
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#include <errhandlingapi.h>
|
#include <errhandlingapi.h>
|
||||||
|
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
|
|
|
@ -24,7 +24,7 @@ static Path gcRoot;
|
||||||
static int rootNr = 0;
|
static int rootNr = 0;
|
||||||
|
|
||||||
|
|
||||||
enum OutputKind { okPlain, okXML, okJSON };
|
enum OutputKind { okPlain, okRaw, okXML, okJSON };
|
||||||
|
|
||||||
void processExpr(EvalState & state, const Strings & attrPaths,
|
void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
bool parseOnly, bool strict, Bindings & autoArgs,
|
bool parseOnly, bool strict, Bindings & autoArgs,
|
||||||
|
@ -50,7 +50,11 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
vRes = v;
|
vRes = v;
|
||||||
else
|
else
|
||||||
state.autoCallFunction(autoArgs, v, vRes);
|
state.autoCallFunction(autoArgs, v, vRes);
|
||||||
if (output == okXML)
|
if (output == okRaw)
|
||||||
|
std::cout << *state.coerceToString(noPos, vRes, context, "while generating the nix-instantiate output");
|
||||||
|
// We intentionally don't output a newline here. The default PS1 for Bash in NixOS starts with a newline
|
||||||
|
// and other interactive shells like Zsh are smart enough to print a missing newline before the prompt.
|
||||||
|
else if (output == okXML)
|
||||||
printValueAsXML(state, strict, location, vRes, std::cout, context, noPos);
|
printValueAsXML(state, strict, location, vRes, std::cout, context, noPos);
|
||||||
else if (output == okJSON) {
|
else if (output == okJSON) {
|
||||||
printValueAsJSON(state, strict, vRes, v.determinePos(noPos), std::cout, context);
|
printValueAsJSON(state, strict, vRes, v.determinePos(noPos), std::cout, context);
|
||||||
|
@ -132,6 +136,8 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||||
gcRoot = getArg(*arg, arg, end);
|
gcRoot = getArg(*arg, arg, end);
|
||||||
else if (*arg == "--indirect")
|
else if (*arg == "--indirect")
|
||||||
;
|
;
|
||||||
|
else if (*arg == "--raw")
|
||||||
|
outputKind = okRaw;
|
||||||
else if (*arg == "--xml")
|
else if (*arg == "--xml")
|
||||||
outputKind = okXML;
|
outputKind = okXML;
|
||||||
else if (*arg == "--json")
|
else if (*arg == "--json")
|
||||||
|
|
|
@ -183,9 +183,9 @@ static void opAdd(Strings opFlags, Strings opArgs)
|
||||||
if (!opFlags.empty()) throw UsageError("unknown flag");
|
if (!opFlags.empty()) throw UsageError("unknown flag");
|
||||||
|
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
auto [accessor, canonPath] = PosixSourceAccessor::createAtRoot(i);
|
auto sourcePath = PosixSourceAccessor::createAtRoot(makeParentCanonical(i));
|
||||||
cout << fmt("%s\n", store->printStorePath(store->addToStore(
|
cout << fmt("%s\n", store->printStorePath(store->addToStore(
|
||||||
std::string(baseNameOf(i)), {accessor, canonPath})));
|
std::string(baseNameOf(i)), sourcePath)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,10 +207,10 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
|
||||||
opArgs.pop_front();
|
opArgs.pop_front();
|
||||||
|
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
auto [accessor, canonPath] = PosixSourceAccessor::createAtRoot(i);
|
auto sourcePath = PosixSourceAccessor::createAtRoot(makeParentCanonical(i));
|
||||||
std::cout << fmt("%s\n", store->printStorePath(store->addToStoreSlow(
|
std::cout << fmt("%s\n", store->printStorePath(store->addToStoreSlow(
|
||||||
baseNameOf(i),
|
baseNameOf(i),
|
||||||
{accessor, canonPath},
|
sourcePath,
|
||||||
method,
|
method,
|
||||||
hashAlgo).path));
|
hashAlgo).path));
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,13 @@ struct CmdAddToStore : MixDryRun, StoreCommand
|
||||||
{
|
{
|
||||||
if (!namePart) namePart = baseNameOf(path);
|
if (!namePart) namePart = baseNameOf(path);
|
||||||
|
|
||||||
auto [accessor, path2] = PosixSourceAccessor::createAtRoot(path);
|
auto sourcePath = PosixSourceAccessor::createAtRoot(makeParentCanonical(path));
|
||||||
|
|
||||||
auto storePath = dryRun
|
auto storePath = dryRun
|
||||||
? store->computeStorePath(
|
? store->computeStorePath(
|
||||||
*namePart, {accessor, path2}, caMethod, hashAlgo, {}).first
|
*namePart, sourcePath, caMethod, hashAlgo, {}).first
|
||||||
: store->addToStoreSlow(
|
: store->addToStoreSlow(
|
||||||
*namePart, {accessor, path2}, caMethod, hashAlgo, {}).path;
|
*namePart, sourcePath, caMethod, hashAlgo, {}).path;
|
||||||
|
|
||||||
logger->cout("%s", store->printStorePath(storePath));
|
logger->cout("%s", store->printStorePath(storePath));
|
||||||
}
|
}
|
||||||
|
|
|
@ -938,10 +938,10 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
createSymlink(target, to2);
|
createSymlink(target, os_string_to_string(PathViewNG { to2 }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error("file '%s' has unsupported type", from2);
|
throw Error("path '%s' needs to be a symlink, file, or directory but instead is a %s", from2, st.typeString());
|
||||||
changedFiles.push_back(to2);
|
changedFiles.push_back(to2);
|
||||||
notice("wrote: %s", to2);
|
notice("wrote: %s", to2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,18 +87,35 @@ struct CmdHashBase : Command
|
||||||
return std::make_unique<HashSink>(hashAlgo);
|
return std::make_unique<HashSink>(hashAlgo);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto path2 = PosixSourceAccessor::createAtRoot(path);
|
auto makeSourcePath = [&]() -> SourcePath {
|
||||||
|
return PosixSourceAccessor::createAtRoot(makeParentCanonical(path));
|
||||||
|
};
|
||||||
|
|
||||||
Hash h { HashAlgorithm::SHA256 }; // throwaway def to appease C++
|
Hash h { HashAlgorithm::SHA256 }; // throwaway def to appease C++
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case FileIngestionMethod::Flat:
|
case FileIngestionMethod::Flat:
|
||||||
|
{
|
||||||
|
// While usually we could use the some code as for NixArchive,
|
||||||
|
// the Flat method needs to support FIFOs, such as those
|
||||||
|
// produced by bash process substitution, e.g.:
|
||||||
|
// nix hash --mode flat <(echo hi)
|
||||||
|
// Also symlinks semantics are unambiguous in the flat case,
|
||||||
|
// so we don't need to go low-level, or reject symlink `path`s.
|
||||||
|
auto hashSink = makeSink();
|
||||||
|
readFile(path, *hashSink);
|
||||||
|
h = hashSink->finish().first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FileIngestionMethod::NixArchive:
|
case FileIngestionMethod::NixArchive:
|
||||||
{
|
{
|
||||||
|
auto sourcePath = makeSourcePath();
|
||||||
auto hashSink = makeSink();
|
auto hashSink = makeSink();
|
||||||
dumpPath(path2, *hashSink, (FileSerialisationMethod) mode);
|
dumpPath(sourcePath, *hashSink, (FileSerialisationMethod) mode);
|
||||||
h = hashSink->finish().first;
|
h = hashSink->finish().first;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FileIngestionMethod::Git: {
|
case FileIngestionMethod::Git: {
|
||||||
|
auto sourcePath = makeSourcePath();
|
||||||
std::function<git::DumpHook> hook;
|
std::function<git::DumpHook> hook;
|
||||||
hook = [&](const SourcePath & path) -> git::TreeEntry {
|
hook = [&](const SourcePath & path) -> git::TreeEntry {
|
||||||
auto hashSink = makeSink();
|
auto hashSink = makeSink();
|
||||||
|
@ -109,7 +126,7 @@ struct CmdHashBase : Command
|
||||||
.hash = hash,
|
.hash = hash,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
h = hook(path2).hash;
|
h = hook(sourcePath).hash;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ project('nix', 'cpp',
|
||||||
'cpp_std=c++2a',
|
'cpp_std=c++2a',
|
||||||
# TODO(Qyriad): increase the warning level
|
# TODO(Qyriad): increase the warning level
|
||||||
'warning_level=1',
|
'warning_level=1',
|
||||||
'debug=true',
|
|
||||||
'optimization=2',
|
|
||||||
'errorlogs=true', # Please print logs for tests that fail
|
'errorlogs=true', # Please print logs for tests that fail
|
||||||
'localstatedir=/nix/var',
|
'localstatedir=/nix/var',
|
||||||
],
|
],
|
||||||
|
|
|
@ -15,7 +15,7 @@ using namespace nix;
|
||||||
|
|
||||||
struct CmdUpgradeNix : MixDryRun, StoreCommand
|
struct CmdUpgradeNix : MixDryRun, StoreCommand
|
||||||
{
|
{
|
||||||
Path profileDir;
|
std::filesystem::path profileDir;
|
||||||
|
|
||||||
CmdUpgradeNix()
|
CmdUpgradeNix()
|
||||||
{
|
{
|
||||||
|
@ -64,7 +64,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
|
||||||
if (profileDir == "")
|
if (profileDir == "")
|
||||||
profileDir = getProfileDir(store);
|
profileDir = getProfileDir(store);
|
||||||
|
|
||||||
printInfo("upgrading Nix in profile '%s'", profileDir);
|
printInfo("upgrading Nix in profile %s", profileDir);
|
||||||
|
|
||||||
auto storePath = getLatestNix(store);
|
auto storePath = getLatestNix(store);
|
||||||
|
|
||||||
|
@ -93,7 +93,9 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
|
||||||
|
|
||||||
{
|
{
|
||||||
Activity act(*logger, lvlInfo, actUnknown,
|
Activity act(*logger, lvlInfo, actUnknown,
|
||||||
fmt("installing '%s' into profile '%s'...", store->printStorePath(storePath), profileDir));
|
fmt("installing '%s' into profile %s...", store->printStorePath(storePath), profileDir));
|
||||||
|
|
||||||
|
// FIXME: don't call an external process.
|
||||||
runProgram(getNixBin("nix-env").string(), false,
|
runProgram(getNixBin("nix-env").string(), false,
|
||||||
{"--profile", profileDir, "-i", store->printStorePath(storePath), "--no-sandbox"});
|
{"--profile", profileDir, "-i", store->printStorePath(storePath), "--no-sandbox"});
|
||||||
}
|
}
|
||||||
|
@ -102,31 +104,33 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the profile in which Nix is installed. */
|
/* Return the profile in which Nix is installed. */
|
||||||
Path getProfileDir(ref<Store> store)
|
std::filesystem::path getProfileDir(ref<Store> store)
|
||||||
{
|
{
|
||||||
auto whereOpt = ExecutablePath::load().findName(OS_STR("nix-env"));
|
auto whereOpt = ExecutablePath::load().findName(OS_STR("nix-env"));
|
||||||
if (!whereOpt)
|
if (!whereOpt)
|
||||||
throw Error("couldn't figure out how Nix is installed, so I can't upgrade it");
|
throw Error("couldn't figure out how Nix is installed, so I can't upgrade it");
|
||||||
const auto & where = whereOpt->parent_path();
|
const auto & where = whereOpt->parent_path();
|
||||||
|
|
||||||
printInfo("found Nix in '%s'", where);
|
printInfo("found Nix in %s", where);
|
||||||
|
|
||||||
if (hasPrefix(where.string(), "/run/current-system"))
|
if (hasPrefix(where.string(), "/run/current-system"))
|
||||||
throw Error("Nix on NixOS must be upgraded via 'nixos-rebuild'");
|
throw Error("Nix on NixOS must be upgraded via 'nixos-rebuild'");
|
||||||
|
|
||||||
Path profileDir = where.parent_path().string();
|
auto profileDir = where.parent_path();
|
||||||
|
|
||||||
// Resolve profile to /nix/var/nix/profiles/<name> link.
|
// Resolve profile to /nix/var/nix/profiles/<name> link.
|
||||||
while (canonPath(profileDir).find("/profiles/") == std::string::npos && std::filesystem::is_symlink(profileDir))
|
while (canonPath(profileDir.string()).find("/profiles/") == std::string::npos && std::filesystem::is_symlink(profileDir))
|
||||||
profileDir = readLink(profileDir);
|
profileDir = readLink(profileDir);
|
||||||
|
|
||||||
printInfo("found profile '%s'", profileDir);
|
printInfo("found profile %s", profileDir);
|
||||||
|
|
||||||
Path userEnv = canonPath(profileDir, true);
|
Path userEnv = canonPath(profileDir.string(), true);
|
||||||
|
|
||||||
if (where.filename() != "bin" ||
|
if (std::filesystem::exists(profileDir / "manifest.json"))
|
||||||
!hasSuffix(userEnv, "user-environment"))
|
throw Error("directory %s is managed by 'nix profile' and currently cannot be upgraded by 'nix upgrade-nix'", profileDir);
|
||||||
throw Error("directory %s does not appear to be part of a Nix profile", where);
|
|
||||||
|
if (!std::filesystem::exists(profileDir / "manifest.nix"))
|
||||||
|
throw Error("directory %s does not appear to be part of a Nix profile", profileDir);
|
||||||
|
|
||||||
if (!store->isValidPath(store->parseStorePath(userEnv)))
|
if (!store->isValidPath(store->parseStorePath(userEnv)))
|
||||||
throw Error("directory '%s' is not in the Nix store", userEnv);
|
throw Error("directory '%s' is not in the Nix store", userEnv);
|
||||||
|
|
|
@ -29,6 +29,47 @@ echo "$hash2"
|
||||||
|
|
||||||
test "$hash1" = "sha256:$hash2"
|
test "$hash1" = "sha256:$hash2"
|
||||||
|
|
||||||
|
# The contents can be accessed through a symlink, and this symlink has no effect on the hash
|
||||||
|
# https://github.com/NixOS/nix/issues/11941
|
||||||
|
test_issue_11941() {
|
||||||
|
local expected actual
|
||||||
|
mkdir -p "$TEST_ROOT/foo/bar" && ln -s "$TEST_ROOT/foo" "$TEST_ROOT/foo-link"
|
||||||
|
|
||||||
|
# legacy
|
||||||
|
expected=$(nix-store --add-fixed --recursive sha256 "$TEST_ROOT/foo/bar")
|
||||||
|
actual=$(nix-store --add-fixed --recursive sha256 "$TEST_ROOT/foo-link/bar")
|
||||||
|
[[ "$expected" == "$actual" ]]
|
||||||
|
actual=$(nix-store --add "$TEST_ROOT/foo-link/bar")
|
||||||
|
[[ "$expected" == "$actual" ]]
|
||||||
|
|
||||||
|
# nix store add
|
||||||
|
actual=$(nix store add --hash-algo sha256 --mode nar "$TEST_ROOT/foo/bar")
|
||||||
|
[[ "$expected" == "$actual" ]]
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
rm -r "$TEST_ROOT/foo" "$TEST_ROOT/foo-link"
|
||||||
|
}
|
||||||
|
test_issue_11941
|
||||||
|
|
||||||
|
# A symlink is added to the store as a symlink, not as a copy of the target
|
||||||
|
test_add_symlink() {
|
||||||
|
ln -s /bin "$TEST_ROOT/my-bin"
|
||||||
|
|
||||||
|
# legacy
|
||||||
|
path=$(nix-store --add-fixed --recursive sha256 "$TEST_ROOT/my-bin")
|
||||||
|
[[ "$(readlink "$path")" == /bin ]]
|
||||||
|
path=$(nix-store --add "$TEST_ROOT/my-bin")
|
||||||
|
[[ "$(readlink "$path")" == /bin ]]
|
||||||
|
|
||||||
|
# nix store add
|
||||||
|
path=$(nix store add --hash-algo sha256 --mode nar "$TEST_ROOT/my-bin")
|
||||||
|
[[ "$(readlink "$path")" == /bin ]]
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
rm "$TEST_ROOT/my-bin"
|
||||||
|
}
|
||||||
|
test_add_symlink
|
||||||
|
|
||||||
#### New style commands
|
#### New style commands
|
||||||
|
|
||||||
clearStoreIfPossible
|
clearStoreIfPossible
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
int = 123;
|
int = 123;
|
||||||
str = "foo";
|
str = "foo\nbar";
|
||||||
attr.foo = "bar";
|
attr.foo = "bar";
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ EOF
|
||||||
nix eval --expr 'assert 1 + 2 == 3; true'
|
nix eval --expr 'assert 1 + 2 == 3; true'
|
||||||
|
|
||||||
[[ $(nix eval int -f "./eval.nix") == 123 ]]
|
[[ $(nix eval int -f "./eval.nix") == 123 ]]
|
||||||
[[ $(nix eval str -f "./eval.nix") == '"foo"' ]]
|
[[ $(nix eval str -f "./eval.nix") == '"foo\nbar"' ]]
|
||||||
[[ $(nix eval str --raw -f "./eval.nix") == 'foo' ]]
|
[[ $(nix eval str --raw -f "./eval.nix") == $'foo\nbar' ]]
|
||||||
[[ "$(nix eval attr -f "./eval.nix")" == '{ foo = "bar"; }' ]]
|
[[ "$(nix eval attr -f "./eval.nix")" == '{ foo = "bar"; }' ]]
|
||||||
[[ $(nix eval attr --json -f "./eval.nix") == '{"foo":"bar"}' ]]
|
[[ $(nix eval attr --json -f "./eval.nix") == '{"foo":"bar"}' ]]
|
||||||
[[ $(nix eval int -f - < "./eval.nix") == 123 ]]
|
[[ $(nix eval int -f - < "./eval.nix") == 123 ]]
|
||||||
|
@ -28,7 +28,8 @@ nix eval --expr 'assert 1 + 2 == 3; true'
|
||||||
|
|
||||||
nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
|
nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
|
||||||
[[ $(nix-instantiate -A int --eval "./eval.nix") == 123 ]]
|
[[ $(nix-instantiate -A int --eval "./eval.nix") == 123 ]]
|
||||||
[[ $(nix-instantiate -A str --eval "./eval.nix") == '"foo"' ]]
|
[[ $(nix-instantiate -A str --eval "./eval.nix") == '"foo\nbar"' ]]
|
||||||
|
[[ $(nix-instantiate -A str --raw --eval "./eval.nix") == $'foo\nbar' ]]
|
||||||
[[ "$(nix-instantiate -A attr --eval "./eval.nix")" == '{ foo = "bar"; }' ]]
|
[[ "$(nix-instantiate -A attr --eval "./eval.nix")" == '{ foo = "bar"; }' ]]
|
||||||
[[ $(nix-instantiate -A attr --eval --json "./eval.nix") == '{"foo":"bar"}' ]]
|
[[ $(nix-instantiate -A attr --eval --json "./eval.nix") == '{"foo":"bar"}' ]]
|
||||||
[[ $(nix-instantiate -A int --eval - < "./eval.nix") == 123 ]]
|
[[ $(nix-instantiate -A int --eval - < "./eval.nix") == 123 ]]
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue