Compare commits
1 Commits
fetchFinal
...
nix-develo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82aa3ca2d7 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -174,7 +174,7 @@ jobs:
|
||||
echo "installer-url=file://$GITHUB_WORKSPACE/out" >> "$GITHUB_OUTPUT"
|
||||
TARBALL_PATH="$(find "$GITHUB_WORKSPACE/out" -name 'nix*.tar.xz' -print | head -n 1)"
|
||||
echo "tarball-path=file://$TARBALL_PATH" >> "$GITHUB_OUTPUT"
|
||||
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31.8.4
|
||||
- uses: cachix/install-nix-action@456688f15bc354bef6d396e4a35f4f89d40bf2b7 # v31.8.2
|
||||
if: ${{ !matrix.experimental-installer }}
|
||||
with:
|
||||
install_url: ${{ format('{0}/install', steps.installer-tarball-url.outputs.installer-url) }}
|
||||
|
||||
@@ -37,7 +37,6 @@ mkMesonDerivation (finalAttrs: {
|
||||
(fileset.unions [
|
||||
../../.version
|
||||
# For example JSON
|
||||
../../src/libutil-tests/data/memory-source-accessor
|
||||
../../src/libutil-tests/data/hash
|
||||
../../src/libstore-tests/data/content-address
|
||||
../../src/libstore-tests/data/store-path
|
||||
@@ -59,8 +58,8 @@ mkMesonDerivation (finalAttrs: {
|
||||
"man"
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
nix-cli
|
||||
# Hack for sake of the dev shell
|
||||
passthru.externalNativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
(lib.getBin lowdown-unsandboxed)
|
||||
@@ -79,6 +78,10 @@ mkMesonDerivation (finalAttrs: {
|
||||
changelog-d
|
||||
];
|
||||
|
||||
nativeBuildInputs = finalAttrs.passthru.externalNativeBuildInputs ++ [
|
||||
nix-cli
|
||||
];
|
||||
|
||||
preConfigure = ''
|
||||
chmod u+w ./.version
|
||||
echo ${finalAttrs.version} > ./.version
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
synopsis: Fix "download buffer is full; consider increasing the 'download-buffer-size' setting" warning
|
||||
prs: [14614]
|
||||
issues: [11728]
|
||||
---
|
||||
|
||||
The underlying issue that led to [#11728](https://github.com/NixOS/nix/issues/11728) has been resolved by utilizing
|
||||
[libcurl write pausing functionality](https://curl.se/libcurl/c/curl_easy_pause.html) to control backpressure when unpacking to slow destinations like the git-backed tarball cache. The default value of `download-buffer-size` is now 1 MiB and it's no longer recommended to increase it, since the root cause has been fixed.
|
||||
|
||||
This is expected to improve download performance on fast connections, since previously a single slow download consumer would stall the thread and prevent any other transfers from progressing.
|
||||
|
||||
Many thanks go out to the [Lix project](https://lix.systems/) for the [implementation](https://git.lix.systems/lix-project/lix/commit/4ae6fb5a8f0d456b8d2ba2aaca3712b4e49057fc) that served as inspiration for this change and for triaging libcurl [issues with pausing](https://github.com/curl/curl/issues/19334).
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
synopsis: "S3 binary cache stores now support storage class configuration"
|
||||
prs: [14464]
|
||||
issues: [7015]
|
||||
---
|
||||
|
||||
S3 binary cache stores now support configuring the storage class for uploaded objects via the `storage-class` parameter. This allows users to optimize costs by selecting appropriate storage tiers based on access patterns.
|
||||
|
||||
Example usage:
|
||||
|
||||
```bash
|
||||
# Use Glacier storage for long-term archival
|
||||
nix copy --to 's3://my-bucket?storage-class=GLACIER' /nix/store/...
|
||||
|
||||
# Use Intelligent Tiering for automatic cost optimization
|
||||
nix copy --to 's3://my-bucket?storage-class=INTELLIGENT_TIERING' /nix/store/...
|
||||
```
|
||||
|
||||
The storage class applies to both regular uploads and multipart uploads. When not specified, objects use the bucket's default storage class.
|
||||
|
||||
See the [S3 storage classes documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html) for available storage classes and their characteristics.
|
||||
@@ -29,7 +29,6 @@
|
||||
- [Build Trace](store/build-trace.md)
|
||||
- [Derivation Resolution](store/resolution.md)
|
||||
- [Building](store/building.md)
|
||||
- [Secrets](store/secrets.md)
|
||||
- [Store Types](store/types/index.md)
|
||||
{{#include ./store/types/SUMMARY.md}}
|
||||
- [Appendix: Math notation](store/math-notation.md)
|
||||
@@ -121,7 +120,6 @@
|
||||
- [Architecture and Design](architecture/architecture.md)
|
||||
- [Formats and Protocols](protocols/index.md)
|
||||
- [JSON Formats](protocols/json/index.md)
|
||||
- [File System Object](protocols/json/file-system-object.md)
|
||||
- [Hash](protocols/json/hash.md)
|
||||
- [Content Address](protocols/json/content-address.md)
|
||||
- [Store Path](protocols/json/store-path.md)
|
||||
|
||||
@@ -36,7 +36,7 @@ to a temporary location. The tarball must include a single top-level
|
||||
directory containing at least a file named `default.nix`.
|
||||
|
||||
`nix-build` is essentially a wrapper around
|
||||
[`nix-instantiate`](./nix-instantiate.md) (to translate a high-level Nix
|
||||
[`nix-instantiate`](nix-instantiate.md) (to translate a high-level Nix
|
||||
expression to a low-level [store derivation]) and [`nix-store
|
||||
--realise`](@docroot@/command-ref/nix-store/realise.md) (to build the store
|
||||
derivation).
|
||||
@@ -52,8 +52,8 @@ derivation).
|
||||
# Options
|
||||
|
||||
All options not listed here are passed to
|
||||
[`nix-store --realise`](./nix-store/realise.md),
|
||||
except for `--arg` and `--attr` / `-A` which are passed to [`nix-instantiate`](./nix-instantiate.md).
|
||||
[`nix-store --realise`](nix-store/realise.md),
|
||||
except for `--arg` and `--attr` / `-A` which are passed to [`nix-instantiate`](nix-instantiate.md).
|
||||
|
||||
- <span id="opt-no-out-link">[`--no-out-link`](#opt-no-out-link)<span>
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ standard input.
|
||||
|
||||
- `--add-root` *path*
|
||||
|
||||
See the [corresponding option](./nix-store.md) in `nix-store`.
|
||||
See the [corresponding option](nix-store.md) in `nix-store`.
|
||||
|
||||
- `--parse`
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ In the development shell, set the `mesonBuildType` environment variable to `debu
|
||||
Then, proceed to build Nix as described in [Building Nix](./building.md).
|
||||
This will build Nix with debug symbols, which are essential for effective debugging.
|
||||
|
||||
It is also possible to build without optimization for faster build:
|
||||
It is also possible to build without debugging for faster build:
|
||||
|
||||
```console
|
||||
[nix-shell]$ NIX_HARDENING_ENABLE=$(printLines $NIX_HARDENING_ENABLE | grep -v fortify)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{{#include file-system-object-v1-fixed.md}}
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple
|
||||
|
||||
```json
|
||||
{{#include schema/file-system-object-v1/simple.json}}
|
||||
```
|
||||
|
||||
### Complex
|
||||
|
||||
```json
|
||||
{{#include schema/file-system-object-v1/complex.json}}
|
||||
```
|
||||
|
||||
<!-- need to convert YAML to JSON first
|
||||
## Raw Schema
|
||||
|
||||
[JSON Schema for File System Object v1](schema/file-system-object-v1.json)
|
||||
-->
|
||||
@@ -11,7 +11,6 @@ s/\\`/`/g
|
||||
#
|
||||
# As we have more such relative links, more replacements of this nature
|
||||
# should appear below.
|
||||
s^#/\$defs/\(regular\|symlink\|directory\)^In this schema^g
|
||||
s^\(./hash-v1.yaml\)\?#/$defs/algorithm^[JSON format for `Hash`](./hash.html#algorithm)^g
|
||||
s^\(./hash-v1.yaml\)^[JSON format for `Hash`](./hash.html)^g
|
||||
s^\(./content-address-v1.yaml\)\?#/$defs/method^[JSON format for `ContentAddress`](./content-address.html#method)^g
|
||||
|
||||
@@ -9,7 +9,6 @@ json_schema_for_humans = find_program('generate-schema-doc', required : false)
|
||||
json_schema_config = files('json-schema-for-humans-config.yaml')
|
||||
|
||||
schemas = [
|
||||
'file-system-object-v1',
|
||||
'hash-v1',
|
||||
'content-address-v1',
|
||||
'store-path-v1',
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../src/libutil-tests/data/memory-source-accessor
|
||||
@@ -1,71 +0,0 @@
|
||||
"$schema": http://json-schema.org/draft-04/schema#
|
||||
"$id": https://nix.dev/manual/nix/latest/protocols/json/schema/file-system-object-v1.json
|
||||
title: File System Object
|
||||
description: |
|
||||
This schema describes the JSON representation of Nix's [File System Object](@docroot@/store/file-system-object.md).
|
||||
|
||||
The schema is recursive because file system objects contain other file system objects.
|
||||
type: object
|
||||
required: ["type"]
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: ["regular", "symlink", "directory"]
|
||||
|
||||
# Enforce conditional structure based on `type`
|
||||
anyOf:
|
||||
- $ref: "#/$defs/regular"
|
||||
required: ["type", "contents"]
|
||||
|
||||
- $ref: "#/$defs/directory"
|
||||
required: ["type", "entries"]
|
||||
|
||||
- $ref: "#/$defs/symlink"
|
||||
required: ["type", "target"]
|
||||
|
||||
"$defs":
|
||||
regular:
|
||||
title: Regular File
|
||||
description: |
|
||||
See [Regular File](@docroot@/store/file-system-object.md#regular) in the manual for details.
|
||||
required: ["contents"]
|
||||
properties:
|
||||
type:
|
||||
const: "regular"
|
||||
contents:
|
||||
type: string
|
||||
description: File contents
|
||||
executable:
|
||||
type: boolean
|
||||
description: Whether the file is executable.
|
||||
default: false
|
||||
additionalProperties: false
|
||||
|
||||
directory:
|
||||
title: Directory
|
||||
description: |
|
||||
See [Directory](@docroot@/store/file-system-object.md#directory) in the manual for details.
|
||||
required: ["entries"]
|
||||
properties:
|
||||
type:
|
||||
const: "directory"
|
||||
entries:
|
||||
type: object
|
||||
description: |
|
||||
Map of names to nested file system objects (for type=directory)
|
||||
additionalProperties:
|
||||
$ref: "#"
|
||||
additionalProperties: false
|
||||
|
||||
symlink:
|
||||
title: Symbolic Link
|
||||
description: |
|
||||
See [Symbolic Link](@docroot@/store/file-system-object.md#symlink) in the manual for details.
|
||||
required: ["target"]
|
||||
properties:
|
||||
type:
|
||||
const: "symlink"
|
||||
target:
|
||||
type: string
|
||||
description: Target path of the symlink.
|
||||
additionalProperties: false
|
||||
@@ -24,7 +24,7 @@ nar-obj-inner
|
||||
| str("type"), str("directory") directory
|
||||
;
|
||||
|
||||
regular = [ str("executable"), str("") ], str("contents"), str(contents);
|
||||
regular = [ str("executable") ], str("contents"), str(contents);
|
||||
|
||||
symlink = str("target"), str(target);
|
||||
|
||||
@@ -52,4 +52,4 @@ The Nix Archive (NAR) format is also formally described using [Kaitai Struct](ht
|
||||
{{#include nar.ksy}}
|
||||
```
|
||||
|
||||
The source of the spec can be found [here](https://github.com/nixos/nix/blob/master/src/nix-manual/source/protocols/nix-archive/nar.ksy). Contributions and improvements to the spec are welcomed.
|
||||
The source of the spec can be found [here](https://github.com/nixos/nix/blob/master/src/nix-manual/source/protocols/nix-archive/nar.ksy). Contributions and improvements to the spec are welcomed.
|
||||
@@ -3,23 +3,19 @@
|
||||
Nix uses a simplified model of the file system, which consists of file system objects.
|
||||
Every file system object is one of the following:
|
||||
|
||||
- [**Regular File**]{#regular}
|
||||
- File
|
||||
|
||||
- A possibly empty sequence of bytes for contents
|
||||
- A single boolean representing the [executable](https://en.m.wikipedia.org/wiki/File-system_permissions#Permissions) permission
|
||||
|
||||
- [**Directory**]{#directory}
|
||||
- Directory
|
||||
|
||||
Mapping of names to child file system objects
|
||||
|
||||
- [**Symbolic link**]{#symlink}
|
||||
- [Symbolic link](https://en.m.wikipedia.org/wiki/Symbolic_link)
|
||||
|
||||
An arbitrary string, known as the *target* of the symlink.
|
||||
|
||||
In general, Nix does not assign any semantics to symbolic links.
|
||||
Certain operations however, may make additional assumptions and attempt to use the target to find another file system object.
|
||||
|
||||
> See [the Wikpedia article on symbolic links](https://en.m.wikipedia.org/wiki/Symbolic_link) for background information if you are unfamiliar with this Unix concept.
|
||||
An arbitrary string.
|
||||
Nix does not assign any semantics to symbolic links.
|
||||
|
||||
File system objects and their children form a tree.
|
||||
A bare file or symlink can be a root file system object.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Secrets
|
||||
|
||||
The store is readable to all users on the system. For this reason, it
|
||||
is generally discouraged to allow secrets to make it into the store.
|
||||
|
||||
Even on a single-user system, separate system users isolate services
|
||||
from each other and having secrets that all local users can read
|
||||
weakens that isolation. When using external store caches the secrets
|
||||
may end up there, and on multi-user systems the secrets will be
|
||||
available to all those users.
|
||||
|
||||
Organize your derivations so that secrets are read from the filesystem
|
||||
(with appropriate access controls) at run time. Place the secrets on
|
||||
the filesystem manually or use a scheme that includes the secret in
|
||||
the store in encrypted form, and decrypts it adding the relevant
|
||||
access control on system activation.
|
||||
Several such schemes for NixOS can in the
|
||||
[comparison of secret managing schemes] on the wiki.
|
||||
|
||||
[comparison of secret managing schemes]: https://wiki.nixos.org/wiki/Comparison_of_secret_managing_schemes
|
||||
@@ -60,9 +60,4 @@ if get_option('unit-tests')
|
||||
subproject('libflake-tests')
|
||||
endif
|
||||
subproject('nix-functional-tests')
|
||||
if get_option('json-schema-checks')
|
||||
subproject('json-schema-checks')
|
||||
endif
|
||||
if get_option('kaitai-struct-checks')
|
||||
subproject('kaitai-struct-checks')
|
||||
endif
|
||||
subproject('json-schema-checks')
|
||||
|
||||
@@ -27,17 +27,3 @@ option(
|
||||
value : false,
|
||||
description : 'Build benchmarks (requires gbenchmark)',
|
||||
)
|
||||
|
||||
option(
|
||||
'kaitai-struct-checks',
|
||||
type : 'boolean',
|
||||
value : true,
|
||||
description : 'Check the Kaitai Struct specifications (requires Kaitai Struct)',
|
||||
)
|
||||
|
||||
option(
|
||||
'json-schema-checks',
|
||||
type : 'boolean',
|
||||
value : true,
|
||||
description : 'Check JSON schema validity of schemas and examples (requires jv)',
|
||||
)
|
||||
|
||||
@@ -3,118 +3,10 @@
|
||||
devFlake,
|
||||
}:
|
||||
|
||||
let
|
||||
# Some helper functions
|
||||
|
||||
/**
|
||||
Compute a filtered closure of build inputs.
|
||||
|
||||
Specifically, `buildInputsClosure cond startSet` computes the closure formed
|
||||
by recursive application of `p: filter cond p.buildInputs ++ filter cond p.propagatedBuildInputs`
|
||||
to `startSet`.
|
||||
|
||||
Example:
|
||||
```nix
|
||||
builtInputsClosure isInternal [ pkg1 pkg2 ]
|
||||
=> [ pkg1 pkg3 pkg2 pkg10 ]
|
||||
```
|
||||
|
||||
Note: order tbd
|
||||
|
||||
Note: `startSet` is *NOT* filtered.
|
||||
*/
|
||||
buildInputsClosureCond =
|
||||
cond: startSet:
|
||||
let
|
||||
closure = builtins.genericClosure {
|
||||
startSet = map (d: {
|
||||
key = d.drvPath;
|
||||
value = d;
|
||||
}) startSet;
|
||||
operator =
|
||||
d:
|
||||
let
|
||||
r =
|
||||
map
|
||||
(d': {
|
||||
key = d'.drvPath;
|
||||
value = d';
|
||||
})
|
||||
(
|
||||
lib.filter cond d.value.buildInputs or [ ] ++ lib.filter cond d.value.propagatedBuildInputs or [ ]
|
||||
);
|
||||
in
|
||||
r;
|
||||
};
|
||||
in
|
||||
map (item: item.value) closure;
|
||||
|
||||
/**
|
||||
`[ pkg1 pkg2 ]` -> `{ "...-pkg2.drv" = null; "...-pkg1.drv" = null }`
|
||||
|
||||
Note: fairly arbitrary order (hash based). Use for efficient set membership test only.
|
||||
*/
|
||||
byDrvPath =
|
||||
l:
|
||||
lib.listToAttrs (
|
||||
map (c: {
|
||||
name =
|
||||
# Just a lookup key
|
||||
builtins.unsafeDiscardStringContext c.drvPath;
|
||||
value = null;
|
||||
}) l
|
||||
);
|
||||
|
||||
/**
|
||||
Stable dedup.
|
||||
|
||||
Unlike `listToAttrs` -> `attrValues`, this preserves the input ordering,
|
||||
which is more predictable ("deterministic") than e.g. sorting store paths,
|
||||
whose hashes affect the ordering on every change.
|
||||
*/
|
||||
# TODO: add to Nixpkgs lib, refer from uniqueStrings
|
||||
dedupByString =
|
||||
key: l:
|
||||
let
|
||||
r =
|
||||
lib.foldl'
|
||||
(
|
||||
a@{ list, set }:
|
||||
elem:
|
||||
let
|
||||
k = builtins.unsafeDiscardStringContext (key elem);
|
||||
in
|
||||
if set ? ${k} then
|
||||
a
|
||||
else
|
||||
let
|
||||
# Note: O(n²) copying. Use linkedLists to concat them in one go at the end.
|
||||
# https://github.com/NixOS/nixpkgs/pull/452088
|
||||
newList = [ elem ] ++ list;
|
||||
newSet = set // {
|
||||
${k} = null;
|
||||
};
|
||||
in
|
||||
builtins.seq newList builtins.seq newSet {
|
||||
list = newList;
|
||||
set = newSet;
|
||||
}
|
||||
)
|
||||
{
|
||||
list = [ ];
|
||||
set = { };
|
||||
}
|
||||
l;
|
||||
in
|
||||
r.list;
|
||||
|
||||
in
|
||||
|
||||
{ pkgs }:
|
||||
|
||||
# TODO: don't use nix-util for this?
|
||||
pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
finalAttrs: prevAttrs:
|
||||
attrs:
|
||||
|
||||
let
|
||||
stdenv = pkgs.nixDependencies2.stdenv;
|
||||
@@ -129,93 +21,13 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
"-D${prefix}:${rest}";
|
||||
havePerl = stdenv.buildPlatform == stdenv.hostPlatform && stdenv.hostPlatform.isUnix;
|
||||
ignoreCrossFile = flags: builtins.filter (flag: !(lib.strings.hasInfix "cross-file" flag)) flags;
|
||||
|
||||
availableComponents = lib.filterAttrs (
|
||||
k: v: lib.meta.availableOn pkgs.hostPlatform v
|
||||
) allComponents;
|
||||
|
||||
activeComponents = buildInputsClosureCond isInternal (
|
||||
lib.attrValues (finalAttrs.passthru.config.getComponents availableComponents)
|
||||
);
|
||||
|
||||
allComponents = lib.filterAttrs (k: v: lib.isDerivation v) pkgs.nixComponents2;
|
||||
internalDrvs = byDrvPath (
|
||||
# Drop the attr names (not present in buildInputs anyway)
|
||||
lib.attrValues availableComponents
|
||||
++ lib.concatMap (c: lib.attrValues c.tests or { }) (lib.attrValues availableComponents)
|
||||
);
|
||||
|
||||
isInternal =
|
||||
dep: internalDrvs ? ${builtins.unsafeDiscardStringContext dep.drvPath or "_non-existent_"};
|
||||
|
||||
in
|
||||
{
|
||||
pname = "shell-for-nix";
|
||||
|
||||
passthru = {
|
||||
inherit activeComponents;
|
||||
|
||||
# We use this attribute to store non-derivation values like functions and
|
||||
# perhaps other things that are primarily for overriding and not the shell.
|
||||
config = {
|
||||
# Default getComponents
|
||||
getComponents =
|
||||
c:
|
||||
builtins.removeAttrs c (
|
||||
lib.optionals (!havePerl) [ "nix-perl-bindings" ]
|
||||
++ lib.optionals (!buildCanExecuteHost) [ "nix-manual" ]
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
Produce a devShell for a given set of nix components
|
||||
|
||||
Example:
|
||||
|
||||
```nix
|
||||
shell.withActiveComponents (c: {
|
||||
inherit (c) nix-util;
|
||||
})
|
||||
```
|
||||
*/
|
||||
withActiveComponents =
|
||||
f2:
|
||||
finalAttrs.finalPackage.overrideAttrs (
|
||||
finalAttrs: prevAttrs: {
|
||||
passthru = prevAttrs.passthru // {
|
||||
config = prevAttrs.passthru.config // {
|
||||
getComponents = f2;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
small =
|
||||
(finalAttrs.finalPackage.withActiveComponents (
|
||||
c:
|
||||
lib.intersectAttrs (lib.genAttrs [
|
||||
"nix-cli"
|
||||
"nix-util-tests"
|
||||
"nix-store-tests"
|
||||
"nix-expr-tests"
|
||||
"nix-fetchers-tests"
|
||||
"nix-flake-tests"
|
||||
"nix-functional-tests"
|
||||
"nix-perl-bindings"
|
||||
] (_: null)) c
|
||||
)).overrideAttrs
|
||||
(o: {
|
||||
mesonFlags = o.mesonFlags ++ [
|
||||
# TODO: infer from activeComponents or vice versa
|
||||
"-Dkaitai-struct-checks=false"
|
||||
"-Djson-schema-checks=false"
|
||||
];
|
||||
});
|
||||
};
|
||||
pname = "shell-for-" + attrs.pname;
|
||||
|
||||
# Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
|
||||
version = lib.fileContents ../.version;
|
||||
name = finalAttrs.pname;
|
||||
name = attrs.pname;
|
||||
|
||||
installFlags = "sysconfdir=$(out)/etc";
|
||||
shellHook = ''
|
||||
@@ -273,8 +85,6 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
CXX_LD = "mold";
|
||||
};
|
||||
|
||||
dontUseCmakeConfigure = true;
|
||||
|
||||
mesonFlags =
|
||||
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
|
||||
++ map (transformFlag "libstore") (ignoreCrossFile pkgs.nixComponents2.nix-store.mesonFlags)
|
||||
@@ -288,9 +98,17 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
nativeBuildInputs =
|
||||
let
|
||||
inputs =
|
||||
dedupByString (v: "${v}") (
|
||||
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.nativeBuildInputs) activeComponents)
|
||||
)
|
||||
attrs.nativeBuildInputs or [ ]
|
||||
++ pkgs.nixComponents2.nix-util.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-store.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-fetchers.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.nativeBuildInputs
|
||||
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.nativeBuildInputs
|
||||
++ lib.optionals buildCanExecuteHost pkgs.nixComponents2.nix-manual.externalNativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-internal-api-docs.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-external-api-docs.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-functional-tests.externalNativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-json-schema-checks.externalNativeBuildInputs
|
||||
++ lib.optional (
|
||||
!buildCanExecuteHost
|
||||
# Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479
|
||||
@@ -299,7 +117,9 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
&& lib.meta.availableOn stdenv.buildPlatform (stdenv.hostPlatform.emulator pkgs.buildPackages)
|
||||
) pkgs.buildPackages.mesonEmulatorHook
|
||||
++ [
|
||||
pkgs.buildPackages.cmake
|
||||
pkgs.buildPackages.gnused
|
||||
pkgs.buildPackages.changelog-d
|
||||
modular.pre-commit.settings.package
|
||||
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
|
||||
pkgs.buildPackages.nixfmt-rfc-style
|
||||
@@ -316,22 +136,18 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
# from making its way into NIX_CFLAGS_COMPILE.
|
||||
lib.filter (p: !lib.hasInfix "separate-debug-info" p) inputs;
|
||||
|
||||
propagatedNativeBuildInputs = dedupByString (v: "${v}") (
|
||||
lib.filter (x: !isInternal x) (
|
||||
lib.lists.concatMap (c: c.propagatedNativeBuildInputs) activeComponents
|
||||
)
|
||||
);
|
||||
|
||||
buildInputs = [
|
||||
pkgs.gbenchmark
|
||||
]
|
||||
++ dedupByString (v: "${v}") (
|
||||
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.buildInputs) activeComponents)
|
||||
)
|
||||
++ attrs.buildInputs or [ ]
|
||||
++ pkgs.nixComponents2.nix-util.buildInputs
|
||||
++ pkgs.nixComponents2.nix-store.buildInputs
|
||||
++ pkgs.nixComponents2.nix-store-tests.externalBuildInputs
|
||||
++ pkgs.nixComponents2.nix-fetchers.buildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.buildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.externalPropagatedBuildInputs
|
||||
++ pkgs.nixComponents2.nix-cmd.buildInputs
|
||||
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.externalBuildInputs
|
||||
++ lib.optional havePerl pkgs.perl;
|
||||
|
||||
propagatedBuildInputs = dedupByString (v: "${v}") (
|
||||
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.propagatedBuildInputs) activeComponents)
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../src/libutil-tests/data/memory-source-accessor
|
||||
@@ -20,14 +20,6 @@ schema_dir = meson.current_source_dir() / 'schema'
|
||||
|
||||
# Get all example files
|
||||
schemas = [
|
||||
{
|
||||
'stem' : 'file-system-object',
|
||||
'schema' : schema_dir / 'file-system-object-v1.yaml',
|
||||
'files' : [
|
||||
'simple.json',
|
||||
'complex.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
'stem' : 'hash',
|
||||
'schema' : schema_dir / 'hash-v1.yaml',
|
||||
|
||||
@@ -20,7 +20,6 @@ mkMesonDerivation (finalAttrs: {
|
||||
fileset = lib.fileset.unions [
|
||||
../../.version
|
||||
../../doc/manual/source/protocols/json/schema
|
||||
../../src/libutil-tests/data/memory-source-accessor
|
||||
../../src/libutil-tests/data/hash
|
||||
../../src/libstore-tests/data/content-address
|
||||
../../src/libstore-tests/data/store-path
|
||||
@@ -35,11 +34,15 @@ mkMesonDerivation (finalAttrs: {
|
||||
|
||||
outputs = [ "out" ];
|
||||
|
||||
passthru.externalNativeBuildInputs = [
|
||||
jsonschema
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
jsonschema
|
||||
];
|
||||
]
|
||||
++ finalAttrs.passthru.externalNativeBuildInputs;
|
||||
|
||||
doCheck = true;
|
||||
|
||||
|
||||
@@ -37,15 +37,7 @@ mkMesonDerivation (finalAttrs: {
|
||||
|
||||
outputs = [ "out" ];
|
||||
|
||||
buildInputs = [
|
||||
gtest
|
||||
kaitai-struct-cpp-stl-runtime
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
passthru.externalNativeBuildInputs = [
|
||||
# This can go away when we bump up to 25.11
|
||||
(kaitai-struct-compiler.overrideAttrs (finalAttrs: {
|
||||
version = "0.11";
|
||||
@@ -56,6 +48,20 @@ mkMesonDerivation (finalAttrs: {
|
||||
}))
|
||||
];
|
||||
|
||||
passthru.externalBuildInputs = [
|
||||
gtest
|
||||
kaitai-struct-cpp-stl-runtime
|
||||
];
|
||||
|
||||
buildInputs = finalAttrs.passthru.externalBuildInputs;
|
||||
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
]
|
||||
++ finalAttrs.passthru.externalNativeBuildInputs;
|
||||
|
||||
doCheck = true;
|
||||
|
||||
mesonCheckFlags = [ "--print-errorlogs" ];
|
||||
@@ -65,6 +71,6 @@ mkMesonDerivation (finalAttrs: {
|
||||
'';
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.unix;
|
||||
platforms = lib.platforms.all;
|
||||
};
|
||||
})
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "nix/cmd/command.hh"
|
||||
#include "nix/cmd/legacy.hh"
|
||||
#include "nix/cmd/markdown.hh"
|
||||
#include "nix/store/store-open.hh"
|
||||
#include "nix/store/local-fs-store.hh"
|
||||
@@ -15,18 +14,6 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
RegisterCommand::Commands & RegisterCommand::commands()
|
||||
{
|
||||
static RegisterCommand::Commands commands;
|
||||
return commands;
|
||||
}
|
||||
|
||||
RegisterLegacyCommand::Commands & RegisterLegacyCommand::commands()
|
||||
{
|
||||
static RegisterLegacyCommand::Commands commands;
|
||||
return commands;
|
||||
}
|
||||
|
||||
nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix)
|
||||
{
|
||||
nix::Commands res;
|
||||
|
||||
@@ -33,8 +33,7 @@ EvalSettings evalSettings{
|
||||
// FIXME `parseFlakeRef` should take a `std::string_view`.
|
||||
auto flakeRef = parseFlakeRef(fetchSettings, std::string{rest}, {}, true, false);
|
||||
debug("fetching flake search path element '%s''", rest);
|
||||
auto [accessor, lockedRef] =
|
||||
flakeRef.resolve(fetchSettings, *state.store).lazyFetch(fetchSettings, *state.store);
|
||||
auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store);
|
||||
auto storePath = nix::fetchToStore(
|
||||
state.fetchSettings,
|
||||
*state.store,
|
||||
@@ -168,9 +167,9 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
||||
? state.rootPath(absPath(getCommandBaseDir()))
|
||||
: state.rootPath(".")));
|
||||
},
|
||||
[&](const AutoArgString & arg) { v->mkString(arg.s, state.mem); },
|
||||
[&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string()), state.mem); },
|
||||
[&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO), state.mem); }},
|
||||
[&](const AutoArgString & arg) { v->mkString(arg.s); },
|
||||
[&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string())); },
|
||||
[&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO)); }},
|
||||
arg);
|
||||
res.insert(state.symbols.create(name), v);
|
||||
}
|
||||
@@ -180,7 +179,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * baseDir)
|
||||
{
|
||||
if (EvalSettings::isPseudoUrl(s)) {
|
||||
auto accessor = fetchers::downloadTarball(*state.store, state.fetchSettings, EvalSettings::resolvePseudoUrl(s));
|
||||
auto accessor = fetchers::downloadTarball(state.store, state.fetchSettings, EvalSettings::resolvePseudoUrl(s));
|
||||
auto storePath = fetchToStore(state.fetchSettings, *state.store, SourcePath(accessor), FetchMode::Copy);
|
||||
return state.storePath(storePath);
|
||||
}
|
||||
@@ -188,8 +187,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * bas
|
||||
else if (hasPrefix(s, "flake:")) {
|
||||
experimentalFeatureSettings.require(Xp::Flakes);
|
||||
auto flakeRef = parseFlakeRef(fetchSettings, std::string(s.substr(6)), {}, true, false);
|
||||
auto [accessor, lockedRef] =
|
||||
flakeRef.resolve(fetchSettings, *state.store).lazyFetch(fetchSettings, *state.store);
|
||||
auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store);
|
||||
auto storePath = nix::fetchToStore(
|
||||
state.fetchSettings, *state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName());
|
||||
state.allowPath(storePath);
|
||||
|
||||
@@ -286,7 +286,11 @@ struct RegisterCommand
|
||||
{
|
||||
typedef std::map<std::vector<std::string>, std::function<ref<Command>()>> Commands;
|
||||
|
||||
static Commands & commands();
|
||||
static Commands & commands()
|
||||
{
|
||||
static Commands commands;
|
||||
return commands;
|
||||
}
|
||||
|
||||
RegisterCommand(std::vector<std::string> && name, std::function<ref<Command>()> command)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,11 @@ struct RegisterLegacyCommand
|
||||
{
|
||||
typedef std::map<std::string, MainFunction> Commands;
|
||||
|
||||
static Commands & commands();
|
||||
static Commands & commands()
|
||||
{
|
||||
static Commands commands;
|
||||
return commands;
|
||||
}
|
||||
|
||||
RegisterLegacyCommand(const std::string & name, MainFunction fun)
|
||||
{
|
||||
|
||||
@@ -409,7 +409,7 @@ void completeFlakeRef(AddCompletions & completions, ref<Store> store, std::strin
|
||||
Args::completeDir(completions, 0, prefix);
|
||||
|
||||
/* Look for registry entries that match the prefix. */
|
||||
for (auto & registry : fetchers::getRegistries(fetchSettings, *store)) {
|
||||
for (auto & registry : fetchers::getRegistries(fetchSettings, store)) {
|
||||
for (auto & entry : registry->entries) {
|
||||
auto from = entry.from.to_string();
|
||||
if (!hasPrefix(prefix, "flake:") && hasPrefix(from, "flake:")) {
|
||||
|
||||
@@ -738,8 +738,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||
}
|
||||
|
||||
auto flakeRef = parseFlakeRef(fetchSettings, flakeRefS, cwd.string(), true);
|
||||
if (evalSettings.pureEval && !flakeRef.input.isLocked(fetchSettings))
|
||||
throw Error("cannot use ':load-flake' on unlocked flake reference '%s' (use --impure to override)", flakeRefS);
|
||||
if (evalSettings.pureEval && !flakeRef.input.isLocked())
|
||||
throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS);
|
||||
|
||||
Value v;
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ nix_err nix_expr_eval_from_string(
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
|
||||
state->state.eval(parsedExpr, *value->value);
|
||||
state->state.forceValue(*value->value, nix::noPos);
|
||||
state->state.eval(parsedExpr, value->value);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -80,8 +80,8 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, n
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.callFunction(*fn->value, *arg->value, *value->value, nix::noPos);
|
||||
state->state.forceValue(*value->value, nix::noPos);
|
||||
state->state.callFunction(fn->value, arg->value, value->value, nix::noPos);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -91,15 +91,9 @@ nix_err nix_value_call_multi(
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
||||
std::vector<nix::Value *> internal_args;
|
||||
internal_args.reserve(nargs);
|
||||
for (size_t i = 0; i < nargs; i++)
|
||||
internal_args.push_back(args[i]->value);
|
||||
|
||||
try {
|
||||
state->state.callFunction(*fn->value, {internal_args.data(), nargs}, *value->value, nix::noPos);
|
||||
state->state.forceValue(*value->value, nix::noPos);
|
||||
state->state.callFunction(fn->value, {(nix::Value **) args, nargs}, value->value, nix::noPos);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -109,7 +103,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value *
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.forceValue(*value->value, nix::noPos);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -119,7 +113,7 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.forceValueDeep(*value->value);
|
||||
state->state.forceValueDeep(value->value);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -143,8 +137,6 @@ nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Sto
|
||||
|
||||
void nix_eval_state_builder_free(nix_eval_state_builder * builder)
|
||||
{
|
||||
if (builder)
|
||||
builder->~nix_eval_state_builder();
|
||||
operator delete(builder, static_cast<std::align_val_t>(alignof(nix_eval_state_builder)));
|
||||
}
|
||||
|
||||
@@ -211,8 +203,6 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
|
||||
|
||||
void nix_state_free(EvalState * state)
|
||||
{
|
||||
if (state)
|
||||
state->~EvalState();
|
||||
operator delete(state, static_cast<std::align_val_t>(alignof(EvalState)));
|
||||
}
|
||||
|
||||
|
||||
@@ -39,13 +39,7 @@ struct ListBuilder
|
||||
|
||||
struct nix_value
|
||||
{
|
||||
nix::Value * value;
|
||||
/**
|
||||
* As we move to a managed heap, we need EvalMemory in more places. Ideally, we would take in EvalState or
|
||||
* EvalMemory as an argument when we need it, but we don't want to make changes to the stable C api, so we stuff it
|
||||
* into the nix_value that will get passed in to the relevant functions.
|
||||
*/
|
||||
nix::EvalMemory * mem;
|
||||
nix::Value value;
|
||||
};
|
||||
|
||||
struct nix_string_return
|
||||
|
||||
@@ -20,7 +20,7 @@ static const nix::Value & check_value_not_null(const nix_value * value)
|
||||
if (!value) {
|
||||
throw std::runtime_error("nix_value is null");
|
||||
}
|
||||
return *value->value;
|
||||
return *((const nix::Value *) value);
|
||||
}
|
||||
|
||||
static nix::Value & check_value_not_null(nix_value * value)
|
||||
@@ -28,7 +28,7 @@ static nix::Value & check_value_not_null(nix_value * value)
|
||||
if (!value) {
|
||||
throw std::runtime_error("nix_value is null");
|
||||
}
|
||||
return *value->value;
|
||||
return value->value;
|
||||
}
|
||||
|
||||
static const nix::Value & check_value_in(const nix_value * value)
|
||||
@@ -58,14 +58,9 @@ static nix::Value & check_value_out(nix_value * value)
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline nix_value * new_nix_value(nix::Value * v, nix::EvalMemory & mem)
|
||||
static inline nix_value * as_nix_value_ptr(nix::Value * v)
|
||||
{
|
||||
nix_value * ret = new (mem.allocBytes(sizeof(nix_value))) nix_value{
|
||||
.value = v,
|
||||
.mem = &mem,
|
||||
};
|
||||
nix_gc_incref(nullptr, ret);
|
||||
return ret;
|
||||
return reinterpret_cast<nix_value *>(v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,13 +69,7 @@ static inline nix_value * new_nix_value(nix::Value * v, nix::EvalMemory & mem)
|
||||
* Deals with errors and converts arguments from C++ into C types.
|
||||
*/
|
||||
static void nix_c_primop_wrapper(
|
||||
PrimOpFun f,
|
||||
void * userdata,
|
||||
int arity,
|
||||
nix::EvalState & state,
|
||||
const nix::PosIdx pos,
|
||||
nix::Value ** args,
|
||||
nix::Value & v)
|
||||
PrimOpFun f, void * userdata, nix::EvalState & state, const nix::PosIdx pos, nix::Value ** args, nix::Value & v)
|
||||
{
|
||||
nix_c_context ctx;
|
||||
|
||||
@@ -96,15 +85,8 @@ static void nix_c_primop_wrapper(
|
||||
// ok because we don't see a need for this yet (e.g. inspecting thunks,
|
||||
// or maybe something to make blackholes work better; we don't know).
|
||||
nix::Value vTmp;
|
||||
nix_value * vTmpPtr = new_nix_value(&vTmp, state.mem);
|
||||
|
||||
std::vector<nix_value *> external_args;
|
||||
external_args.reserve(arity);
|
||||
for (int i = 0; i < arity; i++) {
|
||||
nix_value * external_arg = new_nix_value(args[i], state.mem);
|
||||
external_args.push_back(external_arg);
|
||||
}
|
||||
f(userdata, &ctx, (EvalState *) &state, external_args.data(), vTmpPtr);
|
||||
f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp);
|
||||
|
||||
if (ctx.last_err_code != NIX_OK) {
|
||||
/* TODO: Throw different errors depending on the error code */
|
||||
@@ -153,7 +135,7 @@ PrimOp * nix_alloc_primop(
|
||||
.args = {},
|
||||
.arity = (size_t) arity,
|
||||
.doc = doc,
|
||||
.fun = std::bind(nix_c_primop_wrapper, fun, user_data, arity, _1, _2, _3, _4)};
|
||||
.fun = std::bind(nix_c_primop_wrapper, fun, user_data, _1, _2, _3, _4)};
|
||||
if (args)
|
||||
for (size_t i = 0; args[i]; i++)
|
||||
p->args.emplace_back(*args);
|
||||
@@ -178,7 +160,8 @@ nix_value * nix_alloc_value(nix_c_context * context, EvalState * state)
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
nix_value * res = new_nix_value(state->state.allocValue(), state->state.mem);
|
||||
nix_value * res = as_nix_value_ptr(state->state.allocValue());
|
||||
nix_gc_incref(nullptr, res);
|
||||
return res;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
@@ -348,10 +331,10 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
|
||||
return nullptr;
|
||||
}
|
||||
auto * p = v.listView()[ix];
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
state->state.forceValue(*p, nix::noPos);
|
||||
return new_nix_value(p, state->state.mem);
|
||||
nix_gc_incref(nullptr, p);
|
||||
if (p != nullptr)
|
||||
state->state.forceValue(*p, nix::noPos);
|
||||
return as_nix_value_ptr(p);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
@@ -369,8 +352,9 @@ nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalSt
|
||||
return nullptr;
|
||||
}
|
||||
auto * p = v.listView()[ix];
|
||||
nix_gc_incref(nullptr, p);
|
||||
// Note: intentionally NOT calling forceValue() to keep the element lazy
|
||||
return new_nix_value(p, state->state.mem);
|
||||
return as_nix_value_ptr(p);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
@@ -385,8 +369,9 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
|
||||
nix::Symbol s = state->state.symbols.create(name);
|
||||
auto attr = v.attrs()->get(s);
|
||||
if (attr) {
|
||||
nix_gc_incref(nullptr, attr->value);
|
||||
state->state.forceValue(*attr->value, nix::noPos);
|
||||
return new_nix_value(attr->value, state->state.mem);
|
||||
return as_nix_value_ptr(attr->value);
|
||||
}
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
|
||||
return nullptr;
|
||||
@@ -405,8 +390,9 @@ nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalS
|
||||
nix::Symbol s = state->state.symbols.create(name);
|
||||
auto attr = v.attrs()->get(s);
|
||||
if (attr) {
|
||||
nix_gc_incref(nullptr, attr->value);
|
||||
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
|
||||
return new_nix_value(attr->value, state->state.mem);
|
||||
return as_nix_value_ptr(attr->value);
|
||||
}
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
|
||||
return nullptr;
|
||||
@@ -454,8 +440,9 @@ nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state
|
||||
}
|
||||
const nix::Attr & a = (*v.attrs())[i];
|
||||
*name = state->state.symbols[a.name].c_str();
|
||||
nix_gc_incref(nullptr, a.value);
|
||||
state->state.forceValue(*a.value, nix::noPos);
|
||||
return new_nix_value(a.value, state->state.mem);
|
||||
return as_nix_value_ptr(a.value);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
@@ -474,8 +461,9 @@ nix_value * nix_get_attr_byidx_lazy(
|
||||
}
|
||||
const nix::Attr & a = (*v.attrs())[i];
|
||||
*name = state->state.symbols[a.name].c_str();
|
||||
nix_gc_incref(nullptr, a.value);
|
||||
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
|
||||
return new_nix_value(a.value, state->state.mem);
|
||||
return as_nix_value_ptr(a.value);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
@@ -515,7 +503,7 @@ nix_err nix_init_string(nix_c_context * context, nix_value * value, const char *
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_out(value);
|
||||
v.mkString(std::string_view(str), *value->mem);
|
||||
v.mkString(std::string_view(str));
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -526,7 +514,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value *
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_out(value);
|
||||
v.mkPath(s->state.rootPath(nix::CanonPath(str)), s->state.mem);
|
||||
v.mkPath(s->state.rootPath(nix::CanonPath(str)));
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ TEST_F(JSONValueTest, StringQuotes)
|
||||
TEST_F(JSONValueTest, DISABLED_Path)
|
||||
{
|
||||
Value v;
|
||||
v.mkPath(state.rootPath(CanonPath("/test")), state.mem);
|
||||
v.mkPath(state.rootPath(CanonPath("/test")));
|
||||
ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\"");
|
||||
}
|
||||
} /* namespace nix */
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_eval_state_lookup_path)
|
||||
TEST_F(nix_api_store_test, nix_eval_state_lookup_path)
|
||||
{
|
||||
auto tmpDir = nix::createTempDir();
|
||||
auto delTmpDir = std::make_unique<nix::AutoDelete>(tmpDir, true);
|
||||
@@ -42,16 +42,12 @@ TEST_F(nix_api_expr_test, nix_eval_state_lookup_path)
|
||||
nix_expr_eval_from_string(ctx, state, "builtins.seq <nixos-config> <nixpkgs>", ".", value);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_state_free(state);
|
||||
|
||||
ASSERT_EQ(nix_get_type(ctx, value), NIX_TYPE_PATH);
|
||||
assert_ctx_ok();
|
||||
|
||||
auto pathStr = nix_get_path_string(ctx, value);
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(0, strcmp(pathStr, nixpkgs.c_str()));
|
||||
|
||||
nix_gc_decref(nullptr, value);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_eval_from_string)
|
||||
|
||||
@@ -661,14 +661,8 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
CASE(R"(null)", ""),
|
||||
CASE(R"({ v = "bar"; __toString = self: self.v; })", "bar"),
|
||||
CASE(R"({ v = "bar"; __toString = self: self.v; outPath = "foo"; })", "bar"),
|
||||
CASE(R"({ outPath = "foo"; })", "foo")
|
||||
// this is broken on cygwin because canonPath("//./test", false) returns //./test
|
||||
// FIXME: don't use canonPath
|
||||
#ifndef __CYGWIN__
|
||||
,
|
||||
CASE(R"(./test)", "/test")
|
||||
#endif
|
||||
));
|
||||
CASE(R"({ outPath = "foo"; })", "foo"),
|
||||
CASE(R"(./test)", "/test")));
|
||||
#undef CASE
|
||||
|
||||
TEST_F(PrimOpTest, substring)
|
||||
|
||||
@@ -268,7 +268,7 @@ struct StringPrintingTests : LibExprTest
|
||||
void test(std::string_view literal, std::string_view expected, unsigned int maxLength, A... args)
|
||||
{
|
||||
Value v;
|
||||
v.mkString(literal, state.mem);
|
||||
v.mkString(literal);
|
||||
|
||||
std::stringstream out;
|
||||
printValue(state, out, v, PrintOptions{.maxStringLength = maxLength});
|
||||
@@ -353,7 +353,7 @@ TEST_F(ValuePrintingTests, ansiColorsStringElided)
|
||||
TEST_F(ValuePrintingTests, ansiColorsPath)
|
||||
{
|
||||
Value v;
|
||||
v.mkPath(state.rootPath(CanonPath("puppy")), state.mem);
|
||||
v.mkPath(state.rootPath(CanonPath("puppy")));
|
||||
|
||||
test(v, ANSI_GREEN "/puppy" ANSI_NORMAL, PrintOptions{.ansiColors = true});
|
||||
}
|
||||
|
||||
@@ -81,20 +81,20 @@ static const char * makeImmutableString(std::string_view s)
|
||||
return t;
|
||||
}
|
||||
|
||||
StringData & StringData::alloc(EvalMemory & mem, size_t size)
|
||||
StringData & StringData::alloc(size_t size)
|
||||
{
|
||||
void * t = mem.allocBytes(sizeof(StringData) + size + 1);
|
||||
void * t = GC_MALLOC_ATOMIC(sizeof(StringData) + size + 1);
|
||||
if (!t)
|
||||
throw std::bad_alloc();
|
||||
auto res = new (t) StringData(size);
|
||||
return *res;
|
||||
}
|
||||
|
||||
const StringData & StringData::make(EvalMemory & mem, std::string_view s)
|
||||
const StringData & StringData::make(std::string_view s)
|
||||
{
|
||||
if (s.empty())
|
||||
return ""_sds;
|
||||
auto & res = alloc(mem, s.size());
|
||||
auto & res = alloc(s.size());
|
||||
std::memcpy(&res.data_, s.data(), s.size());
|
||||
res.data_[s.size()] = '\0';
|
||||
return res;
|
||||
@@ -205,7 +205,7 @@ bool Value::isTrivial() const
|
||||
{
|
||||
return !isa<tApp, tPrimOpApp>()
|
||||
&& (!isa<tThunk>()
|
||||
|| (dynamic_cast<ExprAttrs *>(thunk().expr) && ((ExprAttrs *) thunk().expr)->dynamicAttrs->empty())
|
||||
|| (dynamic_cast<ExprAttrs *>(thunk().expr) && ((ExprAttrs *) thunk().expr)->dynamicAttrs.empty())
|
||||
|| dynamic_cast<ExprLambda *>(thunk().expr) || dynamic_cast<ExprList *>(thunk().expr));
|
||||
}
|
||||
|
||||
@@ -517,16 +517,15 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
|
||||
if (primOp.arity == 0) {
|
||||
primOp.arity = 1;
|
||||
auto vPrimOp = allocValue();
|
||||
vPrimOp->mkPrimOp(new PrimOp(std::move(primOp)));
|
||||
vPrimOp->mkPrimOp(new PrimOp(primOp));
|
||||
Value v;
|
||||
v.mkApp(vPrimOp, vPrimOp);
|
||||
auto & primOp1 = *vPrimOp->primOp();
|
||||
return addConstant(
|
||||
primOp1.name,
|
||||
primOp.name,
|
||||
v,
|
||||
{
|
||||
.type = nThunk, // FIXME
|
||||
.doc = primOp1.doc ? primOp1.doc->c_str() : nullptr,
|
||||
.doc = primOp.doc,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -566,14 +565,13 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||
{
|
||||
if (v.isPrimOp()) {
|
||||
auto v2 = &v;
|
||||
auto & primOp = *v2->primOp();
|
||||
if (primOp.doc)
|
||||
if (auto * doc = v2->primOp()->doc)
|
||||
return Doc{
|
||||
.pos = {},
|
||||
.name = primOp.name,
|
||||
.arity = primOp.arity,
|
||||
.args = primOp.args,
|
||||
.doc = primOp.doc->c_str(),
|
||||
.name = v2->primOp()->name,
|
||||
.arity = v2->primOp()->arity,
|
||||
.args = v2->primOp()->args,
|
||||
.doc = doc,
|
||||
};
|
||||
}
|
||||
if (v.isLambda()) {
|
||||
@@ -849,36 +847,35 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t)
|
||||
evalState.runDebugRepl(nullptr, trace.env, trace.expr);
|
||||
}
|
||||
|
||||
void Value::mkString(std::string_view s, EvalMemory & mem)
|
||||
void Value::mkString(std::string_view s)
|
||||
{
|
||||
mkStringNoCopy(StringData::make(mem, s));
|
||||
mkStringNoCopy(StringData::make(s));
|
||||
}
|
||||
|
||||
Value::StringWithContext::Context *
|
||||
Value::StringWithContext::Context::fromBuilder(const NixStringContext & context, EvalMemory & mem)
|
||||
Value::StringWithContext::Context * Value::StringWithContext::Context::fromBuilder(const NixStringContext & context)
|
||||
{
|
||||
if (context.empty())
|
||||
return nullptr;
|
||||
|
||||
auto ctx = new (mem.allocBytes(sizeof(Context) + context.size() * sizeof(value_type))) Context(context.size());
|
||||
auto ctx = new (allocBytes(sizeof(Context) + context.size() * sizeof(value_type))) Context(context.size());
|
||||
std::ranges::transform(
|
||||
context, ctx->elems, [&](const NixStringContextElem & elt) { return &StringData::make(mem, elt.to_string()); });
|
||||
context, ctx->elems, [](const NixStringContextElem & elt) { return &StringData::make(elt.to_string()); });
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void Value::mkString(std::string_view s, const NixStringContext & context, EvalMemory & mem)
|
||||
void Value::mkString(std::string_view s, const NixStringContext & context)
|
||||
{
|
||||
mkStringNoCopy(StringData::make(mem, s), Value::StringWithContext::Context::fromBuilder(context, mem));
|
||||
mkStringNoCopy(StringData::make(s), Value::StringWithContext::Context::fromBuilder(context));
|
||||
}
|
||||
|
||||
void Value::mkStringMove(const StringData & s, const NixStringContext & context, EvalMemory & mem)
|
||||
void Value::mkStringMove(const StringData & s, const NixStringContext & context)
|
||||
{
|
||||
mkStringNoCopy(s, Value::StringWithContext::Context::fromBuilder(context, mem));
|
||||
mkStringNoCopy(s, Value::StringWithContext::Context::fromBuilder(context));
|
||||
}
|
||||
|
||||
void Value::mkPath(const SourcePath & path, EvalMemory & mem)
|
||||
void Value::mkPath(const SourcePath & path)
|
||||
{
|
||||
mkPath(&*path.accessor, StringData::make(mem, path.path.abs()));
|
||||
mkPath(&*path.accessor, StringData::make(path.path.abs()));
|
||||
}
|
||||
|
||||
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
@@ -914,9 +911,9 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
}
|
||||
}
|
||||
|
||||
ListBuilder::ListBuilder(EvalMemory & mem, size_t size)
|
||||
ListBuilder::ListBuilder(size_t size)
|
||||
: size(size)
|
||||
, elems(size <= 2 ? inlineElems : (Value **) mem.allocBytes(size * sizeof(Value *)))
|
||||
, elems(size <= 2 ? inlineElems : (Value **) allocBytes(size * sizeof(Value *)))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -943,7 +940,7 @@ void EvalState::mkPos(Value & v, PosIdx p)
|
||||
auto origin = positions.originOf(p);
|
||||
if (auto path = std::get_if<SourcePath>(&origin)) {
|
||||
auto attrs = buildBindings(3);
|
||||
attrs.alloc(s.file).mkString(path->path.abs(), mem);
|
||||
attrs.alloc(s.file).mkString(path->path.abs());
|
||||
makePositionThunks(*this, p, attrs.alloc(s.line), attrs.alloc(s.column));
|
||||
v.mkAttrs(attrs);
|
||||
} else
|
||||
@@ -956,8 +953,7 @@ void EvalState::mkStorePathString(const StorePath & p, Value & v)
|
||||
store->printStorePath(p),
|
||||
NixStringContext{
|
||||
NixStringContextElem::Opaque{.path = p},
|
||||
},
|
||||
mem);
|
||||
});
|
||||
}
|
||||
|
||||
std::string EvalState::mkOutputStringRaw(
|
||||
@@ -979,7 +975,7 @@ void EvalState::mkOutputString(
|
||||
std::optional<StorePath> optStaticOutputPath,
|
||||
const ExperimentalFeatureSettings & xpSettings)
|
||||
{
|
||||
value.mkString(mkOutputStringRaw(b, optStaticOutputPath, xpSettings), NixStringContext{b}, mem);
|
||||
value.mkString(mkOutputStringRaw(b, optStaticOutputPath, xpSettings), NixStringContext{b});
|
||||
}
|
||||
|
||||
std::string EvalState::mkSingleDerivedPathStringRaw(const SingleDerivedPath & p)
|
||||
@@ -1014,8 +1010,7 @@ void EvalState::mkSingleDerivedPathString(const SingleDerivedPath & p, Value & v
|
||||
mkSingleDerivedPathStringRaw(p),
|
||||
NixStringContext{
|
||||
std::visit([](auto && v) -> NixStringContextElem { return v; }, p),
|
||||
},
|
||||
mem);
|
||||
});
|
||||
}
|
||||
|
||||
Value * Expr::maybeThunk(EvalState & state, Env & env)
|
||||
@@ -1226,26 +1221,26 @@ Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
|
||||
|
||||
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
auto bindings = state.buildBindings(attrs->size() + dynamicAttrs->size());
|
||||
auto bindings = state.buildBindings(attrs.size() + dynamicAttrs.size());
|
||||
auto dynamicEnv = &env;
|
||||
bool sort = false;
|
||||
|
||||
if (recursive) {
|
||||
/* Create a new environment that contains the attributes in
|
||||
this `rec'. */
|
||||
Env & env2(state.mem.allocEnv(attrs->size()));
|
||||
Env & env2(state.mem.allocEnv(attrs.size()));
|
||||
env2.up = &env;
|
||||
dynamicEnv = &env2;
|
||||
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env2) : nullptr;
|
||||
|
||||
AttrDefs::iterator overrides = attrs->find(state.s.overrides);
|
||||
bool hasOverrides = overrides != attrs->end();
|
||||
AttrDefs::iterator overrides = attrs.find(state.s.overrides);
|
||||
bool hasOverrides = overrides != attrs.end();
|
||||
|
||||
/* The recursive attributes are evaluated in the new
|
||||
environment, while the inherited attributes are evaluated
|
||||
in the original environment. */
|
||||
Displacement displ = 0;
|
||||
for (auto & i : *attrs) {
|
||||
for (auto & i : attrs) {
|
||||
Value * vAttr;
|
||||
if (hasOverrides && i.second.kind != AttrDef::Kind::Inherited) {
|
||||
vAttr = state.allocValue();
|
||||
@@ -1272,8 +1267,8 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
"while evaluating the `__overrides` attribute");
|
||||
bindings.grow(state.buildBindings(bindings.capacity() + vOverrides->attrs()->size()));
|
||||
for (auto & i : *vOverrides->attrs()) {
|
||||
AttrDefs::iterator j = attrs->find(i.name);
|
||||
if (j != attrs->end()) {
|
||||
AttrDefs::iterator j = attrs.find(i.name);
|
||||
if (j != attrs.end()) {
|
||||
(*bindings.bindings)[j->second.displ] = i;
|
||||
env2.values[j->second.displ] = i.value;
|
||||
} else
|
||||
@@ -1285,13 +1280,13 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
else {
|
||||
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env) : nullptr;
|
||||
for (auto & i : *attrs)
|
||||
for (auto & i : attrs)
|
||||
bindings.insert(
|
||||
i.first, i.second.e->maybeThunk(state, *i.second.chooseByKind(&env, &env, inheritEnv)), i.second.pos);
|
||||
}
|
||||
|
||||
/* Dynamic attrs apply *after* rec and __overrides. */
|
||||
for (auto & i : *dynamicAttrs) {
|
||||
for (auto & i : dynamicAttrs) {
|
||||
Value nameVal;
|
||||
i.nameExpr->eval(state, *dynamicEnv, nameVal);
|
||||
state.forceValue(nameVal, i.pos);
|
||||
@@ -1325,7 +1320,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
/* Create a new environment that contains the attributes in this
|
||||
`let'. */
|
||||
Env & env2(state.mem.allocEnv(attrs->attrs->size()));
|
||||
Env & env2(state.mem.allocEnv(attrs->attrs.size()));
|
||||
env2.up = &env;
|
||||
|
||||
Env * inheritEnv = attrs->inheritFromExprs ? attrs->buildInheritFromEnv(state, env2) : nullptr;
|
||||
@@ -1334,7 +1329,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||
while the inherited attributes are evaluated in the original
|
||||
environment. */
|
||||
Displacement displ = 0;
|
||||
for (auto & i : *attrs->attrs) {
|
||||
for (auto & i : attrs->attrs) {
|
||||
env2.values[displ++] = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, inheritEnv));
|
||||
}
|
||||
|
||||
@@ -1751,9 +1746,9 @@ void ExprCall::eval(EvalState & state, Env & env, Value & v)
|
||||
// 4: about 60
|
||||
// 5: under 10
|
||||
// This excluded attrset lambdas (`{...}:`). Contributions of mixed lambdas appears insignificant at ~150 total.
|
||||
SmallValueVector<4> vArgs(args->size());
|
||||
for (size_t i = 0; i < args->size(); ++i)
|
||||
vArgs[i] = (*args)[i]->maybeThunk(state, env);
|
||||
SmallValueVector<4> vArgs(args.size());
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
vArgs[i] = args[i]->maybeThunk(state, env);
|
||||
|
||||
state.callFunction(vFun, vArgs, v, pos);
|
||||
}
|
||||
@@ -2139,16 +2134,16 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
for (const auto & part : strings) {
|
||||
resultStr += *part;
|
||||
}
|
||||
v.mkPath(state.rootPath(CanonPath(resultStr)), state.mem);
|
||||
v.mkPath(state.rootPath(CanonPath(resultStr)));
|
||||
} else {
|
||||
auto & resultStr = StringData::alloc(state.mem, sSize);
|
||||
auto & resultStr = StringData::alloc(sSize);
|
||||
auto * tmp = resultStr.data();
|
||||
for (const auto & part : strings) {
|
||||
std::memcpy(tmp, part->data(), part->size());
|
||||
tmp += part->size();
|
||||
}
|
||||
*tmp = '\0';
|
||||
v.mkStringMove(resultStr, context, state.mem);
|
||||
v.mkStringMove(resultStr, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2188,8 +2183,6 @@ void EvalState::forceValueDeep(Value & v)
|
||||
std::set<const Value *> seen;
|
||||
|
||||
[&, &state(*this)](this const auto & recurse, Value & v) {
|
||||
auto _level = state.addCallDepth(v.determinePos(noPos));
|
||||
|
||||
if (!seen.insert(&v).second)
|
||||
return;
|
||||
|
||||
@@ -2216,15 +2209,8 @@ void EvalState::forceValueDeep(Value & v)
|
||||
}
|
||||
|
||||
else if (v.isList()) {
|
||||
size_t index = 0;
|
||||
for (auto v2 : v.listView())
|
||||
try {
|
||||
recurse(*v2);
|
||||
index++;
|
||||
} catch (Error & e) {
|
||||
state.addErrorTrace(e, "while evaluating list element at index %1%", index);
|
||||
throw;
|
||||
}
|
||||
recurse(*v2);
|
||||
}
|
||||
}(v);
|
||||
}
|
||||
@@ -2354,7 +2340,7 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos, std::s
|
||||
error<EvalError>(
|
||||
"the string '%1%' is not allowed to refer to a store path (such as '%2%')",
|
||||
v.string_view(),
|
||||
(*v.context()->begin())->view())
|
||||
*v.context()->begin())
|
||||
.withTrace(pos, errorCtx)
|
||||
.debugThrow();
|
||||
}
|
||||
@@ -3199,7 +3185,7 @@ std::optional<SourcePath> EvalState::resolveLookupPathPath(const LookupPath::Pat
|
||||
|
||||
if (EvalSettings::isPseudoUrl(value)) {
|
||||
try {
|
||||
auto accessor = fetchers::downloadTarball(*store, fetchSettings, EvalSettings::resolvePseudoUrl(value));
|
||||
auto accessor = fetchers::downloadTarball(store, fetchSettings, EvalSettings::resolvePseudoUrl(value));
|
||||
auto storePath = fetchToStore(fetchSettings, *store, SourcePath(accessor), FetchMode::Copy);
|
||||
return finish(this->storePath(storePath));
|
||||
} catch (Error & e) {
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace nix {
|
||||
* Note: Various places expect the allocated memory to be zeroed.
|
||||
*/
|
||||
[[gnu::always_inline]]
|
||||
inline void * EvalMemory::allocBytes(size_t n)
|
||||
inline void * allocBytes(size_t n)
|
||||
{
|
||||
void * p;
|
||||
#if NIX_USE_BOEHMGC
|
||||
|
||||
@@ -108,7 +108,7 @@ struct PrimOp
|
||||
/**
|
||||
* Optional free-form documentation about the primop.
|
||||
*/
|
||||
std::optional<std::string> doc;
|
||||
const char * doc = nullptr;
|
||||
|
||||
/**
|
||||
* Add a trace item, while calling the `<name>` builtin.
|
||||
@@ -335,7 +335,6 @@ public:
|
||||
EvalMemory & operator=(const EvalMemory &) = delete;
|
||||
EvalMemory & operator=(EvalMemory &&) = delete;
|
||||
|
||||
inline void * allocBytes(size_t n);
|
||||
inline Value * allocValue();
|
||||
inline Env & allocEnv(size_t size);
|
||||
|
||||
@@ -349,7 +348,7 @@ public:
|
||||
ListBuilder buildList(size_t size)
|
||||
{
|
||||
stats.nrListElems += size;
|
||||
return ListBuilder(*this, size);
|
||||
return ListBuilder(size);
|
||||
}
|
||||
|
||||
const Statistics & getStats() const &
|
||||
|
||||
@@ -339,7 +339,7 @@ struct ExprOpHasAttr : Expr
|
||||
Expr * e;
|
||||
std::span<AttrName> attrPath;
|
||||
|
||||
ExprOpHasAttr(std::pmr::polymorphic_allocator<char> & alloc, Expr * e, std::span<AttrName> attrPath)
|
||||
ExprOpHasAttr(std::pmr::polymorphic_allocator<char> & alloc, Expr * e, std::vector<AttrName> attrPath)
|
||||
: e(e)
|
||||
, attrPath({alloc.allocate_object<AttrName>(attrPath.size()), attrPath.size()})
|
||||
{
|
||||
@@ -395,13 +395,9 @@ struct ExprAttrs : Expr
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::pmr::map<Symbol, AttrDef> AttrDefs;
|
||||
/**
|
||||
* attrs will never be null. we use std::optional so that we can call emplace() to re-initialize the value with a
|
||||
* new pmr::map using a different allocator (move assignment will copy into the old allocator)
|
||||
*/
|
||||
std::optional<AttrDefs> attrs;
|
||||
std::unique_ptr<std::pmr::vector<Expr *>> inheritFromExprs;
|
||||
typedef std::map<Symbol, AttrDef> AttrDefs;
|
||||
AttrDefs attrs;
|
||||
std::unique_ptr<std::vector<Expr *>> inheritFromExprs;
|
||||
|
||||
struct DynamicAttrDef
|
||||
{
|
||||
@@ -413,20 +409,13 @@ struct ExprAttrs : Expr
|
||||
, pos(pos) {};
|
||||
};
|
||||
|
||||
typedef std::pmr::vector<DynamicAttrDef> DynamicAttrDefs;
|
||||
/**
|
||||
* dynamicAttrs will never be null. See comment on AttrDefs above.
|
||||
*/
|
||||
std::optional<DynamicAttrDefs> dynamicAttrs;
|
||||
typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
|
||||
DynamicAttrDefs dynamicAttrs;
|
||||
ExprAttrs(const PosIdx & pos)
|
||||
: recursive(false)
|
||||
, pos(pos)
|
||||
, attrs(AttrDefs{})
|
||||
, dynamicAttrs(DynamicAttrDefs{}) {};
|
||||
, pos(pos) {};
|
||||
ExprAttrs()
|
||||
: recursive(false)
|
||||
, attrs(AttrDefs{})
|
||||
, dynamicAttrs(DynamicAttrDefs{}) {};
|
||||
: recursive(false) {};
|
||||
|
||||
PosIdx getPos() const override
|
||||
{
|
||||
@@ -444,7 +433,7 @@ struct ExprList : Expr
|
||||
{
|
||||
std::span<Expr *> elems;
|
||||
|
||||
ExprList(std::pmr::polymorphic_allocator<char> & alloc, std::span<Expr *> exprs)
|
||||
ExprList(std::pmr::polymorphic_allocator<char> & alloc, std::vector<Expr *> exprs)
|
||||
: elems({alloc.allocate_object<Expr *>(exprs.size()), exprs.size()})
|
||||
{
|
||||
std::ranges::copy(exprs, elems.begin());
|
||||
@@ -573,7 +562,7 @@ public:
|
||||
const PosTable & positions,
|
||||
std::pmr::polymorphic_allocator<char> & alloc,
|
||||
PosIdx pos,
|
||||
const FormalsBuilder & formals,
|
||||
FormalsBuilder formals,
|
||||
Expr * body)
|
||||
: ExprLambda(positions, alloc, pos, Symbol(), formals, body) {};
|
||||
|
||||
@@ -592,14 +581,11 @@ public:
|
||||
struct ExprCall : Expr
|
||||
{
|
||||
Expr * fun;
|
||||
/**
|
||||
* args will never be null. See comment on ExprAttrs::AttrDefs below.
|
||||
*/
|
||||
std::optional<std::pmr::vector<Expr *>> args;
|
||||
std::vector<Expr *> args;
|
||||
PosIdx pos;
|
||||
std::optional<PosIdx> cursedOrEndPos; // used during parsing to warn about https://github.com/NixOS/nix/issues/11118
|
||||
|
||||
ExprCall(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args)
|
||||
ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args)
|
||||
: fun(fun)
|
||||
, args(args)
|
||||
, pos(pos)
|
||||
@@ -607,7 +593,7 @@ struct ExprCall : Expr
|
||||
{
|
||||
}
|
||||
|
||||
ExprCall(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args, PosIdx && cursedOrEndPos)
|
||||
ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args, PosIdx && cursedOrEndPos)
|
||||
: fun(fun)
|
||||
, args(args)
|
||||
, pos(pos)
|
||||
@@ -767,19 +753,7 @@ struct ExprConcatStrings : Expr
|
||||
std::pmr::polymorphic_allocator<char> & alloc,
|
||||
const PosIdx & pos,
|
||||
bool forceString,
|
||||
std::span<std::pair<PosIdx, Expr *>> es)
|
||||
: pos(pos)
|
||||
, forceString(forceString)
|
||||
, es({alloc.allocate_object<std::pair<PosIdx, Expr *>>(es.size()), es.size()})
|
||||
{
|
||||
std::ranges::copy(es, this->es.begin());
|
||||
};
|
||||
|
||||
ExprConcatStrings(
|
||||
std::pmr::polymorphic_allocator<char> & alloc,
|
||||
const PosIdx & pos,
|
||||
bool forceString,
|
||||
std::initializer_list<std::pair<PosIdx, Expr *>> es)
|
||||
const std::vector<std::pair<PosIdx, Expr *>> & es)
|
||||
: pos(pos)
|
||||
, forceString(forceString)
|
||||
, es({alloc.allocate_object<std::pair<PosIdx, Expr *>>(es.size()), es.size()})
|
||||
@@ -839,7 +813,7 @@ public:
|
||||
// we define some calls to add explicitly so that the argument can be passed in as initializer lists
|
||||
template<class C>
|
||||
[[gnu::always_inline]]
|
||||
C * add(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args)
|
||||
C * add(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args)
|
||||
requires(std::same_as<C, ExprCall>)
|
||||
{
|
||||
return alloc.new_object<C>(pos, fun, std::move(args));
|
||||
@@ -847,7 +821,7 @@ public:
|
||||
|
||||
template<class C>
|
||||
[[gnu::always_inline]]
|
||||
C * add(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args, PosIdx && cursedOrEndPos)
|
||||
C * add(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args, PosIdx && cursedOrEndPos)
|
||||
requires(std::same_as<C, ExprCall>)
|
||||
{
|
||||
return alloc.new_object<C>(pos, fun, std::move(args), std::move(cursedOrEndPos));
|
||||
@@ -859,19 +833,7 @@ public:
|
||||
add(std::pmr::polymorphic_allocator<char> & alloc,
|
||||
const PosIdx & pos,
|
||||
bool forceString,
|
||||
std::span<std::pair<PosIdx, Expr *>> es)
|
||||
requires(std::same_as<C, ExprConcatStrings>)
|
||||
{
|
||||
return alloc.new_object<C>(alloc, pos, forceString, es);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
[[gnu::always_inline]]
|
||||
C *
|
||||
add(std::pmr::polymorphic_allocator<char> & alloc,
|
||||
const PosIdx & pos,
|
||||
bool forceString,
|
||||
std::initializer_list<std::pair<PosIdx, Expr *>> es)
|
||||
const std::vector<std::pair<PosIdx, Expr *>> & es)
|
||||
requires(std::same_as<C, ExprConcatStrings>)
|
||||
{
|
||||
return alloc.new_object<C>(alloc, pos, forceString, es);
|
||||
|
||||
@@ -96,7 +96,7 @@ struct ParserState
|
||||
ExprAttrs * attrs, AttrPath && attrPath, const ParserLocation & loc, Expr * e, const ParserLocation & exprLoc);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symbol, ExprAttrs::AttrDef && def);
|
||||
void validateFormals(FormalsBuilder & formals, PosIdx pos = noPos, Symbol arg = {});
|
||||
Expr * stripIndentation(const PosIdx pos, std::span<std::pair<PosIdx, std::variant<Expr *, StringToken>>> es);
|
||||
Expr * stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
|
||||
PosIdx at(const ParserLocation & loc);
|
||||
};
|
||||
|
||||
@@ -126,8 +126,8 @@ inline void ParserState::addAttr(
|
||||
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
||||
ExprAttrs * nested;
|
||||
if (i->symbol) {
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs->find(i->symbol);
|
||||
if (j != attrs->attrs->end()) {
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||
if (j != attrs->attrs.end()) {
|
||||
nested = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||
if (!nested) {
|
||||
attrPath.erase(i + 1, attrPath.end());
|
||||
@@ -135,11 +135,11 @@ inline void ParserState::addAttr(
|
||||
}
|
||||
} else {
|
||||
nested = exprs.add<ExprAttrs>();
|
||||
(*attrs->attrs)[i->symbol] = ExprAttrs::AttrDef(nested, pos);
|
||||
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
|
||||
}
|
||||
} else {
|
||||
nested = exprs.add<ExprAttrs>();
|
||||
attrs->dynamicAttrs->push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
|
||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
|
||||
}
|
||||
attrs = nested;
|
||||
}
|
||||
@@ -148,7 +148,7 @@ inline void ParserState::addAttr(
|
||||
if (i->symbol) {
|
||||
addAttr(attrs, attrPath, i->symbol, ExprAttrs::AttrDef(e, pos));
|
||||
} else {
|
||||
attrs->dynamicAttrs->push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||
}
|
||||
|
||||
auto it = lexerState.positionToDocComment.find(pos);
|
||||
@@ -165,8 +165,8 @@ inline void ParserState::addAttr(
|
||||
inline void
|
||||
ParserState::addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symbol, ExprAttrs::AttrDef && def)
|
||||
{
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs->find(symbol);
|
||||
if (j != attrs->attrs->end()) {
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(symbol);
|
||||
if (j != attrs->attrs.end()) {
|
||||
// This attr path is already defined. However, if both
|
||||
// e and the expr pointed by the attr path are two attribute sets,
|
||||
// we want to merge them.
|
||||
@@ -181,8 +181,8 @@ ParserState::addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symb
|
||||
// See https://github.com/NixOS/nix/issues/9020.
|
||||
if (jAttrs && ae) {
|
||||
if (ae->inheritFromExprs && !jAttrs->inheritFromExprs)
|
||||
jAttrs->inheritFromExprs = std::make_unique<std::pmr::vector<Expr *>>();
|
||||
for (auto & ad : *ae->attrs) {
|
||||
jAttrs->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
for (auto & ad : ae->attrs) {
|
||||
if (ad.second.kind == ExprAttrs::AttrDef::Kind::InheritedFrom) {
|
||||
auto & sel = dynamic_cast<ExprSelect &>(*ad.second.e);
|
||||
auto & from = dynamic_cast<ExprInheritFrom &>(*sel.e);
|
||||
@@ -192,12 +192,12 @@ ParserState::addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symb
|
||||
addAttr(jAttrs, attrPath, ad.first, std::move(ad.second));
|
||||
attrPath.pop_back();
|
||||
}
|
||||
ae->attrs->clear();
|
||||
jAttrs->dynamicAttrs->insert(
|
||||
jAttrs->dynamicAttrs->end(),
|
||||
std::make_move_iterator(ae->dynamicAttrs->begin()),
|
||||
std::make_move_iterator(ae->dynamicAttrs->end()));
|
||||
ae->dynamicAttrs->clear();
|
||||
ae->attrs.clear();
|
||||
jAttrs->dynamicAttrs.insert(
|
||||
jAttrs->dynamicAttrs.end(),
|
||||
std::make_move_iterator(ae->dynamicAttrs.begin()),
|
||||
std::make_move_iterator(ae->dynamicAttrs.end()));
|
||||
ae->dynamicAttrs.clear();
|
||||
if (ae->inheritFromExprs) {
|
||||
jAttrs->inheritFromExprs->insert(
|
||||
jAttrs->inheritFromExprs->end(),
|
||||
@@ -210,7 +210,7 @@ ParserState::addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symb
|
||||
}
|
||||
} else {
|
||||
// This attr path is not defined. Let's create it.
|
||||
attrs->attrs->emplace(symbol, def);
|
||||
attrs->attrs.emplace(symbol, def);
|
||||
def.e->setName(symbol);
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,7 @@ inline void ParserState::validateFormals(FormalsBuilder & formals, PosIdx pos, S
|
||||
}
|
||||
|
||||
inline Expr *
|
||||
ParserState::stripIndentation(const PosIdx pos, std::span<std::pair<PosIdx, std::variant<Expr *, StringToken>>> es)
|
||||
ParserState::stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es)
|
||||
{
|
||||
if (es.empty())
|
||||
return exprs.add<ExprString>(""_sds);
|
||||
@@ -343,7 +343,7 @@ ParserState::stripIndentation(const PosIdx pos, std::span<std::pair<PosIdx, std:
|
||||
auto * const result = (es2)[0].second;
|
||||
return result;
|
||||
}
|
||||
return exprs.add<ExprConcatStrings>(exprs.alloc, pos, true, es2);
|
||||
return exprs.add<ExprConcatStrings>(exprs.alloc, pos, true, std::move(es2));
|
||||
}
|
||||
|
||||
inline PosIdx LexerState::at(const ParserLocation & loc)
|
||||
|
||||
@@ -12,7 +12,11 @@ struct RegisterPrimOp
|
||||
{
|
||||
typedef std::vector<PrimOp> PrimOps;
|
||||
|
||||
static PrimOps & primOps();
|
||||
static PrimOps & primOps()
|
||||
{
|
||||
static PrimOps primOps;
|
||||
return primOps;
|
||||
}
|
||||
|
||||
/**
|
||||
* You can register a constant by passing an arity of 0. fun
|
||||
|
||||
@@ -110,7 +110,7 @@ struct PrintOptions
|
||||
* `PrintOptions` for unknown and therefore potentially large values in error messages,
|
||||
* to avoid printing "too much" output.
|
||||
*/
|
||||
static constexpr PrintOptions errorPrintOptions = PrintOptions{
|
||||
static PrintOptions errorPrintOptions = PrintOptions{
|
||||
.ansiColors = true,
|
||||
.maxDepth = 10,
|
||||
.maxAttrs = 10,
|
||||
|
||||
@@ -88,7 +88,6 @@ class PosIdx;
|
||||
struct Pos;
|
||||
class StorePath;
|
||||
class EvalState;
|
||||
class EvalMemory;
|
||||
class XMLWriter;
|
||||
class Printer;
|
||||
|
||||
@@ -162,7 +161,7 @@ class ListBuilder
|
||||
Value * inlineElems[2] = {nullptr, nullptr};
|
||||
public:
|
||||
Value ** elems;
|
||||
ListBuilder(EvalMemory & mem, size_t size);
|
||||
ListBuilder(size_t size);
|
||||
|
||||
// NOTE: Can be noexcept because we are just copying integral values and
|
||||
// raw pointers.
|
||||
@@ -232,13 +231,13 @@ public:
|
||||
* Allocate StringData on the (possibly) GC-managed heap and copy
|
||||
* the contents of s to it.
|
||||
*/
|
||||
static const StringData & make(EvalMemory & mem, std::string_view s);
|
||||
static const StringData & make(std::string_view s);
|
||||
|
||||
/**
|
||||
* Allocate StringData on the (possibly) GC-managed heap.
|
||||
* @param size Length of the string (without the NUL terminator).
|
||||
*/
|
||||
static StringData & alloc(EvalMemory & mem, size_t size);
|
||||
static StringData & alloc(size_t size);
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
@@ -365,7 +364,7 @@ struct ValueBase
|
||||
/**
|
||||
* @return null pointer when context.empty()
|
||||
*/
|
||||
static Context * fromBuilder(const NixStringContext & context, EvalMemory & mem);
|
||||
static Context * fromBuilder(const NixStringContext & context);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1147,13 +1146,13 @@ public:
|
||||
setStorage(StringWithContext{.str = &s, .context = context});
|
||||
}
|
||||
|
||||
void mkString(std::string_view s, EvalMemory & mem);
|
||||
void mkString(std::string_view s);
|
||||
|
||||
void mkString(std::string_view s, const NixStringContext & context, EvalMemory & mem);
|
||||
void mkString(std::string_view s, const NixStringContext & context);
|
||||
|
||||
void mkStringMove(const StringData & s, const NixStringContext & context, EvalMemory & mem);
|
||||
void mkStringMove(const StringData & s, const NixStringContext & context);
|
||||
|
||||
void mkPath(const SourcePath & path, EvalMemory & mem);
|
||||
void mkPath(const SourcePath & path);
|
||||
|
||||
inline void mkPath(SourceAccessor * accessor, const StringData & path) noexcept
|
||||
{
|
||||
|
||||
@@ -151,7 +151,7 @@ public:
|
||||
bool string(string_t & val) override
|
||||
{
|
||||
forceNoNullByte(val);
|
||||
rs->value(state).mkString(val, state.mem);
|
||||
rs->value(state).mkString(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -74,9 +74,9 @@ void ExprOpHasAttr::show(const SymbolTable & symbols, std::ostream & str) const
|
||||
|
||||
void ExprAttrs::showBindings(const SymbolTable & symbols, std::ostream & str) const
|
||||
{
|
||||
typedef const AttrDefs::value_type * Attr;
|
||||
typedef const decltype(attrs)::value_type * Attr;
|
||||
std::vector<Attr> sorted;
|
||||
for (auto & i : *attrs)
|
||||
for (auto & i : attrs)
|
||||
sorted.push_back(&i);
|
||||
std::sort(sorted.begin(), sorted.end(), [&](Attr a, Attr b) {
|
||||
std::string_view sa = symbols[a->first], sb = symbols[b->first];
|
||||
@@ -122,7 +122,7 @@ void ExprAttrs::showBindings(const SymbolTable & symbols, std::ostream & str) co
|
||||
str << "; ";
|
||||
}
|
||||
}
|
||||
for (auto & i : *dynamicAttrs) {
|
||||
for (auto & i : dynamicAttrs) {
|
||||
str << "\"${";
|
||||
i.nameExpr->show(symbols, str);
|
||||
str << "}\" = ";
|
||||
@@ -191,7 +191,7 @@ void ExprCall::show(const SymbolTable & symbols, std::ostream & str) const
|
||||
{
|
||||
str << '(';
|
||||
fun->show(symbols, str);
|
||||
for (auto e : *args) {
|
||||
for (auto e : args) {
|
||||
str << ' ';
|
||||
e->show(symbols, str);
|
||||
}
|
||||
@@ -401,26 +401,15 @@ ExprAttrs::bindInheritSources(EvalState & es, const std::shared_ptr<const Static
|
||||
|
||||
void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
||||
{
|
||||
// Move storage into the Exprs arena
|
||||
{
|
||||
auto arena = es.mem.exprs.alloc;
|
||||
AttrDefs newAttrs{std::move(*attrs), arena};
|
||||
attrs.emplace(std::move(newAttrs), arena);
|
||||
DynamicAttrDefs newDynamicAttrs{std::move(*dynamicAttrs), arena};
|
||||
dynamicAttrs.emplace(std::move(newDynamicAttrs), arena);
|
||||
if (inheritFromExprs)
|
||||
inheritFromExprs = std::make_unique<std::pmr::vector<Expr *>>(std::move(*inheritFromExprs), arena);
|
||||
}
|
||||
|
||||
if (es.debugRepl)
|
||||
es.exprEnvs.insert(std::make_pair(this, env));
|
||||
|
||||
if (recursive) {
|
||||
auto newEnv = [&]() -> std::shared_ptr<const StaticEnv> {
|
||||
auto newEnv = std::make_shared<StaticEnv>(nullptr, env, attrs->size());
|
||||
auto newEnv = std::make_shared<StaticEnv>(nullptr, env, attrs.size());
|
||||
|
||||
Displacement displ = 0;
|
||||
for (auto & i : *attrs)
|
||||
for (auto & i : attrs)
|
||||
newEnv->vars.emplace_back(i.first, i.second.displ = displ++);
|
||||
return newEnv;
|
||||
}();
|
||||
@@ -428,20 +417,20 @@ void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
|
||||
// No need to sort newEnv since attrs is in sorted order.
|
||||
|
||||
auto inheritFromEnv = bindInheritSources(es, newEnv);
|
||||
for (auto & i : *attrs)
|
||||
for (auto & i : attrs)
|
||||
i.second.e->bindVars(es, i.second.chooseByKind(newEnv, env, inheritFromEnv));
|
||||
|
||||
for (auto & i : *dynamicAttrs) {
|
||||
for (auto & i : dynamicAttrs) {
|
||||
i.nameExpr->bindVars(es, newEnv);
|
||||
i.valueExpr->bindVars(es, newEnv);
|
||||
}
|
||||
} else {
|
||||
auto inheritFromEnv = bindInheritSources(es, env);
|
||||
|
||||
for (auto & i : *attrs)
|
||||
for (auto & i : attrs)
|
||||
i.second.e->bindVars(es, i.second.chooseByKind(env, env, inheritFromEnv));
|
||||
|
||||
for (auto & i : *dynamicAttrs) {
|
||||
for (auto & i : dynamicAttrs) {
|
||||
i.nameExpr->bindVars(es, env);
|
||||
i.valueExpr->bindVars(es, env);
|
||||
}
|
||||
@@ -486,27 +475,21 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
|
||||
|
||||
void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
||||
{
|
||||
// Move storage into the Exprs arena
|
||||
{
|
||||
auto arena = es.mem.exprs.alloc;
|
||||
std::pmr::vector<Expr *> newArgs{std::move(*args), arena};
|
||||
args.emplace(std::move(newArgs), arena);
|
||||
}
|
||||
if (es.debugRepl)
|
||||
es.exprEnvs.insert(std::make_pair(this, env));
|
||||
|
||||
fun->bindVars(es, env);
|
||||
for (auto e : *args)
|
||||
for (auto e : args)
|
||||
e->bindVars(es, env);
|
||||
}
|
||||
|
||||
void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
||||
{
|
||||
auto newEnv = [&]() -> std::shared_ptr<const StaticEnv> {
|
||||
auto newEnv = std::make_shared<StaticEnv>(nullptr, env, attrs->attrs->size());
|
||||
auto newEnv = std::make_shared<StaticEnv>(nullptr, env, attrs->attrs.size());
|
||||
|
||||
Displacement displ = 0;
|
||||
for (auto & i : *attrs->attrs)
|
||||
for (auto & i : attrs->attrs)
|
||||
newEnv->vars.emplace_back(i.first, i.second.displ = displ++);
|
||||
return newEnv;
|
||||
}();
|
||||
@@ -514,7 +497,7 @@ void ExprLet::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> &
|
||||
// No need to sort newEnv since attrs->attrs is in sorted order.
|
||||
|
||||
auto inheritFromEnv = attrs->bindInheritSources(es, newEnv);
|
||||
for (auto & i : *attrs->attrs)
|
||||
for (auto & i : attrs->attrs)
|
||||
i.second.e->bindVars(es, i.second.chooseByKind(newEnv, env, inheritFromEnv));
|
||||
|
||||
if (es.debugRepl)
|
||||
|
||||
@@ -70,6 +70,11 @@ mkMesonLibrary (finalAttrs: {
|
||||
nix-util
|
||||
nix-store
|
||||
nix-fetchers
|
||||
]
|
||||
++ finalAttrs.passthru.externalPropagatedBuildInputs;
|
||||
|
||||
# Hack for sake of the dev shell
|
||||
passthru.externalPropagatedBuildInputs = [
|
||||
boost
|
||||
nlohmann_json
|
||||
]
|
||||
|
||||
@@ -115,7 +115,7 @@ static void setDocPosition(const LexerState & lexerState, ExprLambda * lambda, P
|
||||
|
||||
static Expr * makeCall(Exprs & exprs, PosIdx pos, Expr * fn, Expr * arg) {
|
||||
if (auto e2 = dynamic_cast<ExprCall *>(fn)) {
|
||||
e2->args->push_back(arg);
|
||||
e2->args.push_back(arg);
|
||||
return fn;
|
||||
}
|
||||
return exprs.add<ExprCall>(pos, fn, {arg});
|
||||
@@ -126,26 +126,26 @@ static Expr * makeCall(Exprs & exprs, PosIdx pos, Expr * fn, Expr * arg) {
|
||||
|
||||
%define api.value.type variant
|
||||
|
||||
%type <Expr *> start expr expr_function expr_if expr_op
|
||||
%type <Expr *> expr_select expr_simple expr_app
|
||||
%type <Expr *> expr_pipe_from expr_pipe_into
|
||||
%type <std::pmr::vector<Expr *>> list
|
||||
%type <ExprAttrs *> binds binds1
|
||||
%type <FormalsBuilder> formals formal_set
|
||||
%type <Formal> formal
|
||||
%type <std::vector<AttrName>> attrpath
|
||||
%type <std::vector<std::pair<AttrName, PosIdx>>> attrs
|
||||
%type <std::vector<std::pair<PosIdx, Expr *>>> string_parts_interpolated
|
||||
%type <std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>>> ind_string_parts
|
||||
%type <Expr *> path_start
|
||||
%type <std::variant<Expr *, std::string_view>> string_parts string_attr
|
||||
%type <StringToken> attr
|
||||
%token <StringToken> ID
|
||||
%token <StringToken> STR IND_STR
|
||||
%token <NixInt> INT_LIT
|
||||
%token <NixFloat> FLOAT_LIT
|
||||
%token <StringToken> PATH HPATH SPATH PATH_END
|
||||
%token <StringToken> URI
|
||||
%type <nix::Expr *> start expr expr_function expr_if expr_op
|
||||
%type <nix::Expr *> expr_select expr_simple expr_app
|
||||
%type <nix::Expr *> expr_pipe_from expr_pipe_into
|
||||
%type <std::vector<Expr *>> list
|
||||
%type <nix::ExprAttrs *> binds binds1
|
||||
%type <nix::FormalsBuilder> formals formal_set
|
||||
%type <nix::Formal> formal
|
||||
%type <std::vector<nix::AttrName>> attrpath
|
||||
%type <std::vector<std::pair<nix::AttrName, nix::PosIdx>>> attrs
|
||||
%type <std::vector<std::pair<nix::PosIdx, nix::Expr *>>> string_parts_interpolated
|
||||
%type <std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, nix::StringToken>>>> ind_string_parts
|
||||
%type <nix::Expr *> path_start
|
||||
%type <std::variant<nix::Expr *, std::string_view>> string_parts string_attr
|
||||
%type <nix::StringToken> attr
|
||||
%token <nix::StringToken> ID
|
||||
%token <nix::StringToken> STR IND_STR
|
||||
%token <nix::NixInt> INT_LIT
|
||||
%token <nix::NixFloat> FLOAT_LIT
|
||||
%token <nix::StringToken> PATH HPATH SPATH PATH_END
|
||||
%token <nix::StringToken> URI
|
||||
%token IF THEN ELSE ASSERT WITH LET IN_KW REC INHERIT EQ NEQ AND OR IMPL OR_KW
|
||||
%token PIPE_FROM PIPE_INTO /* <| and |> */
|
||||
%token DOLLAR_CURLY /* == ${ */
|
||||
@@ -186,7 +186,7 @@ expr_function
|
||||
| formal_set ':' expr_function[body]
|
||||
{
|
||||
state->validateFormals($formal_set);
|
||||
auto me = state->exprs.add<ExprLambda>(state->positions, state->exprs.alloc, CUR_POS, $formal_set, $body);
|
||||
auto me = state->exprs.add<ExprLambda>(state->positions, state->exprs.alloc, CUR_POS, std::move($formal_set), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
@@ -194,7 +194,7 @@ expr_function
|
||||
{
|
||||
auto arg = state->symbols.create($ID);
|
||||
state->validateFormals($formal_set, CUR_POS, arg);
|
||||
auto me = state->exprs.add<ExprLambda>(state->positions, state->exprs.alloc, CUR_POS, arg, $formal_set, $body);
|
||||
auto me = state->exprs.add<ExprLambda>(state->positions, state->exprs.alloc, CUR_POS, arg, std::move($formal_set), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ expr_function
|
||||
{
|
||||
auto arg = state->symbols.create($ID);
|
||||
state->validateFormals($formal_set, CUR_POS, arg);
|
||||
auto me = state->exprs.add<ExprLambda>(state->positions, state->exprs.alloc, CUR_POS, arg, $formal_set, $body);
|
||||
auto me = state->exprs.add<ExprLambda>(state->positions, state->exprs.alloc, CUR_POS, arg, std::move($formal_set), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
@@ -211,7 +211,7 @@ expr_function
|
||||
| WITH expr ';' expr_function
|
||||
{ $$ = state->exprs.add<ExprWith>(CUR_POS, $2, $4); }
|
||||
| LET binds IN_KW expr_function
|
||||
{ if (!$2->dynamicAttrs->empty())
|
||||
{ if (!$2->dynamicAttrs.empty())
|
||||
throw ParseError({
|
||||
.msg = HintFmt("dynamic attributes not allowed in let"),
|
||||
.pos = state->positions[CUR_POS]
|
||||
@@ -251,7 +251,7 @@ expr_op
|
||||
| expr_op OR expr_op { $$ = state->exprs.add<ExprOpOr>(state->at(@2), $1, $3); }
|
||||
| expr_op IMPL expr_op { $$ = state->exprs.add<ExprOpImpl>(state->at(@2), $1, $3); }
|
||||
| expr_op UPDATE expr_op { $$ = state->exprs.add<ExprOpUpdate>(state->at(@2), $1, $3); }
|
||||
| expr_op '?' attrpath { $$ = state->exprs.add<ExprOpHasAttr>(state->exprs.alloc, $1, $3); }
|
||||
| expr_op '?' attrpath { $$ = state->exprs.add<ExprOpHasAttr>(state->exprs.alloc, $1, std::move($3)); }
|
||||
| expr_op '+' expr_op
|
||||
{ $$ = state->exprs.add<ExprConcatStrings>(state->exprs.alloc, state->at(@2), false, {{state->at(@1), $1}, {state->at(@3), $3}}); }
|
||||
| expr_op '-' expr_op { $$ = state->exprs.add<ExprCall>(state->at(@2), state->exprs.add<ExprVar>(state->s.sub), {$1, $3}); }
|
||||
@@ -272,9 +272,9 @@ expr_app
|
||||
|
||||
expr_select
|
||||
: expr_simple '.' attrpath
|
||||
{ $$ = state->exprs.add<ExprSelect>(state->exprs.alloc, CUR_POS, $1, $3, nullptr); }
|
||||
{ $$ = state->exprs.add<ExprSelect>(state->exprs.alloc, CUR_POS, $1, std::move($3), nullptr); }
|
||||
| expr_simple '.' attrpath OR_KW expr_select
|
||||
{ $$ = state->exprs.add<ExprSelect>(state->exprs.alloc, CUR_POS, $1, $3, $5); $5->warnIfCursedOr(state->symbols, state->positions); }
|
||||
{ $$ = state->exprs.add<ExprSelect>(state->exprs.alloc, CUR_POS, $1, std::move($3), $5); $5->warnIfCursedOr(state->symbols, state->positions); }
|
||||
| /* Backwards compatibility: because Nixpkgs has a function named ‘or’,
|
||||
allow stuff like ‘map or [...]’. This production is problematic (see
|
||||
https://github.com/NixOS/nix/issues/11118) and will be refactored in the
|
||||
@@ -304,12 +304,12 @@ expr_simple
|
||||
$2);
|
||||
}
|
||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||
$$ = state->stripIndentation(CUR_POS, $2);
|
||||
$$ = state->stripIndentation(CUR_POS, std::move($2));
|
||||
}
|
||||
| path_start PATH_END
|
||||
| path_start string_parts_interpolated PATH_END {
|
||||
$2.insert($2.begin(), {state->at(@1), $1});
|
||||
$$ = state->exprs.add<ExprConcatStrings>(state->exprs.alloc, CUR_POS, false, $2);
|
||||
$$ = state->exprs.add<ExprConcatStrings>(state->exprs.alloc, CUR_POS, false, std::move($2));
|
||||
}
|
||||
| SPATH {
|
||||
std::string_view path($1.p + 1, $1.l - 2);
|
||||
@@ -338,12 +338,12 @@ expr_simple
|
||||
{ $2->pos = CUR_POS; $$ = $2; }
|
||||
| '{' '}'
|
||||
{ $$ = state->exprs.add<ExprAttrs>(CUR_POS); }
|
||||
| '[' list ']' { $$ = state->exprs.add<ExprList>(state->exprs.alloc, $2); }
|
||||
| '[' list ']' { $$ = state->exprs.add<ExprList>(state->exprs.alloc, std::move($2)); }
|
||||
;
|
||||
|
||||
string_parts
|
||||
: STR { $$ = $1; }
|
||||
| string_parts_interpolated { $$ = state->exprs.add<ExprConcatStrings>(state->exprs.alloc, CUR_POS, true, $1); }
|
||||
| string_parts_interpolated { $$ = state->exprs.add<ExprConcatStrings>(state->exprs.alloc, CUR_POS, true, std::move($1)); }
|
||||
| { $$ = std::string_view(); }
|
||||
;
|
||||
|
||||
@@ -413,9 +413,9 @@ binds1
|
||||
| binds[accum] INHERIT attrs ';'
|
||||
{ $$ = $accum;
|
||||
for (auto & [i, iPos] : $attrs) {
|
||||
if ($accum->attrs->find(i.symbol) != $accum->attrs->end())
|
||||
state->dupAttr(i.symbol, iPos, (*$accum->attrs)[i.symbol].pos);
|
||||
$accum->attrs->emplace(
|
||||
if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
|
||||
$accum->attrs.emplace(
|
||||
i.symbol,
|
||||
ExprAttrs::AttrDef(state->exprs.add<ExprVar>(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited));
|
||||
}
|
||||
@@ -423,13 +423,13 @@ binds1
|
||||
| binds[accum] INHERIT '(' expr ')' attrs ';'
|
||||
{ $$ = $accum;
|
||||
if (!$accum->inheritFromExprs)
|
||||
$accum->inheritFromExprs = std::make_unique<std::pmr::vector<Expr *>>();
|
||||
$accum->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
$accum->inheritFromExprs->push_back($expr);
|
||||
auto from = state->exprs.add<ExprInheritFrom>(state->at(@expr), $accum->inheritFromExprs->size() - 1);
|
||||
auto from = new nix::ExprInheritFrom(state->at(@expr), $accum->inheritFromExprs->size() - 1);
|
||||
for (auto & [i, iPos] : $attrs) {
|
||||
if ($accum->attrs->find(i.symbol) != $accum->attrs->end())
|
||||
state->dupAttr(i.symbol, iPos, (*$accum->attrs)[i.symbol].pos);
|
||||
$accum->attrs->emplace(
|
||||
if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
|
||||
$accum->attrs.emplace(
|
||||
i.symbol,
|
||||
ExprAttrs::AttrDef(
|
||||
state->exprs.add<ExprSelect>(state->exprs.alloc, iPos, from, i.symbol),
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
RegisterPrimOp::PrimOps & RegisterPrimOp::primOps()
|
||||
{
|
||||
static RegisterPrimOp::PrimOps primOps;
|
||||
return primOps;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Miscellaneous
|
||||
*************************************************************/
|
||||
@@ -53,7 +47,7 @@ RegisterPrimOp::PrimOps & RegisterPrimOp::primOps()
|
||||
static inline Value * mkString(EvalState & state, const std::csub_match & match)
|
||||
{
|
||||
Value * v = state.allocValue();
|
||||
v->mkString({match.first, match.second}, state.mem);
|
||||
v->mkString({match.first, match.second});
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -228,14 +222,13 @@ void derivationToValue(
|
||||
path2,
|
||||
{
|
||||
NixStringContextElem::DrvDeep{.drvPath = storePath},
|
||||
},
|
||||
state.mem);
|
||||
attrs.alloc(state.s.name).mkString(drv.env["name"], state.mem);
|
||||
});
|
||||
attrs.alloc(state.s.name).mkString(drv.env["name"]);
|
||||
|
||||
auto list = state.buildList(drv.outputs.size());
|
||||
for (const auto & [i, o] : enumerate(drv.outputs)) {
|
||||
mkOutputString(state, attrs, storePath, o);
|
||||
(list[i] = state.allocValue())->mkString(o.first, state.mem);
|
||||
(list[i] = state.allocValue())->mkString(o.first);
|
||||
}
|
||||
attrs.alloc(state.s.outputs).mkList(list);
|
||||
|
||||
@@ -519,7 +512,7 @@ static void prim_typeOf(EvalState & state, const PosIdx pos, Value ** args, Valu
|
||||
v.mkStringNoCopy("lambda"_sds);
|
||||
break;
|
||||
case nExternal:
|
||||
v.mkString(args[0]->external()->typeOf(), state.mem);
|
||||
v.mkString(args[0]->external()->typeOf());
|
||||
break;
|
||||
case nFloat:
|
||||
v.mkStringNoCopy("float"_sds);
|
||||
@@ -1176,7 +1169,7 @@ static void prim_getEnv(EvalState & state, const PosIdx pos, Value ** args, Valu
|
||||
{
|
||||
std::string name(
|
||||
state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getEnv"));
|
||||
v.mkString(state.settings.restrictEval || state.settings.pureEval ? "" : getEnv(name).value_or(""), state.mem);
|
||||
v.mkString(state.settings.restrictEval || state.settings.pureEval ? "" : getEnv(name).value_or(""));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_getEnv({
|
||||
@@ -1818,8 +1811,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
drvPathS,
|
||||
{
|
||||
NixStringContextElem::DrvDeep{.drvPath = drvPath},
|
||||
},
|
||||
state.mem);
|
||||
});
|
||||
for (auto & i : drv.outputs)
|
||||
mkOutputString(state, result, drvPath, i);
|
||||
|
||||
@@ -1842,10 +1834,8 @@ static RegisterPrimOp primop_derivationStrict(
|
||||
‘out’. */
|
||||
static void prim_placeholder(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
{
|
||||
v.mkString(
|
||||
hashPlaceholder(state.forceStringNoCtx(
|
||||
*args[0], pos, "while evaluating the first argument passed to builtins.placeholder")),
|
||||
state.mem);
|
||||
v.mkString(hashPlaceholder(
|
||||
state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.placeholder")));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_placeholder({
|
||||
@@ -1874,7 +1864,7 @@ static void prim_toPath(EvalState & state, const PosIdx pos, Value ** args, Valu
|
||||
NixStringContext context;
|
||||
auto path =
|
||||
state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.toPath");
|
||||
v.mkString(path.path.abs(), context, state.mem);
|
||||
v.mkString(path.path.abs(), context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_toPath({
|
||||
@@ -1917,7 +1907,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value ** args, V
|
||||
if (!settings.readOnlyMode)
|
||||
state.store->ensurePath(path2);
|
||||
context.insert(NixStringContextElem::Opaque{.path = path2});
|
||||
v.mkString(path.abs(), context, state.mem);
|
||||
v.mkString(path.abs(), context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_storePath({
|
||||
@@ -1999,8 +1989,7 @@ static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value ** args,
|
||||
v.mkString(
|
||||
legacyBaseNameOf(*state.coerceToString(
|
||||
pos, *args[0], context, "while evaluating the first argument passed to builtins.baseNameOf", false, false)),
|
||||
context,
|
||||
state.mem);
|
||||
context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_baseNameOf({
|
||||
@@ -2029,18 +2018,18 @@ static void prim_dirOf(EvalState & state, const PosIdx pos, Value ** args, Value
|
||||
state.forceValue(*args[0], pos);
|
||||
if (args[0]->type() == nPath) {
|
||||
auto path = args[0]->path();
|
||||
v.mkPath(path.path.isRoot() ? path : path.parent(), state.mem);
|
||||
v.mkPath(path.path.isRoot() ? path : path.parent());
|
||||
} else {
|
||||
NixStringContext context;
|
||||
auto path = state.coerceToString(
|
||||
pos, *args[0], context, "while evaluating the first argument passed to 'builtins.dirOf'", false, false);
|
||||
auto pos = path->rfind('/');
|
||||
if (pos == path->npos)
|
||||
v.mkStringMove("."_sds, context, state.mem);
|
||||
v.mkStringMove("."_sds, context);
|
||||
else if (pos == 0)
|
||||
v.mkStringMove("/"_sds, context, state.mem);
|
||||
v.mkStringMove("/"_sds, context);
|
||||
else
|
||||
v.mkString(path->substr(0, pos), context, state.mem);
|
||||
v.mkString(path->substr(0, pos), context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2082,7 +2071,7 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
.path = std::move((StorePath &&) p),
|
||||
});
|
||||
}
|
||||
v.mkString(s, context, state.mem);
|
||||
v.mkString(s, context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_readFile({
|
||||
@@ -2146,7 +2135,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
auto path =
|
||||
state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile");
|
||||
|
||||
v.mkPath(state.findFile(lookupPath, path, pos), state.mem);
|
||||
v.mkPath(state.findFile(lookupPath, path, pos));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_findFile(
|
||||
@@ -2295,7 +2284,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
|
||||
auto path = realisePath(state, pos, *args[1]);
|
||||
|
||||
v.mkString(hashString(*ha, path.readFile()).to_string(HashFormat::Base16, false), state.mem);
|
||||
v.mkString(hashString(*ha, path.readFile()).to_string(HashFormat::Base16, false));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_hashFile({
|
||||
@@ -2384,7 +2373,7 @@ static void prim_readDir(EvalState & state, const PosIdx pos, Value ** args, Val
|
||||
// detailed node info quickly in this case we produce a thunk to
|
||||
// query the file type lazily.
|
||||
auto epath = state.allocValue();
|
||||
epath->mkPath(path / name, state.mem);
|
||||
epath->mkPath(path / name);
|
||||
if (!readFileType)
|
||||
readFileType = &state.getBuiltin("readFileType");
|
||||
attr.mkApp(readFileType, epath);
|
||||
@@ -2478,7 +2467,7 @@ static void prim_toXML(EvalState & state, const PosIdx pos, Value ** args, Value
|
||||
std::ostringstream out;
|
||||
NixStringContext context;
|
||||
printValueAsXML(state, true, false, *args[0], out, context, pos);
|
||||
v.mkString(out.view(), context, state.mem);
|
||||
v.mkString(out.view(), context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_toXML({
|
||||
@@ -2586,7 +2575,7 @@ static void prim_toJSON(EvalState & state, const PosIdx pos, Value ** args, Valu
|
||||
std::ostringstream out;
|
||||
NixStringContext context;
|
||||
printValueAsJSON(state, true, *args[0], pos, out, context);
|
||||
v.mkString(out.view(), context, state.mem);
|
||||
v.mkString(out.view(), context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_toJSON({
|
||||
@@ -2765,7 +2754,7 @@ bool EvalState::callPathFilter(Value * filterFun, const SourcePath & path, PosId
|
||||
/* Call the filter function. The first argument is the path, the
|
||||
second is a string indicating the type of the file. */
|
||||
Value arg1;
|
||||
arg1.mkString(path.path.abs(), mem);
|
||||
arg1.mkString(path.path.abs());
|
||||
|
||||
// assert that type is not "unknown"
|
||||
Value * args[]{&arg1, const_cast<Value *>(&fileTypeToString(*this, st.type))};
|
||||
@@ -4415,7 +4404,7 @@ static void prim_toString(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(
|
||||
pos, *args[0], context, "while evaluating the first argument passed to builtins.toString", true, false);
|
||||
v.mkString(*s, context, state.mem);
|
||||
v.mkString(*s, context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_toString({
|
||||
@@ -4488,7 +4477,7 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value ** args, V
|
||||
auto s = state.coerceToString(
|
||||
pos, *args[2], context, "while evaluating the third argument (the string) passed to builtins.substring");
|
||||
|
||||
v.mkString(NixUInt(start) >= s->size() ? "" : s->substr(start, _len), context, state.mem);
|
||||
v.mkString(NixUInt(start) >= s->size() ? "" : s->substr(start, _len), context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_substring({
|
||||
@@ -4543,7 +4532,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value ** args,
|
||||
auto s =
|
||||
state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString");
|
||||
|
||||
v.mkString(hashString(*ha, s).to_string(HashFormat::Base16, false), state.mem);
|
||||
v.mkString(hashString(*ha, s).to_string(HashFormat::Base16, false));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_hashString({
|
||||
@@ -4576,7 +4565,7 @@ static void prim_convertHash(EvalState & state, const PosIdx pos, Value ** args,
|
||||
HashFormat hf = parseHashFormat(
|
||||
state.forceStringNoCtx(*iteratorToHashFormat->value, pos, "while evaluating the attribute 'toHashFormat'"));
|
||||
|
||||
v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI), state.mem);
|
||||
v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_convertHash({
|
||||
@@ -4886,7 +4875,7 @@ static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value **
|
||||
"while evaluating one element of the list of strings to concat passed to builtins.concatStringsSep");
|
||||
}
|
||||
|
||||
v.mkString(res, context, state.mem);
|
||||
v.mkString(res, context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_concatStringsSep({
|
||||
@@ -4961,7 +4950,7 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value ** ar
|
||||
}
|
||||
}
|
||||
|
||||
v.mkString(res, context, state.mem);
|
||||
v.mkString(res, context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_replaceStrings({
|
||||
@@ -4994,8 +4983,8 @@ static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value ** args
|
||||
state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.parseDrvName");
|
||||
DrvName parsed(name);
|
||||
auto attrs = state.buildBindings(2);
|
||||
attrs.alloc(state.s.name).mkString(parsed.name, state.mem);
|
||||
attrs.alloc("version").mkString(parsed.version, state.mem);
|
||||
attrs.alloc(state.s.name).mkString(parsed.name);
|
||||
attrs.alloc("version").mkString(parsed.version);
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
|
||||
@@ -5050,7 +5039,7 @@ static void prim_splitVersion(EvalState & state, const PosIdx pos, Value ** args
|
||||
}
|
||||
auto list = state.buildList(components.size());
|
||||
for (const auto & [n, component] : enumerate(components))
|
||||
(list[n] = state.allocValue())->mkString(std::move(component), state.mem);
|
||||
(list[n] = state.allocValue())->mkString(std::move(component));
|
||||
v.mkList(list);
|
||||
}
|
||||
|
||||
@@ -5194,7 +5183,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings)
|
||||
});
|
||||
|
||||
if (!settings.pureEval)
|
||||
v.mkString(settings.getCurrentSystem(), mem);
|
||||
v.mkString(settings.getCurrentSystem());
|
||||
addConstant(
|
||||
"__currentSystem",
|
||||
v,
|
||||
@@ -5226,7 +5215,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings)
|
||||
.impureOnly = true,
|
||||
});
|
||||
|
||||
v.mkString(nixVersion, mem);
|
||||
v.mkString(nixVersion);
|
||||
addConstant(
|
||||
"__nixVersion",
|
||||
v,
|
||||
@@ -5251,7 +5240,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings)
|
||||
)",
|
||||
});
|
||||
|
||||
v.mkString(store->storeDir, mem);
|
||||
v.mkString(store->storeDir);
|
||||
addConstant(
|
||||
"__storeDir",
|
||||
v,
|
||||
@@ -5316,8 +5305,8 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings)
|
||||
auto list = buildList(lookupPath.elements.size());
|
||||
for (const auto & [n, i] : enumerate(lookupPath.elements)) {
|
||||
auto attrs = buildBindings(2);
|
||||
attrs.alloc("path").mkString(i.path.s, mem);
|
||||
attrs.alloc("prefix").mkString(i.prefix.s, mem);
|
||||
attrs.alloc("path").mkString(i.path.s);
|
||||
attrs.alloc("prefix").mkString(i.prefix.s);
|
||||
(list[n] = allocValue())->mkAttrs(attrs);
|
||||
}
|
||||
v.mkList(list);
|
||||
|
||||
@@ -11,7 +11,7 @@ static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos,
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(
|
||||
pos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardStringContext");
|
||||
v.mkString(*s, state.mem);
|
||||
v.mkString(*s);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_unsafeDiscardStringContext({
|
||||
@@ -69,7 +69,7 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx p
|
||||
}
|
||||
}
|
||||
|
||||
v.mkString(*s, context2, state.mem);
|
||||
v.mkString(*s, context2);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_unsafeDiscardOutputDependency(
|
||||
@@ -137,7 +137,7 @@ static void prim_addDrvOutputDependencies(EvalState & state, const PosIdx pos, V
|
||||
context.begin()->raw)}),
|
||||
};
|
||||
|
||||
v.mkString(*s, context2, state.mem);
|
||||
v.mkString(*s, context2);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_addDrvOutputDependencies(
|
||||
@@ -218,7 +218,7 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value ** args,
|
||||
if (!info.second.outputs.empty()) {
|
||||
auto list = state.buildList(info.second.outputs.size());
|
||||
for (const auto & [i, output] : enumerate(info.second.outputs))
|
||||
(list[i] = state.allocValue())->mkString(output, state.mem);
|
||||
(list[i] = state.allocValue())->mkString(output);
|
||||
infoAttrs.alloc(state.s.outputs).mkList(list);
|
||||
}
|
||||
attrs.alloc(state.store->printStorePath(info.first)).mkAttrs(infoAttrs);
|
||||
@@ -321,7 +321,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value ** arg
|
||||
}
|
||||
}
|
||||
|
||||
v.mkString(orig, context, state.mem);
|
||||
v.mkString(orig, context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_appendContext({.name = "__appendContext", .arity = 2, .fun = prim_appendContext});
|
||||
|
||||
@@ -81,17 +81,17 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value ** ar
|
||||
attrs.insert_or_assign("rev", rev->gitRev());
|
||||
auto input = fetchers::Input::fromAttrs(state.fetchSettings, std::move(attrs));
|
||||
|
||||
auto [storePath, input2] = input.fetchToStore(state.fetchSettings, *state.store);
|
||||
auto [storePath, input2] = input.fetchToStore(state.store);
|
||||
|
||||
auto attrs2 = state.buildBindings(8);
|
||||
state.mkStorePathString(storePath, attrs2.alloc(state.s.outPath));
|
||||
if (input2.getRef())
|
||||
attrs2.alloc("branch").mkString(*input2.getRef(), state.mem);
|
||||
attrs2.alloc("branch").mkString(*input2.getRef());
|
||||
// Backward compatibility: set 'rev' to
|
||||
// 0000000000000000000000000000000000000000 for a dirty tree.
|
||||
auto rev2 = input2.getRev().value_or(Hash(HashAlgorithm::SHA1));
|
||||
attrs2.alloc("rev").mkString(rev2.gitRev(), state.mem);
|
||||
attrs2.alloc("shortRev").mkString(rev2.gitRev().substr(0, 12), state.mem);
|
||||
attrs2.alloc("rev").mkString(rev2.gitRev());
|
||||
attrs2.alloc("shortRev").mkString(rev2.gitRev().substr(0, 12));
|
||||
if (auto revCount = input2.getRevCount())
|
||||
attrs2.alloc("revCount").mkInt(*revCount);
|
||||
v.mkAttrs(attrs2);
|
||||
|
||||
@@ -35,7 +35,7 @@ void emitTreeAttrs(
|
||||
// FIXME: support arbitrary input attributes.
|
||||
|
||||
if (auto narHash = input.getNarHash())
|
||||
attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true), state.mem);
|
||||
attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true));
|
||||
|
||||
if (input.getType() == "git")
|
||||
attrs.alloc("submodules").mkBool(fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false));
|
||||
@@ -43,13 +43,13 @@ void emitTreeAttrs(
|
||||
if (!forceDirty) {
|
||||
|
||||
if (auto rev = input.getRev()) {
|
||||
attrs.alloc("rev").mkString(rev->gitRev(), state.mem);
|
||||
attrs.alloc("shortRev").mkString(rev->gitShortRev(), state.mem);
|
||||
attrs.alloc("rev").mkString(rev->gitRev());
|
||||
attrs.alloc("shortRev").mkString(rev->gitShortRev());
|
||||
} else if (emptyRevFallback) {
|
||||
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
|
||||
auto emptyHash = Hash(HashAlgorithm::SHA1);
|
||||
attrs.alloc("rev").mkString(emptyHash.gitRev(), state.mem);
|
||||
attrs.alloc("shortRev").mkString(emptyHash.gitShortRev(), state.mem);
|
||||
attrs.alloc("rev").mkString(emptyHash.gitRev());
|
||||
attrs.alloc("shortRev").mkString(emptyHash.gitShortRev());
|
||||
}
|
||||
|
||||
if (auto revCount = input.getRevCount())
|
||||
@@ -59,14 +59,13 @@ void emitTreeAttrs(
|
||||
}
|
||||
|
||||
if (auto dirtyRev = fetchers::maybeGetStrAttr(input.attrs, "dirtyRev")) {
|
||||
attrs.alloc("dirtyRev").mkString(*dirtyRev, state.mem);
|
||||
attrs.alloc("dirtyShortRev").mkString(*fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev"), state.mem);
|
||||
attrs.alloc("dirtyRev").mkString(*dirtyRev);
|
||||
attrs.alloc("dirtyShortRev").mkString(*fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev"));
|
||||
}
|
||||
|
||||
if (auto lastModified = input.getLastModified()) {
|
||||
attrs.alloc("lastModified").mkInt(*lastModified);
|
||||
attrs.alloc("lastModifiedDate")
|
||||
.mkString(fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S")), state.mem);
|
||||
attrs.alloc("lastModifiedDate").mkString(fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S")));
|
||||
}
|
||||
|
||||
v.mkAttrs(attrs);
|
||||
@@ -83,7 +82,7 @@ struct FetchTreeParams
|
||||
static void fetchTree(
|
||||
EvalState & state, const PosIdx pos, Value ** args, Value & v, const FetchTreeParams & params = FetchTreeParams{})
|
||||
{
|
||||
fetchers::Input input{};
|
||||
fetchers::Input input{state.fetchSettings};
|
||||
NixStringContext context;
|
||||
std::optional<std::string> type;
|
||||
auto fetcher = params.isFetchGit ? "fetchGit" : "fetchTree";
|
||||
@@ -151,6 +150,11 @@ static void fetchTree(
|
||||
attrs.emplace("exportIgnore", Explicit<bool>{true});
|
||||
}
|
||||
|
||||
// fetchTree should fetch git repos with shallow = true by default
|
||||
if (type == "git" && !params.isFetchGit && !attrs.contains("shallow")) {
|
||||
attrs.emplace("shallow", Explicit<bool>{true});
|
||||
}
|
||||
|
||||
if (!params.allowNameArgument)
|
||||
if (auto nameIter = attrs.find("name"); nameIter != attrs.end())
|
||||
state.error<EvalError>("argument 'name' isn’t supported in call to '%s'", fetcher)
|
||||
@@ -190,9 +194,9 @@ static void fetchTree(
|
||||
}
|
||||
|
||||
if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes))
|
||||
input = lookupInRegistries(state.fetchSettings, *state.store, input, fetchers::UseRegistries::Limited).first;
|
||||
input = lookupInRegistries(state.store, input, fetchers::UseRegistries::Limited).first;
|
||||
|
||||
if (state.settings.pureEval && !input.isLocked(state.fetchSettings)) {
|
||||
if (state.settings.pureEval && !input.isLocked()) {
|
||||
if (input.getNarHash())
|
||||
warn(
|
||||
"Input '%s' is unlocked (e.g. lacks a Git revision) but is checked by NAR hash. "
|
||||
@@ -215,8 +219,7 @@ static void fetchTree(
|
||||
throw Error("input '%s' is not allowed to use the '__final' attribute", input.to_string());
|
||||
}
|
||||
|
||||
auto cachedInput =
|
||||
state.inputCache->getAccessor(state.fetchSettings, *state.store, input, fetchers::UseRegistries::No);
|
||||
auto cachedInput = state.inputCache->getAccessor(state.store, input, fetchers::UseRegistries::No);
|
||||
|
||||
auto storePath = state.mountInput(cachedInput.lockedInput, input, cachedInput.accessor);
|
||||
|
||||
@@ -231,127 +234,229 @@ static void prim_fetchTree(EvalState & state, const PosIdx pos, Value ** args, V
|
||||
static RegisterPrimOp primop_fetchTree({
|
||||
.name = "fetchTree",
|
||||
.args = {"input"},
|
||||
.doc = []() -> std::string {
|
||||
std::string doc = stripIndentation(R"(
|
||||
Fetch a file system tree or a plain file using one of the supported backends and return an attribute set with:
|
||||
.doc = R"(
|
||||
Fetch a file system tree or a plain file using one of the supported backends and return an attribute set with:
|
||||
|
||||
- the resulting fixed-output [store path](@docroot@/store/store-path.md)
|
||||
- the corresponding [NAR](@docroot@/store/file-system-object/content-address.md#serial-nix-archive) hash
|
||||
- backend-specific metadata (currently not documented). <!-- TODO: document output attributes -->
|
||||
- the resulting fixed-output [store path](@docroot@/store/store-path.md)
|
||||
- the corresponding [NAR](@docroot@/store/file-system-object/content-address.md#serial-nix-archive) hash
|
||||
- backend-specific metadata (currently not documented). <!-- TODO: document output attributes -->
|
||||
|
||||
*input* must be an attribute set with the following attributes:
|
||||
*input* must be an attribute set with the following attributes:
|
||||
|
||||
- `type` (String, required)
|
||||
- `type` (String, required)
|
||||
|
||||
One of the [supported source types](#source-types).
|
||||
This determines other required and allowed input attributes.
|
||||
One of the [supported source types](#source-types).
|
||||
This determines other required and allowed input attributes.
|
||||
|
||||
- `narHash` (String, optional)
|
||||
- `narHash` (String, optional)
|
||||
|
||||
The `narHash` parameter can be used to substitute the source of the tree.
|
||||
It also allows for verification of tree contents that may not be provided by the underlying transfer mechanism.
|
||||
If `narHash` is set, the source is first looked up is the Nix store and [substituters](@docroot@/command-ref/conf-file.md#conf-substituters), and only fetched if not available.
|
||||
The `narHash` parameter can be used to substitute the source of the tree.
|
||||
It also allows for verification of tree contents that may not be provided by the underlying transfer mechanism.
|
||||
If `narHash` is set, the source is first looked up is the Nix store and [substituters](@docroot@/command-ref/conf-file.md#conf-substituters), and only fetched if not available.
|
||||
|
||||
A subset of the output attributes of `fetchTree` can be re-used for subsequent calls to `fetchTree` to produce the same result again.
|
||||
That is, `fetchTree` is idempotent.
|
||||
A subset of the output attributes of `fetchTree` can be re-used for subsequent calls to `fetchTree` to produce the same result again.
|
||||
That is, `fetchTree` is idempotent.
|
||||
|
||||
Downloads are cached in `$XDG_CACHE_HOME/nix`.
|
||||
The remote source is fetched from the network if both are true:
|
||||
- A NAR hash is supplied and the corresponding store path is not [valid](@docroot@/glossary.md#gloss-validity), that is, not available in the store
|
||||
Downloads are cached in `$XDG_CACHE_HOME/nix`.
|
||||
The remote source is fetched from the network if both are true:
|
||||
- A NAR hash is supplied and the corresponding store path is not [valid](@docroot@/glossary.md#gloss-validity), that is, not available in the store
|
||||
|
||||
> **Note**
|
||||
> **Note**
|
||||
>
|
||||
> [Substituters](@docroot@/command-ref/conf-file.md#conf-substituters) are not used in fetching.
|
||||
|
||||
- There is no cache entry or the cache entry is older than [`tarball-ttl`](@docroot@/command-ref/conf-file.md#conf-tarball-ttl)
|
||||
|
||||
## Source types
|
||||
|
||||
The following source types and associated input attributes are supported.
|
||||
|
||||
<!-- TODO: It would be soooo much more predictable to work with (and
|
||||
document) if `fetchTree` was a curried call with the first parameter for
|
||||
`type` or an attribute like `builtins.fetchTree.git`! -->
|
||||
|
||||
- `"file"`
|
||||
|
||||
Place a plain file into the Nix store.
|
||||
This is similar to [`builtins.fetchurl`](@docroot@/language/builtins.md#builtins-fetchurl)
|
||||
|
||||
- `url` (String, required)
|
||||
|
||||
Supported protocols:
|
||||
|
||||
- `https`
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> [Substituters](@docroot@/command-ref/conf-file.md#conf-substituters) are not used in fetching.
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "file";
|
||||
> url = "https://example.com/index.html";
|
||||
> }
|
||||
> ```
|
||||
|
||||
- There is no cache entry or the cache entry is older than [`tarball-ttl`](@docroot@/command-ref/conf-file.md#conf-tarball-ttl)
|
||||
- `http`
|
||||
|
||||
## Source types
|
||||
Insecure HTTP transfer for legacy sources.
|
||||
|
||||
The following source types and associated input attributes are supported.
|
||||
> **Warning**
|
||||
>
|
||||
> HTTP performs no encryption or authentication.
|
||||
> Use a `narHash` known in advance to ensure the output has expected contents.
|
||||
|
||||
<!-- TODO: It would be soooo much more predictable to work with (and
|
||||
document) if `fetchTree` was a curried call with the first parameter for
|
||||
`type` or an attribute like `builtins.fetchTree.git`! -->
|
||||
)");
|
||||
- `file`
|
||||
|
||||
auto indentString = [](std::string const & str, std::string const & indent) {
|
||||
std::string result;
|
||||
std::istringstream stream(str);
|
||||
std::string line;
|
||||
bool first = true;
|
||||
while (std::getline(stream, line)) {
|
||||
if (!first)
|
||||
result += "\n";
|
||||
result += indent + line;
|
||||
first = false;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
A file on the local file system.
|
||||
|
||||
for (const auto & [schemeName, scheme] : fetchers::getAllInputSchemes()) {
|
||||
doc += "\n- `" + quoteString(schemeName, '"') + "`\n\n";
|
||||
doc += indentString(scheme->schemeDescription(), " ");
|
||||
if (!doc.empty() && doc.back() != '\n')
|
||||
doc += "\n";
|
||||
> **Example**
|
||||
>
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "file";
|
||||
> url = "file:///home/eelco/nix/README.md";
|
||||
> }
|
||||
> ```
|
||||
|
||||
for (const auto & [attrName, attribute] : scheme->allowedAttrs()) {
|
||||
doc += "\n - `" + attrName + "` (" + attribute.type + ", "
|
||||
+ (attribute.required ? "required" : "optional") + ")\n\n";
|
||||
doc += indentString(stripIndentation(attribute.doc), " ");
|
||||
if (!doc.empty() && doc.back() != '\n')
|
||||
doc += "\n";
|
||||
}
|
||||
}
|
||||
- `"tarball"`
|
||||
|
||||
doc += "\n" + stripIndentation(R"(
|
||||
The following input types are still subject to change:
|
||||
Download a tar archive and extract it into the Nix store.
|
||||
This has the same underlying implementation as [`builtins.fetchTarball`](@docroot@/language/builtins.md#builtins-fetchTarball)
|
||||
|
||||
- `"path"`
|
||||
- `"github"`
|
||||
- `"gitlab"`
|
||||
- `"sourcehut"`
|
||||
- `"mercurial"`
|
||||
- `url` (String, required)
|
||||
|
||||
*input* can also be a [URL-like reference](@docroot@/command-ref/new-cli/nix3-flake.md#flake-references).
|
||||
The additional input types and the URL-like syntax requires the [`flakes` experimental feature](@docroot@/development/experimental-features.md#xp-feature-flakes) to be enabled.
|
||||
> **Example**
|
||||
>
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "tarball";
|
||||
> url = "https://github.com/NixOS/nixpkgs/tarball/nixpkgs-23.11";
|
||||
> }
|
||||
> ```
|
||||
|
||||
- `"git"`
|
||||
|
||||
Fetch a Git tree and copy it to the Nix store.
|
||||
This is similar to [`builtins.fetchGit`](@docroot@/language/builtins.md#builtins-fetchGit).
|
||||
|
||||
- `url` (String, required)
|
||||
|
||||
The URL formats supported are the same as for Git itself.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> Fetch a GitHub repository using the attribute set representation:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.fetchTree {
|
||||
> type = "github";
|
||||
> owner = "NixOS";
|
||||
> repo = "nixpkgs";
|
||||
> rev = "ae2e6b3958682513d28f7d633734571fb18285dd";
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> This evaluates to the following attribute set:
|
||||
>
|
||||
> ```nix
|
||||
> {
|
||||
> lastModified = 1686503798;
|
||||
> lastModifiedDate = "20230611171638";
|
||||
> narHash = "sha256-rA9RqKP9OlBrgGCPvfd5HVAXDOy8k2SmPtB/ijShNXc=";
|
||||
> outPath = "/nix/store/l5m6qlvfs9sdw14ja3qbzpglcjlb6j1x-source";
|
||||
> rev = "ae2e6b3958682513d28f7d633734571fb18285dd";
|
||||
> shortRev = "ae2e6b3";
|
||||
> fetchTree {
|
||||
> type = "git";
|
||||
> url = "git@github.com:NixOS/nixpkgs.git";
|
||||
> }
|
||||
> ```
|
||||
|
||||
> **Example**
|
||||
> **Note**
|
||||
>
|
||||
> Fetch the same GitHub repository using the URL-like syntax:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.fetchTree "github:NixOS/nixpkgs/ae2e6b3958682513d28f7d633734571fb18285dd"
|
||||
> ```
|
||||
)");
|
||||
> If the URL points to a local directory, and no `ref` or `rev` is given, Nix only considers files added to the Git index, as listed by `git ls-files` but use the *current file contents* of the Git working directory.
|
||||
|
||||
return doc;
|
||||
}(),
|
||||
- `ref` (String, optional)
|
||||
|
||||
By default, this has no effect. This becomes relevant only once `shallow` cloning is disabled.
|
||||
|
||||
A [Git reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References), such as a branch or tag name.
|
||||
|
||||
Default: `"HEAD"`
|
||||
|
||||
- `rev` (String, optional)
|
||||
|
||||
A Git revision; a commit hash.
|
||||
|
||||
Default: the tip of `ref`
|
||||
|
||||
- `shallow` (Bool, optional)
|
||||
|
||||
Make a shallow clone when fetching the Git tree.
|
||||
When this is enabled, the options `ref` and `allRefs` have no effect anymore.
|
||||
|
||||
Default: `true`
|
||||
|
||||
- `submodules` (Bool, optional)
|
||||
|
||||
Also fetch submodules if available.
|
||||
|
||||
Default: `false`
|
||||
|
||||
- `lfs` (Bool, optional)
|
||||
|
||||
Fetch any [Git LFS](https://git-lfs.com/) files.
|
||||
|
||||
Default: `false`
|
||||
|
||||
- `allRefs` (Bool, optional)
|
||||
|
||||
By default, this has no effect. This becomes relevant only once `shallow` cloning is disabled.
|
||||
|
||||
Whether to fetch all references (eg. branches and tags) of the repository.
|
||||
With this argument being true, it's possible to load a `rev` from *any* `ref`.
|
||||
(Without setting this option, only `rev`s from the specified `ref` are supported).
|
||||
|
||||
Default: `false`
|
||||
|
||||
- `lastModified` (Integer, optional)
|
||||
|
||||
Unix timestamp of the fetched commit.
|
||||
|
||||
If set, pass through the value to the output attribute set.
|
||||
Otherwise, generated from the fetched Git tree.
|
||||
|
||||
- `revCount` (Integer, optional)
|
||||
|
||||
Number of revisions in the history of the Git repository before the fetched commit.
|
||||
|
||||
If set, pass through the value to the output attribute set.
|
||||
Otherwise, generated from the fetched Git tree.
|
||||
|
||||
The following input types are still subject to change:
|
||||
|
||||
- `"path"`
|
||||
- `"github"`
|
||||
- `"gitlab"`
|
||||
- `"sourcehut"`
|
||||
- `"mercurial"`
|
||||
|
||||
*input* can also be a [URL-like reference](@docroot@/command-ref/new-cli/nix3-flake.md#flake-references).
|
||||
The additional input types and the URL-like syntax requires the [`flakes` experimental feature](@docroot@/development/experimental-features.md#xp-feature-flakes) to be enabled.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> Fetch a GitHub repository using the attribute set representation:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.fetchTree {
|
||||
> type = "github";
|
||||
> owner = "NixOS";
|
||||
> repo = "nixpkgs";
|
||||
> rev = "ae2e6b3958682513d28f7d633734571fb18285dd";
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> This evaluates to the following attribute set:
|
||||
>
|
||||
> ```nix
|
||||
> {
|
||||
> lastModified = 1686503798;
|
||||
> lastModifiedDate = "20230611171638";
|
||||
> narHash = "sha256-rA9RqKP9OlBrgGCPvfd5HVAXDOy8k2SmPtB/ijShNXc=";
|
||||
> outPath = "/nix/store/l5m6qlvfs9sdw14ja3qbzpglcjlb6j1x-source";
|
||||
> rev = "ae2e6b3958682513d28f7d633734571fb18285dd";
|
||||
> shortRev = "ae2e6b3";
|
||||
> }
|
||||
> ```
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> Fetch the same GitHub repository using the URL-like syntax:
|
||||
>
|
||||
> ```nix
|
||||
> builtins.fetchTree "github:NixOS/nixpkgs/ae2e6b3958682513d28f7d633734571fb18285dd"
|
||||
> ```
|
||||
)",
|
||||
.fun = prim_fetchTree,
|
||||
.experimentalFeature = Xp::FetchTree,
|
||||
});
|
||||
@@ -362,13 +467,10 @@ void prim_fetchFinalTree(EvalState & state, const PosIdx pos, Value ** args, Val
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_fetchFinalTree({
|
||||
.name = "__fetchFinalTree",
|
||||
.name = "fetchFinalTree",
|
||||
.args = {"input"},
|
||||
.doc = R"(
|
||||
Like `fetchTree`, but does not return any additional fetcher attributes (like `revCount`).
|
||||
This allows inputs to be substituted if `narHash` is specified.
|
||||
)",
|
||||
.fun = prim_fetchFinalTree,
|
||||
.internal = true,
|
||||
});
|
||||
|
||||
static void fetch(
|
||||
@@ -479,10 +581,10 @@ static void fetch(
|
||||
auto storePath = unpack ? fetchToStore(
|
||||
state.fetchSettings,
|
||||
*state.store,
|
||||
fetchers::downloadTarball(*state.store, state.fetchSettings, *url),
|
||||
fetchers::downloadTarball(state.store, state.fetchSettings, *url),
|
||||
FetchMode::Copy,
|
||||
name)
|
||||
: fetchers::downloadFile(*state.store, state.fetchSettings, *url, name).storePath;
|
||||
: fetchers::downloadFile(state.store, state.fetchSettings, *url, name).storePath;
|
||||
|
||||
if (expectedHash) {
|
||||
auto hash = unpack ? state.store->queryPathInfo(storePath)->narHash
|
||||
|
||||
@@ -126,7 +126,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
case toml::value_t::string: {
|
||||
auto s = toml::get<std::string_view>(t);
|
||||
forceNoNullByte(s);
|
||||
v.mkString(s, state.mem);
|
||||
v.mkString(s);
|
||||
} break;
|
||||
case toml::value_t::local_datetime:
|
||||
case toml::value_t::offset_datetime:
|
||||
@@ -142,7 +142,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
|
||||
s << t;
|
||||
auto str = s.view();
|
||||
forceNoNullByte(str);
|
||||
attrs.alloc("value").mkString(str, state.mem);
|
||||
attrs.alloc("value").mkString(str);
|
||||
v.mkAttrs(attrs);
|
||||
} else {
|
||||
throw std::runtime_error("Dates and times are not supported");
|
||||
|
||||
@@ -16,8 +16,6 @@ json printValueAsJSON(
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
auto _level = state.addCallDepth(pos);
|
||||
|
||||
if (strict)
|
||||
state.forceValue(v, pos);
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ TEST_F(GitUtilsTest, sink_basic)
|
||||
// sink->createHardlink("foo-1.1/links/foo-2", CanonPath("foo-1.1/hello"));
|
||||
|
||||
auto result = repo->dereferenceSingletonDirectory(sink->flush());
|
||||
auto accessor = repo->getAccessor(result, {}, getRepoName());
|
||||
auto accessor = repo->getAccessor(result, false, getRepoName());
|
||||
auto entries = accessor->readDirectory(CanonPath::root);
|
||||
ASSERT_EQ(entries.size(), 5u);
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("hello")), "hello world");
|
||||
|
||||
@@ -196,7 +196,7 @@ TEST_F(GitTest, submodulePeriodSupport)
|
||||
{"ref", "main"},
|
||||
});
|
||||
|
||||
auto [accessor, i] = input.getAccessor(settings, *store);
|
||||
auto [accessor, i] = input.getAccessor(store);
|
||||
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("deps/sub/lib.txt")), "hello from submodule\n");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "nix/fetchers/fetch-settings.hh"
|
||||
#include "nix/fetchers/fetch-to-store.hh"
|
||||
#include "nix/util/url.hh"
|
||||
#include "nix/util/archive.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -27,9 +26,18 @@ void registerInputScheme(std::shared_ptr<InputScheme> && inputScheme)
|
||||
throw Error("Input scheme with name %s already registered", schemeName);
|
||||
}
|
||||
|
||||
const InputSchemeMap & getAllInputSchemes()
|
||||
nlohmann::json dumpRegisterInputSchemeInfo()
|
||||
{
|
||||
return inputSchemes();
|
||||
using nlohmann::json;
|
||||
|
||||
auto res = json::object();
|
||||
|
||||
for (auto & [name, scheme] : inputSchemes()) {
|
||||
auto & r = res[name] = json::object();
|
||||
r["allowedAttrs"] = scheme->allowedAttrs();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Input Input::fromURL(const Settings & settings, const std::string & url, bool requireTree)
|
||||
@@ -81,7 +89,7 @@ Input Input::fromAttrs(const Settings & settings, Attrs && attrs)
|
||||
// but not all of them. Doing this is to support those other
|
||||
// operations which are supposed to be robust on
|
||||
// unknown/uninterpretable inputs.
|
||||
Input input;
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
fixupInput(input);
|
||||
return input;
|
||||
@@ -111,7 +119,7 @@ Input Input::fromAttrs(const Settings & settings, Attrs && attrs)
|
||||
return std::move(*res);
|
||||
}
|
||||
|
||||
std::optional<std::string> Input::getFingerprint(Store & store) const
|
||||
std::optional<std::string> Input::getFingerprint(ref<Store> store) const
|
||||
{
|
||||
if (!scheme)
|
||||
return std::nullopt;
|
||||
@@ -151,9 +159,9 @@ bool Input::isDirect() const
|
||||
return !scheme || scheme->isDirect(*this);
|
||||
}
|
||||
|
||||
bool Input::isLocked(const Settings & settings) const
|
||||
bool Input::isLocked() const
|
||||
{
|
||||
return scheme && scheme->isLocked(settings, *this);
|
||||
return scheme && scheme->isLocked(*this);
|
||||
}
|
||||
|
||||
bool Input::isFinal() const
|
||||
@@ -190,19 +198,19 @@ bool Input::contains(const Input & other) const
|
||||
}
|
||||
|
||||
// FIXME: remove
|
||||
std::pair<StorePath, Input> Input::fetchToStore(const Settings & settings, Store & store) const
|
||||
std::pair<StorePath, Input> Input::fetchToStore(ref<Store> store) const
|
||||
{
|
||||
if (!scheme)
|
||||
throw Error("cannot fetch unsupported input '%s'", attrsToJSON(toAttrs()));
|
||||
|
||||
auto [storePath, input] = [&]() -> std::pair<StorePath, Input> {
|
||||
try {
|
||||
auto [accessor, result] = getAccessorUnchecked(settings, store);
|
||||
auto [accessor, result] = getAccessorUnchecked(store);
|
||||
|
||||
auto storePath =
|
||||
nix::fetchToStore(settings, store, SourcePath(accessor), FetchMode::Copy, result.getName());
|
||||
nix::fetchToStore(*settings, *store, SourcePath(accessor), FetchMode::Copy, result.getName());
|
||||
|
||||
auto narHash = store.queryPathInfo(storePath)->narHash;
|
||||
auto narHash = store->queryPathInfo(storePath)->narHash;
|
||||
result.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true));
|
||||
|
||||
result.attrs.insert_or_assign("__final", Explicit<bool>(true));
|
||||
@@ -269,16 +277,30 @@ void Input::checkLocks(Input specified, Input & result)
|
||||
}
|
||||
}
|
||||
|
||||
if (auto prevLastModified = specified.getLastModified()) {
|
||||
if (result.getLastModified() != prevLastModified)
|
||||
throw Error(
|
||||
"'lastModified' attribute mismatch in input '%s', expected %d, got %d",
|
||||
result.to_string(),
|
||||
*prevLastModified,
|
||||
result.getLastModified().value_or(-1));
|
||||
}
|
||||
|
||||
if (auto prevRev = specified.getRev()) {
|
||||
if (result.getRev() != prevRev)
|
||||
throw Error("'rev' attribute mismatch in input '%s', expected %s", result.to_string(), prevRev->gitRev());
|
||||
}
|
||||
|
||||
if (auto prevRevCount = specified.getRevCount()) {
|
||||
if (result.getRevCount() != prevRevCount)
|
||||
throw Error("'revCount' attribute mismatch in input '%s', expected %d", result.to_string(), *prevRevCount);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input> Input::getAccessor(const Settings & settings, Store & store) const
|
||||
std::pair<ref<SourceAccessor>, Input> Input::getAccessor(ref<Store> store) const
|
||||
{
|
||||
try {
|
||||
auto [accessor, result] = getAccessorUnchecked(settings, store);
|
||||
auto [accessor, result] = getAccessorUnchecked(store);
|
||||
|
||||
result.attrs.insert_or_assign("__final", Explicit<bool>(true));
|
||||
|
||||
@@ -291,7 +313,7 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessor(const Settings & settin
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(const Settings & settings, Store & store) const
|
||||
std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> store) const
|
||||
{
|
||||
// FIXME: cache the accessor
|
||||
|
||||
@@ -311,13 +333,13 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(const Settings
|
||||
*/
|
||||
if (isFinal() && getNarHash()) {
|
||||
try {
|
||||
auto storePath = computeStorePath(store);
|
||||
auto storePath = computeStorePath(*store);
|
||||
|
||||
store.ensurePath(storePath);
|
||||
store->ensurePath(storePath);
|
||||
|
||||
debug("using substituted/cached input '%s' in '%s'", to_string(), store.printStorePath(storePath));
|
||||
debug("using substituted/cached input '%s' in '%s'", to_string(), store->printStorePath(storePath));
|
||||
|
||||
auto accessor = store.requireStoreObjectAccessor(storePath);
|
||||
auto accessor = store->requireStoreObjectAccessor(storePath);
|
||||
|
||||
accessor->fingerprint = getFingerprint(store);
|
||||
|
||||
@@ -327,7 +349,7 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(const Settings
|
||||
if (accessor->fingerprint) {
|
||||
ContentAddressMethod method = ContentAddressMethod::Raw::NixArchive;
|
||||
auto cacheKey = makeFetchToStoreCacheKey(getName(), *accessor->fingerprint, method, "/");
|
||||
settings.getCache()->upsert(cacheKey, store, {}, storePath);
|
||||
settings->getCache()->upsert(cacheKey, *store, {}, storePath);
|
||||
}
|
||||
|
||||
accessor->setPathDisplay("«" + to_string() + "»");
|
||||
@@ -338,7 +360,7 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(const Settings
|
||||
}
|
||||
}
|
||||
|
||||
auto [accessor, result] = scheme->getAccessor(settings, store, *this);
|
||||
auto [accessor, result] = scheme->getAccessor(store, *this);
|
||||
|
||||
if (!accessor->fingerprint)
|
||||
accessor->fingerprint = result.getFingerprint(store);
|
||||
@@ -355,10 +377,10 @@ Input Input::applyOverrides(std::optional<std::string> ref, std::optional<Hash>
|
||||
return scheme->applyOverrides(*this, ref, rev);
|
||||
}
|
||||
|
||||
void Input::clone(const Settings & settings, Store & store, const std::filesystem::path & destDir) const
|
||||
void Input::clone(const Path & destDir) const
|
||||
{
|
||||
assert(scheme);
|
||||
scheme->clone(settings, store, *this, destDir);
|
||||
scheme->clone(*this, destDir);
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> Input::getSourcePath() const
|
||||
@@ -471,19 +493,9 @@ void InputScheme::putFile(
|
||||
throw Error("input '%s' does not support modifying file '%s'", input.to_string(), path);
|
||||
}
|
||||
|
||||
void InputScheme::clone(
|
||||
const Settings & settings, Store & store, const Input & input, const std::filesystem::path & destDir) const
|
||||
void InputScheme::clone(const Input & input, const Path & destDir) const
|
||||
{
|
||||
if (std::filesystem::exists(destDir))
|
||||
throw Error("cannot clone into existing path %s", destDir);
|
||||
|
||||
auto [accessor, input2] = getAccessor(settings, store, input);
|
||||
|
||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying '%s' to %s...", input2.to_string(), destDir));
|
||||
|
||||
RestoreSink sink(/*startFsync=*/false);
|
||||
sink.dstPath = destDir;
|
||||
copyRecursive(*accessor, CanonPath::root, sink, CanonPath::root);
|
||||
throw Error("do not know how to clone input '%s'", input.to_string());
|
||||
}
|
||||
|
||||
std::optional<ExperimentalFeature> InputScheme::experimentalFeature() const
|
||||
|
||||
@@ -209,7 +209,7 @@ std::vector<nlohmann::json> Fetch::fetchUrls(const std::vector<Pointer> & pointe
|
||||
auto url = api.endpoint + "/objects/batch";
|
||||
const auto & authHeader = api.authHeader;
|
||||
FileTransferRequest request(parseURL(url));
|
||||
request.method = HttpMethod::Post;
|
||||
request.method = HttpMethod::POST;
|
||||
Headers headers;
|
||||
if (authHeader.has_value())
|
||||
headers.push_back({"Authorization", *authHeader});
|
||||
|
||||
@@ -541,15 +541,14 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
}
|
||||
|
||||
/**
|
||||
* A 'GitSourceAccessor' with no regard for export-ignore.
|
||||
* A 'GitSourceAccessor' with no regard for export-ignore or any other transformations.
|
||||
*/
|
||||
ref<GitSourceAccessor> getRawAccessor(const Hash & rev, const GitAccessorOptions & options);
|
||||
ref<GitSourceAccessor> getRawAccessor(const Hash & rev, bool smudgeLfs = false);
|
||||
|
||||
ref<SourceAccessor>
|
||||
getAccessor(const Hash & rev, const GitAccessorOptions & options, std::string displayPrefix) override;
|
||||
getAccessor(const Hash & rev, bool exportIgnore, std::string displayPrefix, bool smudgeLfs = false) override;
|
||||
|
||||
ref<SourceAccessor>
|
||||
getAccessor(const WorkdirInfo & wd, const GitAccessorOptions & options, MakeNotAllowedError e) override;
|
||||
ref<SourceAccessor> getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError e) override;
|
||||
|
||||
ref<GitFileSystemObjectSink> getFileSystemObjectSink() override;
|
||||
|
||||
@@ -669,7 +668,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
|
||||
Hash treeHashToNarHash(const fetchers::Settings & settings, const Hash & treeHash) override
|
||||
{
|
||||
auto accessor = getAccessor(treeHash, {}, "");
|
||||
auto accessor = getAccessor(treeHash, false, "");
|
||||
|
||||
fetchers::Cache::Key cacheKey{"treeHashToNarHash", {{"treeHash", treeHash.gitRev()}}};
|
||||
|
||||
@@ -717,17 +716,15 @@ struct GitSourceAccessor : SourceAccessor
|
||||
ref<GitRepoImpl> repo;
|
||||
Object root;
|
||||
std::optional<lfs::Fetch> lfsFetch = std::nullopt;
|
||||
GitAccessorOptions options;
|
||||
};
|
||||
|
||||
Sync<State> state_;
|
||||
|
||||
GitSourceAccessor(ref<GitRepoImpl> repo_, const Hash & rev, const GitAccessorOptions & options)
|
||||
GitSourceAccessor(ref<GitRepoImpl> repo_, const Hash & rev, bool smudgeLfs)
|
||||
: state_{State{
|
||||
.repo = repo_,
|
||||
.root = peelToTreeOrBlob(lookupObject(*repo_, hashToOID(rev)).get()),
|
||||
.lfsFetch = options.smudgeLfs ? std::make_optional(lfs::Fetch(*repo_, hashToOID(rev))) : std::nullopt,
|
||||
.options = options,
|
||||
.lfsFetch = smudgeLfs ? std::make_optional(lfs::Fetch(*repo_, hashToOID(rev))) : std::nullopt,
|
||||
}}
|
||||
{
|
||||
}
|
||||
@@ -1257,26 +1254,26 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||
}
|
||||
};
|
||||
|
||||
ref<GitSourceAccessor> GitRepoImpl::getRawAccessor(const Hash & rev, const GitAccessorOptions & options)
|
||||
ref<GitSourceAccessor> GitRepoImpl::getRawAccessor(const Hash & rev, bool smudgeLfs)
|
||||
{
|
||||
auto self = ref<GitRepoImpl>(shared_from_this());
|
||||
return make_ref<GitSourceAccessor>(self, rev, options);
|
||||
return make_ref<GitSourceAccessor>(self, rev, smudgeLfs);
|
||||
}
|
||||
|
||||
ref<SourceAccessor>
|
||||
GitRepoImpl::getAccessor(const Hash & rev, const GitAccessorOptions & options, std::string displayPrefix)
|
||||
GitRepoImpl::getAccessor(const Hash & rev, bool exportIgnore, std::string displayPrefix, bool smudgeLfs)
|
||||
{
|
||||
auto self = ref<GitRepoImpl>(shared_from_this());
|
||||
ref<GitSourceAccessor> rawGitAccessor = getRawAccessor(rev, options);
|
||||
ref<GitSourceAccessor> rawGitAccessor = getRawAccessor(rev, smudgeLfs);
|
||||
rawGitAccessor->setPathDisplay(std::move(displayPrefix));
|
||||
if (options.exportIgnore)
|
||||
if (exportIgnore)
|
||||
return make_ref<GitExportIgnoreSourceAccessor>(self, rawGitAccessor, rev);
|
||||
else
|
||||
return rawGitAccessor;
|
||||
}
|
||||
|
||||
ref<SourceAccessor> GitRepoImpl::getAccessor(
|
||||
const WorkdirInfo & wd, const GitAccessorOptions & options, MakeNotAllowedError makeNotAllowedError)
|
||||
ref<SourceAccessor>
|
||||
GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError)
|
||||
{
|
||||
auto self = ref<GitRepoImpl>(shared_from_this());
|
||||
ref<SourceAccessor> fileAccessor = AllowListSourceAccessor::create(
|
||||
@@ -1286,9 +1283,10 @@ ref<SourceAccessor> GitRepoImpl::getAccessor(
|
||||
boost::unordered_flat_set<CanonPath>{CanonPath::root},
|
||||
std::move(makeNotAllowedError))
|
||||
.cast<SourceAccessor>();
|
||||
if (options.exportIgnore)
|
||||
fileAccessor = make_ref<GitExportIgnoreSourceAccessor>(self, fileAccessor, std::nullopt);
|
||||
return fileAccessor;
|
||||
if (exportIgnore)
|
||||
return make_ref<GitExportIgnoreSourceAccessor>(self, fileAccessor, std::nullopt);
|
||||
else
|
||||
return fileAccessor;
|
||||
}
|
||||
|
||||
ref<GitFileSystemObjectSink> GitRepoImpl::getFileSystemObjectSink()
|
||||
@@ -1301,7 +1299,7 @@ std::vector<std::tuple<GitRepoImpl::Submodule, Hash>> GitRepoImpl::getSubmodules
|
||||
/* Read the .gitmodules files from this revision. */
|
||||
CanonPath modulesFile(".gitmodules");
|
||||
|
||||
auto accessor = getAccessor(rev, {.exportIgnore = exportIgnore}, "");
|
||||
auto accessor = getAccessor(rev, exportIgnore, "");
|
||||
if (!accessor->pathExists(modulesFile))
|
||||
return {};
|
||||
|
||||
@@ -1318,7 +1316,7 @@ std::vector<std::tuple<GitRepoImpl::Submodule, Hash>> GitRepoImpl::getSubmodules
|
||||
|
||||
std::vector<std::tuple<Submodule, Hash>> result;
|
||||
|
||||
auto rawAccessor = getRawAccessor(rev, {});
|
||||
auto rawAccessor = getRawAccessor(rev);
|
||||
|
||||
for (auto & submodule : parseSubmodules(pathTemp)) {
|
||||
/* Filter out .gitmodules entries that don't exist or are not
|
||||
@@ -1334,8 +1332,10 @@ namespace fetchers {
|
||||
|
||||
ref<GitRepo> Settings::getTarballCache() const
|
||||
{
|
||||
static auto repoDir = std::filesystem::path(getCacheDir()) / "tarball-cache";
|
||||
return GitRepo::openRepo(repoDir, true, true);
|
||||
auto tarballCache(_tarballCache.lock());
|
||||
if (!*tarballCache)
|
||||
*tarballCache = GitRepo::openRepo(std::filesystem::path(getCacheDir()) / "tarball-cache", true, true);
|
||||
return ref<GitRepo>(*tarballCache);
|
||||
}
|
||||
|
||||
} // namespace fetchers
|
||||
|
||||
@@ -194,183 +194,28 @@ struct GitInputScheme : InputScheme
|
||||
return "git";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
StringSet allowedAttrs() const override
|
||||
{
|
||||
return stripIndentation(R"(
|
||||
Fetch a Git tree and copy it to the Nix store.
|
||||
This is similar to [`builtins.fetchGit`](@docroot@/language/builtins.md#builtins-fetchGit).
|
||||
)");
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = {
|
||||
{
|
||||
"url",
|
||||
{
|
||||
.type = "String",
|
||||
.required = true,
|
||||
.doc = R"(
|
||||
The URL formats supported are the same as for Git itself.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "git";
|
||||
> url = "git@github.com:NixOS/nixpkgs.git";
|
||||
> }
|
||||
> ```
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> If the URL points to a local directory, and no `ref` or `rev` is given, Nix only considers files added to the Git index, as listed by `git ls-files` but uses the *current file contents* of the Git working directory.
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"ref",
|
||||
{
|
||||
.type = "String",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
By default, this has no effect. This becomes relevant only once `shallow` cloning is disabled.
|
||||
|
||||
A [Git reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References), such as a branch or tag name.
|
||||
|
||||
Default: `"HEAD"`
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"rev",
|
||||
{
|
||||
.type = "String",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
A Git revision; a commit hash.
|
||||
|
||||
Default: the tip of `ref`
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"shallow",
|
||||
{
|
||||
.type = "Bool",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
Make a shallow clone when fetching the Git tree.
|
||||
When this is enabled, the options `ref` and `allRefs` have no effect anymore.
|
||||
|
||||
Default: `true`
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"submodules",
|
||||
{
|
||||
.type = "Bool",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
Also fetch submodules if available.
|
||||
|
||||
Default: `false`
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"lfs",
|
||||
{
|
||||
.type = "Bool",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
Fetch any [Git LFS](https://git-lfs.com/) files.
|
||||
|
||||
Default: `false`
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"exportIgnore",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"lastModified",
|
||||
{
|
||||
.type = "Integer",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
Unix timestamp of the fetched commit.
|
||||
|
||||
If set, pass through the value to the output attribute set.
|
||||
Otherwise, generated from the fetched Git tree.
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"revCount",
|
||||
{
|
||||
.type = "Integer",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
Number of revisions in the history of the Git repository before the fetched commit.
|
||||
|
||||
If set, pass through the value to the output attribute set.
|
||||
Otherwise, generated from the fetched Git tree.
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"narHash",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"allRefs",
|
||||
{
|
||||
.type = "Bool",
|
||||
.required = false,
|
||||
.doc = R"(
|
||||
By default, this has no effect. This becomes relevant only once `shallow` cloning is disabled.
|
||||
|
||||
Whether to fetch all references (eg. branches and tags) of the repository.
|
||||
With this argument being true, it's possible to load a `rev` from *any* `ref`.
|
||||
(Without setting this option, only `rev`s from the specified `ref` are supported).
|
||||
|
||||
Default: `false`
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"dirtyRev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"dirtyShortRev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"verifyCommit",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"keytype",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"publicKey",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"publicKeys",
|
||||
{},
|
||||
},
|
||||
return {
|
||||
"url",
|
||||
"ref",
|
||||
"rev",
|
||||
"shallow",
|
||||
"submodules",
|
||||
"lfs",
|
||||
"exportIgnore",
|
||||
"lastModified",
|
||||
"revCount",
|
||||
"narHash",
|
||||
"allRefs",
|
||||
"name",
|
||||
"dirtyRev",
|
||||
"dirtyShortRev",
|
||||
"verifyCommit",
|
||||
"keytype",
|
||||
"publicKey",
|
||||
"publicKeys",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::optional<Input> inputFromAttrs(const Settings & settings, const Attrs & attrs) const override
|
||||
@@ -384,7 +229,7 @@ struct GitInputScheme : InputScheme
|
||||
if (auto ref = maybeGetStrAttr(attrs, "ref"); ref && !isLegalRefName(*ref))
|
||||
throw BadURL("invalid Git branch/tag name '%s'", *ref);
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
input.attrs["url"] = fixGitURL(getStrAttr(attrs, "url")).to_string();
|
||||
getShallowAttr(input);
|
||||
@@ -433,8 +278,7 @@ struct GitInputScheme : InputScheme
|
||||
return res;
|
||||
}
|
||||
|
||||
void clone(const Settings & settings, Store & store, const Input & input, const std::filesystem::path & destDir)
|
||||
const override
|
||||
void clone(const Input & input, const Path & destDir) const override
|
||||
{
|
||||
auto repoInfo = getRepoInfo(input);
|
||||
|
||||
@@ -778,25 +622,15 @@ struct GitInputScheme : InputScheme
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide whether we can do a shallow clone, which is faster. This is possible if the user explicitly specified
|
||||
* `shallow = true`, or if we already have a `revCount`.
|
||||
*/
|
||||
bool canDoShallow(const Input & input) const
|
||||
{
|
||||
bool shallow = getShallowAttr(input);
|
||||
return shallow || input.getRevCount().has_value();
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessorFromCommit(const Settings & settings, Store & store, RepoInfo & repoInfo, Input && input) const
|
||||
getAccessorFromCommit(ref<Store> store, RepoInfo & repoInfo, Input && input) const
|
||||
{
|
||||
assert(!repoInfo.workdirInfo.isDirty);
|
||||
|
||||
auto origRev = input.getRev();
|
||||
|
||||
auto originalRef = input.getRef();
|
||||
bool shallow = canDoShallow(input);
|
||||
bool shallow = getShallowAttr(input);
|
||||
auto ref = originalRef ? *originalRef : getDefaultRef(repoInfo, shallow);
|
||||
input.attrs.insert_or_assign("ref", ref);
|
||||
|
||||
@@ -807,27 +641,11 @@ struct GitInputScheme : InputScheme
|
||||
if (!input.getRev())
|
||||
input.attrs.insert_or_assign("rev", GitRepo::openRepo(repoDir)->resolveRef(ref).gitRev());
|
||||
} else {
|
||||
auto rev = input.getRev();
|
||||
auto repoUrl = std::get<ParsedURL>(repoInfo.location);
|
||||
std::filesystem::path cacheDir = getCachePath(repoUrl.to_string(), shallow);
|
||||
repoDir = cacheDir;
|
||||
repoInfo.gitDir = ".";
|
||||
|
||||
/* If shallow = false, but we have a non-shallow repo that already contains the desired rev, then use that
|
||||
* repo instead. */
|
||||
std::filesystem::path cacheDirNonShallow = getCachePath(repoUrl.to_string(), false);
|
||||
if (rev && shallow && pathExists(cacheDirNonShallow)) {
|
||||
auto nonShallowRepo = GitRepo::openRepo(cacheDirNonShallow, true, true);
|
||||
if (nonShallowRepo->hasObject(*rev)) {
|
||||
debug(
|
||||
"using non-shallow cached repo for '%s' since it contains rev '%s'",
|
||||
repoUrl.to_string(),
|
||||
rev->gitRev());
|
||||
repoDir = cacheDirNonShallow;
|
||||
goto have_rev;
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::create_directories(cacheDir.parent_path());
|
||||
PathLocks cacheDirLock({cacheDir.string()});
|
||||
|
||||
@@ -843,7 +661,7 @@ struct GitInputScheme : InputScheme
|
||||
|
||||
/* If a rev was specified, we need to fetch if it's not in the
|
||||
repo. */
|
||||
if (rev) {
|
||||
if (auto rev = input.getRev()) {
|
||||
doFetch = !repo->hasObject(*rev);
|
||||
} else {
|
||||
if (getAllRefsAttr(input)) {
|
||||
@@ -857,6 +675,7 @@ struct GitInputScheme : InputScheme
|
||||
}
|
||||
|
||||
if (doFetch) {
|
||||
bool shallow = getShallowAttr(input);
|
||||
try {
|
||||
auto fetchRef = getAllRefsAttr(input) ? "refs/*:refs/*"
|
||||
: input.getRev() ? input.getRev()->gitRev()
|
||||
@@ -884,7 +703,7 @@ struct GitInputScheme : InputScheme
|
||||
warn("could not update cached head '%s' for '%s'", ref, repoInfo.locationToArg());
|
||||
}
|
||||
|
||||
if (rev) {
|
||||
if (auto rev = input.getRev()) {
|
||||
if (!repo->hasObject(*rev))
|
||||
throw Error(
|
||||
"Cannot find Git revision '%s' in ref '%s' of repository '%s'! "
|
||||
@@ -901,30 +720,23 @@ struct GitInputScheme : InputScheme
|
||||
// the remainder
|
||||
}
|
||||
|
||||
have_rev:
|
||||
auto repo = GitRepo::openRepo(repoDir);
|
||||
|
||||
auto isShallow = repo->isShallow();
|
||||
|
||||
if (isShallow && !getShallowAttr(input))
|
||||
throw Error(
|
||||
"'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified",
|
||||
repoInfo.locationToArg());
|
||||
|
||||
// FIXME: check whether rev is an ancestor of ref?
|
||||
|
||||
auto rev = *input.getRev();
|
||||
|
||||
/* Skip lastModified computation if it's already supplied by the caller.
|
||||
We don't care if they specify an incorrect value; it doesn't
|
||||
matter for security, unlike narHash. */
|
||||
if (!input.attrs.contains("lastModified"))
|
||||
input.attrs.insert_or_assign("lastModified", getLastModified(settings, repoInfo, repoDir, rev));
|
||||
input.attrs.insert_or_assign("lastModified", getLastModified(*input.settings, repoInfo, repoDir, rev));
|
||||
|
||||
/* Like lastModified, skip revCount if supplied by the caller. */
|
||||
if (!shallow && !input.attrs.contains("revCount")) {
|
||||
auto isShallow = repo->isShallow();
|
||||
|
||||
if (isShallow && !shallow)
|
||||
throw Error(
|
||||
"'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified",
|
||||
repoInfo.locationToArg());
|
||||
|
||||
input.attrs.insert_or_assign("revCount", getRevCount(settings, repoInfo, repoDir, rev));
|
||||
}
|
||||
if (!getShallowAttr(input))
|
||||
input.attrs.insert_or_assign("revCount", getRevCount(*input.settings, repoInfo, repoDir, rev));
|
||||
|
||||
printTalkative("using revision %s of repo '%s'", rev.gitRev(), repoInfo.locationToArg());
|
||||
|
||||
@@ -932,8 +744,7 @@ struct GitInputScheme : InputScheme
|
||||
|
||||
bool exportIgnore = getExportIgnoreAttr(input);
|
||||
bool smudgeLfs = getLfsAttr(input);
|
||||
auto accessor = repo->getAccessor(
|
||||
rev, {.exportIgnore = exportIgnore, .smudgeLfs = smudgeLfs}, "«" + input.to_string() + "»");
|
||||
auto accessor = repo->getAccessor(rev, exportIgnore, "«" + input.to_string() + "»", smudgeLfs);
|
||||
|
||||
/* If the repo has submodules, fetch them and return a mounted
|
||||
input accessor consisting of the accessor for the top-level
|
||||
@@ -968,8 +779,8 @@ struct GitInputScheme : InputScheme
|
||||
attrs.insert_or_assign("submodules", Explicit<bool>{true});
|
||||
attrs.insert_or_assign("lfs", Explicit<bool>{smudgeLfs});
|
||||
attrs.insert_or_assign("allRefs", Explicit<bool>{true});
|
||||
auto submoduleInput = fetchers::Input::fromAttrs(settings, std::move(attrs));
|
||||
auto [submoduleAccessor, submoduleInput2] = submoduleInput.getAccessor(settings, store);
|
||||
auto submoduleInput = fetchers::Input::fromAttrs(*input.settings, std::move(attrs));
|
||||
auto [submoduleAccessor, submoduleInput2] = submoduleInput.getAccessor(store);
|
||||
submoduleAccessor->setPathDisplay("«" + submoduleInput.to_string() + "»");
|
||||
mounts.insert_or_assign(submodule.path, submoduleAccessor);
|
||||
}
|
||||
@@ -986,7 +797,7 @@ struct GitInputScheme : InputScheme
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessorFromWorkdir(const Settings & settings, Store & store, RepoInfo & repoInfo, Input && input) const
|
||||
getAccessorFromWorkdir(ref<Store> store, RepoInfo & repoInfo, Input && input) const
|
||||
{
|
||||
auto repoPath = repoInfo.getPath().value();
|
||||
|
||||
@@ -1000,7 +811,7 @@ struct GitInputScheme : InputScheme
|
||||
auto exportIgnore = getExportIgnoreAttr(input);
|
||||
|
||||
ref<SourceAccessor> accessor =
|
||||
repo->getAccessor(repoInfo.workdirInfo, {.exportIgnore = exportIgnore}, makeNotAllowedError(repoPath));
|
||||
repo->getAccessor(repoInfo.workdirInfo, exportIgnore, makeNotAllowedError(repoPath));
|
||||
|
||||
/* If the repo has submodules, return a mounted input accessor
|
||||
consisting of the accessor for the top-level repo and the
|
||||
@@ -1018,8 +829,8 @@ struct GitInputScheme : InputScheme
|
||||
// TODO: fall back to getAccessorFromCommit-like fetch when submodules aren't checked out
|
||||
// attrs.insert_or_assign("allRefs", Explicit<bool>{ true });
|
||||
|
||||
auto submoduleInput = fetchers::Input::fromAttrs(settings, std::move(attrs));
|
||||
auto [submoduleAccessor, submoduleInput2] = submoduleInput.getAccessor(settings, store);
|
||||
auto submoduleInput = fetchers::Input::fromAttrs(*input.settings, std::move(attrs));
|
||||
auto [submoduleAccessor, submoduleInput2] = submoduleInput.getAccessor(store);
|
||||
submoduleAccessor->setPathDisplay("«" + submoduleInput.to_string() + "»");
|
||||
|
||||
/* If the submodule is dirty, mark this repo dirty as
|
||||
@@ -1046,12 +857,12 @@ struct GitInputScheme : InputScheme
|
||||
input.attrs.insert_or_assign("rev", rev.gitRev());
|
||||
if (!getShallowAttr(input)) {
|
||||
input.attrs.insert_or_assign(
|
||||
"revCount", rev == nullRev ? 0 : getRevCount(settings, repoInfo, repoPath, rev));
|
||||
"revCount", rev == nullRev ? 0 : getRevCount(*input.settings, repoInfo, repoPath, rev));
|
||||
}
|
||||
|
||||
verifyCommit(input, repo);
|
||||
} else {
|
||||
repoInfo.warnDirty(settings);
|
||||
repoInfo.warnDirty(*input.settings);
|
||||
|
||||
if (repoInfo.workdirInfo.headRev) {
|
||||
input.attrs.insert_or_assign("dirtyRev", repoInfo.workdirInfo.headRev->gitRev() + "-dirty");
|
||||
@@ -1063,14 +874,14 @@ struct GitInputScheme : InputScheme
|
||||
|
||||
input.attrs.insert_or_assign(
|
||||
"lastModified",
|
||||
repoInfo.workdirInfo.headRev ? getLastModified(settings, repoInfo, repoPath, *repoInfo.workdirInfo.headRev)
|
||||
: 0);
|
||||
repoInfo.workdirInfo.headRev
|
||||
? getLastModified(*input.settings, repoInfo, repoPath, *repoInfo.workdirInfo.headRev)
|
||||
: 0);
|
||||
|
||||
return {accessor, std::move(input)};
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & _input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
|
||||
{
|
||||
Input input(_input);
|
||||
|
||||
@@ -1086,13 +897,13 @@ struct GitInputScheme : InputScheme
|
||||
}
|
||||
|
||||
auto [accessor, final] = input.getRef() || input.getRev() || !repoInfo.getPath()
|
||||
? getAccessorFromCommit(settings, store, repoInfo, std::move(input))
|
||||
: getAccessorFromWorkdir(settings, store, repoInfo, std::move(input));
|
||||
? getAccessorFromCommit(store, repoInfo, std::move(input))
|
||||
: getAccessorFromWorkdir(store, repoInfo, std::move(input));
|
||||
|
||||
return {accessor, std::move(final)};
|
||||
}
|
||||
|
||||
std::optional<std::string> getFingerprint(Store & store, const Input & input) const override
|
||||
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
||||
{
|
||||
auto makeFingerprint = [&](const Hash & rev) {
|
||||
return rev.gitRev() + (getSubmodulesAttr(input) ? ";s" : "") + (getExportIgnoreAttr(input) ? ";e" : "")
|
||||
@@ -1123,7 +934,7 @@ struct GitInputScheme : InputScheme
|
||||
}
|
||||
}
|
||||
|
||||
bool isLocked(const Settings & settings, const Input & input) const override
|
||||
bool isLocked(const Input & input) const override
|
||||
{
|
||||
auto rev = input.getRev();
|
||||
return rev && rev != nullRev;
|
||||
|
||||
@@ -92,7 +92,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
if (ref && rev)
|
||||
throw BadURL("URL '%s' contains both a commit hash and a branch/tag name %s %s", url, *ref, rev->gitRev());
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs.insert_or_assign("type", std::string{schemeName()});
|
||||
input.attrs.insert_or_assign("owner", path[0]);
|
||||
input.attrs.insert_or_assign("repo", path[1]);
|
||||
@@ -110,43 +110,18 @@ struct GitArchiveInputScheme : InputScheme
|
||||
return input;
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
StringSet allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = {
|
||||
{
|
||||
"owner",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"repo",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"ref",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"rev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"narHash",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"lastModified",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"host",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"treeHash",
|
||||
{},
|
||||
},
|
||||
return {
|
||||
"owner",
|
||||
"repo",
|
||||
"ref",
|
||||
"rev",
|
||||
"narHash",
|
||||
"lastModified",
|
||||
"host",
|
||||
"treeHash",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::optional<Input> inputFromAttrs(const fetchers::Settings & settings, const Attrs & attrs) const override
|
||||
@@ -154,7 +129,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
getStrAttr(attrs, "owner");
|
||||
getStrAttr(attrs, "repo");
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
return input;
|
||||
}
|
||||
@@ -258,9 +233,9 @@ struct GitArchiveInputScheme : InputScheme
|
||||
std::optional<Hash> treeHash;
|
||||
};
|
||||
|
||||
virtual RefInfo getRevFromRef(const Settings & settings, nix::Store & store, const Input & input) const = 0;
|
||||
virtual RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const = 0;
|
||||
|
||||
virtual DownloadUrl getDownloadUrl(const Settings & settings, const Input & input) const = 0;
|
||||
virtual DownloadUrl getDownloadUrl(const Input & input) const = 0;
|
||||
|
||||
struct TarballInfo
|
||||
{
|
||||
@@ -268,7 +243,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
time_t lastModified;
|
||||
};
|
||||
|
||||
std::pair<Input, TarballInfo> downloadArchive(const Settings & settings, Store & store, Input input) const
|
||||
std::pair<Input, TarballInfo> downloadArchive(ref<Store> store, Input input) const
|
||||
{
|
||||
if (!maybeGetStrAttr(input.attrs, "ref"))
|
||||
input.attrs.insert_or_assign("ref", "HEAD");
|
||||
@@ -277,7 +252,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
|
||||
auto rev = input.getRev();
|
||||
if (!rev) {
|
||||
auto refInfo = getRevFromRef(settings, store, input);
|
||||
auto refInfo = getRevFromRef(store, input);
|
||||
rev = refInfo.rev;
|
||||
upstreamTreeHash = refInfo.treeHash;
|
||||
debug("HEAD revision for '%s' is %s", input.to_string(), refInfo.rev.gitRev());
|
||||
@@ -286,7 +261,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
input.attrs.erase("ref");
|
||||
input.attrs.insert_or_assign("rev", rev->gitRev());
|
||||
|
||||
auto cache = settings.getCache();
|
||||
auto cache = input.settings->getCache();
|
||||
|
||||
Cache::Key treeHashKey{"gitRevToTreeHash", {{"rev", rev->gitRev()}}};
|
||||
Cache::Key lastModifiedKey{"gitRevToLastModified", {{"rev", rev->gitRev()}}};
|
||||
@@ -295,7 +270,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
if (auto lastModifiedAttrs = cache->lookup(lastModifiedKey)) {
|
||||
auto treeHash = getRevAttr(*treeHashAttrs, "treeHash");
|
||||
auto lastModified = getIntAttr(*lastModifiedAttrs, "lastModified");
|
||||
if (settings.getTarballCache()->hasObject(treeHash))
|
||||
if (input.settings->getTarballCache()->hasObject(treeHash))
|
||||
return {std::move(input), TarballInfo{.treeHash = treeHash, .lastModified = (time_t) lastModified}};
|
||||
else
|
||||
debug("Git tree with hash '%s' has disappeared from the cache, refetching...", treeHash.gitRev());
|
||||
@@ -303,7 +278,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
}
|
||||
|
||||
/* Stream the tarball into the tarball cache. */
|
||||
auto url = getDownloadUrl(settings, input);
|
||||
auto url = getDownloadUrl(input);
|
||||
|
||||
auto source = sinkToSource([&](Sink & sink) {
|
||||
FileTransferRequest req(url.url);
|
||||
@@ -315,7 +290,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
*logger, lvlInfo, actUnknown, fmt("unpacking '%s' into the Git cache", input.to_string()));
|
||||
|
||||
TarArchive archive{*source};
|
||||
auto tarballCache = settings.getTarballCache();
|
||||
auto tarballCache = input.settings->getTarballCache();
|
||||
auto parseSink = tarballCache->getFileSystemObjectSink();
|
||||
auto lastModified = unpackTarfileToSink(archive, *parseSink);
|
||||
auto tree = parseSink->flush();
|
||||
@@ -340,10 +315,9 @@ struct GitArchiveInputScheme : InputScheme
|
||||
return {std::move(input), tarballInfo};
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & _input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
|
||||
{
|
||||
auto [input, tarballInfo] = downloadArchive(settings, store, _input);
|
||||
auto [input, tarballInfo] = downloadArchive(store, _input);
|
||||
|
||||
#if 0
|
||||
input.attrs.insert_or_assign("treeHash", tarballInfo.treeHash.gitRev());
|
||||
@@ -351,18 +325,19 @@ struct GitArchiveInputScheme : InputScheme
|
||||
input.attrs.insert_or_assign("lastModified", uint64_t(tarballInfo.lastModified));
|
||||
|
||||
auto accessor =
|
||||
settings.getTarballCache()->getAccessor(tarballInfo.treeHash, {}, "«" + input.to_string() + "»");
|
||||
input.settings->getTarballCache()->getAccessor(tarballInfo.treeHash, false, "«" + input.to_string() + "»");
|
||||
|
||||
return {accessor, input};
|
||||
}
|
||||
|
||||
bool isLocked(const Settings & settings, const Input & input) const override
|
||||
bool isLocked(const Input & input) const override
|
||||
{
|
||||
/* Since we can't verify the integrity of the tarball from the
|
||||
Git revision alone, we also require a NAR hash for
|
||||
locking. FIXME: in the future, we may want to require a Git
|
||||
tree hash instead of a NAR hash. */
|
||||
return input.getRev().has_value() && (settings.trustTarballsFromGitForges || input.getNarHash().has_value());
|
||||
return input.getRev().has_value()
|
||||
&& (input.settings->trustTarballsFromGitForges || input.getNarHash().has_value());
|
||||
}
|
||||
|
||||
std::optional<ExperimentalFeature> experimentalFeature() const override
|
||||
@@ -370,7 +345,7 @@ struct GitArchiveInputScheme : InputScheme
|
||||
return Xp::Flakes;
|
||||
}
|
||||
|
||||
std::optional<std::string> getFingerprint(Store & store, const Input & input) const override
|
||||
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
||||
{
|
||||
if (auto rev = input.getRev())
|
||||
return rev->gitRev();
|
||||
@@ -386,12 +361,6 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||
return "github";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||
{
|
||||
// Github supports PAT/OAuth2 tokens and HTTP Basic
|
||||
@@ -418,7 +387,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||
return getStrAttr(input.attrs, "repo");
|
||||
}
|
||||
|
||||
RefInfo getRevFromRef(const Settings & settings, nix::Store & store, const Input & input) const override
|
||||
RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
||||
{
|
||||
auto host = getHost(input);
|
||||
auto url = fmt(
|
||||
@@ -428,22 +397,22 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||
getRepo(input),
|
||||
*input.getRef());
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(settings, host, input);
|
||||
Headers headers = makeHeadersWithAuthTokens(*input.settings, host, input);
|
||||
|
||||
auto downloadResult = downloadFile(store, settings, url, "source", headers);
|
||||
auto downloadResult = downloadFile(store, *input.settings, url, "source", headers);
|
||||
auto json = nlohmann::json::parse(
|
||||
store.requireStoreObjectAccessor(downloadResult.storePath)->readFile(CanonPath::root));
|
||||
store->requireStoreObjectAccessor(downloadResult.storePath)->readFile(CanonPath::root));
|
||||
|
||||
return RefInfo{
|
||||
.rev = Hash::parseAny(std::string{json["sha"]}, HashAlgorithm::SHA1),
|
||||
.treeHash = Hash::parseAny(std::string{json["commit"]["tree"]["sha"]}, HashAlgorithm::SHA1)};
|
||||
}
|
||||
|
||||
DownloadUrl getDownloadUrl(const Settings & settings, const Input & input) const override
|
||||
DownloadUrl getDownloadUrl(const Input & input) const override
|
||||
{
|
||||
auto host = getHost(input);
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(settings, host, input);
|
||||
Headers headers = makeHeadersWithAuthTokens(*input.settings, host, input);
|
||||
|
||||
// If we have no auth headers then we default to the public archive
|
||||
// urls so we do not run into rate limits.
|
||||
@@ -457,13 +426,12 @@ struct GitHubInputScheme : GitArchiveInputScheme
|
||||
return DownloadUrl{parseURL(url), headers};
|
||||
}
|
||||
|
||||
void clone(const Settings & settings, Store & store, const Input & input, const std::filesystem::path & destDir)
|
||||
const override
|
||||
void clone(const Input & input, const Path & destDir) const override
|
||||
{
|
||||
auto host = getHost(input);
|
||||
Input::fromURL(settings, fmt("git+https://%s/%s/%s.git", host, getOwner(input), getRepo(input)))
|
||||
Input::fromURL(*input.settings, fmt("git+https://%s/%s/%s.git", host, getOwner(input), getRepo(input)))
|
||||
.applyOverrides(input.getRef(), input.getRev())
|
||||
.clone(settings, store, destDir);
|
||||
.clone(destDir);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -474,12 +442,6 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||
return "gitlab";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||
{
|
||||
// Gitlab supports 4 kinds of authorization, two of which are
|
||||
@@ -499,7 +461,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||
return std::make_pair(token.substr(0, fldsplit), token.substr(fldsplit + 1));
|
||||
}
|
||||
|
||||
RefInfo getRevFromRef(const Settings & settings, nix::Store & store, const Input & input) const override
|
||||
RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
||||
{
|
||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
|
||||
// See rate limiting note below
|
||||
@@ -510,11 +472,11 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||
getStrAttr(input.attrs, "repo"),
|
||||
*input.getRef());
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(settings, host, input);
|
||||
Headers headers = makeHeadersWithAuthTokens(*input.settings, host, input);
|
||||
|
||||
auto downloadResult = downloadFile(store, settings, url, "source", headers);
|
||||
auto downloadResult = downloadFile(store, *input.settings, url, "source", headers);
|
||||
auto json = nlohmann::json::parse(
|
||||
store.requireStoreObjectAccessor(downloadResult.storePath)->readFile(CanonPath::root));
|
||||
store->requireStoreObjectAccessor(downloadResult.storePath)->readFile(CanonPath::root));
|
||||
|
||||
if (json.is_array() && json.size() >= 1 && json[0]["id"] != nullptr) {
|
||||
return RefInfo{.rev = Hash::parseAny(std::string(json[0]["id"]), HashAlgorithm::SHA1)};
|
||||
@@ -526,7 +488,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||
}
|
||||
}
|
||||
|
||||
DownloadUrl getDownloadUrl(const Settings & settings, const Input & input) const override
|
||||
DownloadUrl getDownloadUrl(const Input & input) const override
|
||||
{
|
||||
// This endpoint has a rate limit threshold that may be
|
||||
// server-specific and vary based whether the user is
|
||||
@@ -541,20 +503,19 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||
getStrAttr(input.attrs, "repo"),
|
||||
input.getRev()->to_string(HashFormat::Base16, false));
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(settings, host, input);
|
||||
Headers headers = makeHeadersWithAuthTokens(*input.settings, host, input);
|
||||
return DownloadUrl{parseURL(url), headers};
|
||||
}
|
||||
|
||||
void clone(const Settings & settings, Store & store, const Input & input, const std::filesystem::path & destDir)
|
||||
const override
|
||||
void clone(const Input & input, const Path & destDir) const override
|
||||
{
|
||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
|
||||
// FIXME: get username somewhere
|
||||
Input::fromURL(
|
||||
settings,
|
||||
*input.settings,
|
||||
fmt("git+https://%s/%s/%s.git", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
|
||||
.applyOverrides(input.getRef(), input.getRev())
|
||||
.clone(settings, store, destDir);
|
||||
.clone(destDir);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -565,12 +526,6 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||
return "sourcehut";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
|
||||
{
|
||||
// SourceHut supports both PAT and OAuth2. See
|
||||
@@ -581,7 +536,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||
// Once it is implemented, however, should work as expected.
|
||||
}
|
||||
|
||||
RefInfo getRevFromRef(const Settings & settings, nix::Store & store, const Input & input) const override
|
||||
RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
||||
{
|
||||
// TODO: In the future, when the sourcehut graphql API is implemented for mercurial
|
||||
// and with anonymous access, this method should use it instead.
|
||||
@@ -592,12 +547,12 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||
auto base_url =
|
||||
fmt("https://%s/%s/%s", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"));
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(settings, host, input);
|
||||
Headers headers = makeHeadersWithAuthTokens(*input.settings, host, input);
|
||||
|
||||
std::string refUri;
|
||||
if (ref == "HEAD") {
|
||||
auto downloadFileResult = downloadFile(store, settings, fmt("%s/HEAD", base_url), "source", headers);
|
||||
auto contents = store.requireStoreObjectAccessor(downloadFileResult.storePath)->readFile(CanonPath::root);
|
||||
auto downloadFileResult = downloadFile(store, *input.settings, fmt("%s/HEAD", base_url), "source", headers);
|
||||
auto contents = store->requireStoreObjectAccessor(downloadFileResult.storePath)->readFile(CanonPath::root);
|
||||
|
||||
auto remoteLine = git::parseLsRemoteLine(getLine(contents).first);
|
||||
if (!remoteLine) {
|
||||
@@ -609,8 +564,9 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||
}
|
||||
std::regex refRegex(refUri);
|
||||
|
||||
auto downloadFileResult = downloadFile(store, settings, fmt("%s/info/refs", base_url), "source", headers);
|
||||
auto contents = store.requireStoreObjectAccessor(downloadFileResult.storePath)->readFile(CanonPath::root);
|
||||
auto downloadFileResult =
|
||||
downloadFile(store, *input.settings, fmt("%s/info/refs", base_url), "source", headers);
|
||||
auto contents = store->requireStoreObjectAccessor(downloadFileResult.storePath)->readFile(CanonPath::root);
|
||||
std::istringstream is(contents);
|
||||
|
||||
std::string line;
|
||||
@@ -627,7 +583,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||
return RefInfo{.rev = Hash::parseAny(*id, HashAlgorithm::SHA1)};
|
||||
}
|
||||
|
||||
DownloadUrl getDownloadUrl(const Settings & settings, const Input & input) const override
|
||||
DownloadUrl getDownloadUrl(const Input & input) const override
|
||||
{
|
||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||
auto url =
|
||||
@@ -637,19 +593,18 @@ struct SourceHutInputScheme : GitArchiveInputScheme
|
||||
getStrAttr(input.attrs, "repo"),
|
||||
input.getRev()->to_string(HashFormat::Base16, false));
|
||||
|
||||
Headers headers = makeHeadersWithAuthTokens(settings, host, input);
|
||||
Headers headers = makeHeadersWithAuthTokens(*input.settings, host, input);
|
||||
return DownloadUrl{parseURL(url), headers};
|
||||
}
|
||||
|
||||
void clone(const Settings & settings, Store & store, const Input & input, const std::filesystem::path & destDir)
|
||||
const override
|
||||
void clone(const Input & input, const Path & destDir) const override
|
||||
{
|
||||
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
|
||||
Input::fromURL(
|
||||
settings,
|
||||
*input.settings,
|
||||
fmt("git+https://%s/%s/%s", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
|
||||
.applyOverrides(input.getRef(), input.getRev())
|
||||
.clone(settings, store, destDir);
|
||||
.clone(destDir);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@ struct Settings : public Config
|
||||
|
||||
private:
|
||||
mutable Sync<std::shared_ptr<Cache>> _cache;
|
||||
|
||||
mutable Sync<std::shared_ptr<GitRepo>> _tarballCache;
|
||||
};
|
||||
|
||||
} // namespace nix::fetchers
|
||||
|
||||
@@ -36,6 +36,13 @@ struct Input
|
||||
{
|
||||
friend struct InputScheme;
|
||||
|
||||
const Settings * settings;
|
||||
|
||||
Input(const Settings & settings)
|
||||
: settings{&settings}
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<InputScheme> scheme; // note: can be null
|
||||
Attrs attrs;
|
||||
|
||||
@@ -80,7 +87,7 @@ public:
|
||||
* attributes like a Git revision or NAR hash that uniquely
|
||||
* identify its contents.
|
||||
*/
|
||||
bool isLocked(const Settings & settings) const;
|
||||
bool isLocked() const;
|
||||
|
||||
/**
|
||||
* Only for relative path flakes, i.e. 'path:./foo', returns the
|
||||
@@ -113,7 +120,7 @@ public:
|
||||
* Fetch the entire input into the Nix store, returning the
|
||||
* location in the Nix store and the locked input.
|
||||
*/
|
||||
std::pair<StorePath, Input> fetchToStore(const Settings & settings, Store & store) const;
|
||||
std::pair<StorePath, Input> fetchToStore(ref<Store> store) const;
|
||||
|
||||
/**
|
||||
* Check the locking attributes in `result` against
|
||||
@@ -133,17 +140,17 @@ public:
|
||||
* input without copying it to the store. Also return a possibly
|
||||
* unlocked input.
|
||||
*/
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(const Settings & settings, Store & store) const;
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store) const;
|
||||
|
||||
private:
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessorUnchecked(const Settings & settings, Store & store) const;
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessorUnchecked(ref<Store> store) const;
|
||||
|
||||
public:
|
||||
|
||||
Input applyOverrides(std::optional<std::string> ref, std::optional<Hash> rev) const;
|
||||
|
||||
void clone(const Settings & settings, Store & store, const std::filesystem::path & destDir) const;
|
||||
void clone(const Path & destDir) const;
|
||||
|
||||
std::optional<std::filesystem::path> getSourcePath() const;
|
||||
|
||||
@@ -173,7 +180,7 @@ public:
|
||||
*
|
||||
* This is not a stable identifier between Nix versions, but not guaranteed to change either.
|
||||
*/
|
||||
std::optional<std::string> getFingerprint(Store & store) const;
|
||||
std::optional<std::string> getFingerprint(ref<Store> store) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -203,34 +210,20 @@ struct InputScheme
|
||||
*/
|
||||
virtual std::string_view schemeName() const = 0;
|
||||
|
||||
/**
|
||||
* Longform description of this scheme, for documentation purposes.
|
||||
*/
|
||||
virtual std::string schemeDescription() const = 0;
|
||||
|
||||
// TODO remove these defaults
|
||||
struct AttributeInfo
|
||||
{
|
||||
const char * type = "String";
|
||||
bool required = true;
|
||||
const char * doc = "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Allowed attributes in an attribute set that is converted to an
|
||||
* input, and documentation for each attribute.
|
||||
* input.
|
||||
*
|
||||
* `type` is not included from this map, because the `type` field is
|
||||
* `type` is not included from this set, because the `type` field is
|
||||
parsed first to choose which scheme; `type` is always required.
|
||||
*/
|
||||
virtual const std::map<std::string, AttributeInfo> & allowedAttrs() const = 0;
|
||||
virtual StringSet allowedAttrs() const = 0;
|
||||
|
||||
virtual ParsedURL toURL(const Input & input) const;
|
||||
|
||||
virtual Input applyOverrides(const Input & input, std::optional<std::string> ref, std::optional<Hash> rev) const;
|
||||
|
||||
virtual void
|
||||
clone(const Settings & settings, Store & store, const Input & input, const std::filesystem::path & destDir) const;
|
||||
virtual void clone(const Input & input, const Path & destDir) const;
|
||||
|
||||
virtual std::optional<std::filesystem::path> getSourcePath(const Input & input) const;
|
||||
|
||||
@@ -240,8 +233,7 @@ struct InputScheme
|
||||
std::string_view contents,
|
||||
std::optional<std::string> commitMsg) const;
|
||||
|
||||
virtual std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & input) const = 0;
|
||||
virtual std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & input) const = 0;
|
||||
|
||||
/**
|
||||
* Is this `InputScheme` part of an experimental feature?
|
||||
@@ -253,12 +245,12 @@ struct InputScheme
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual std::optional<std::string> getFingerprint(Store & store, const Input & input) const
|
||||
virtual std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
virtual bool isLocked(const Settings & settings, const Input & input) const
|
||||
virtual bool isLocked(const Input & input) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -277,12 +269,7 @@ struct InputScheme
|
||||
|
||||
void registerInputScheme(std::shared_ptr<InputScheme> && fetcher);
|
||||
|
||||
using InputSchemeMap = std::map<std::string_view, std::shared_ptr<InputScheme>>;
|
||||
|
||||
/**
|
||||
* Use this for docs, not for finding a specific scheme
|
||||
*/
|
||||
const InputSchemeMap & getAllInputSchemes();
|
||||
nlohmann::json dumpRegisterInputSchemeInfo();
|
||||
|
||||
struct PublicKey
|
||||
{
|
||||
|
||||
@@ -22,12 +22,6 @@ struct GitFileSystemObjectSink : ExtendedFileSystemObjectSink
|
||||
virtual Hash flush() = 0;
|
||||
};
|
||||
|
||||
struct GitAccessorOptions
|
||||
{
|
||||
bool exportIgnore = false;
|
||||
bool smudgeLfs = false;
|
||||
};
|
||||
|
||||
struct GitRepo
|
||||
{
|
||||
virtual ~GitRepo() {}
|
||||
@@ -95,10 +89,10 @@ struct GitRepo
|
||||
virtual bool hasObject(const Hash & oid) = 0;
|
||||
|
||||
virtual ref<SourceAccessor>
|
||||
getAccessor(const Hash & rev, const GitAccessorOptions & options, std::string displayPrefix) = 0;
|
||||
getAccessor(const Hash & rev, bool exportIgnore, std::string displayPrefix, bool smudgeLfs = false) = 0;
|
||||
|
||||
virtual ref<SourceAccessor> getAccessor(
|
||||
const WorkdirInfo & wd, const GitAccessorOptions & options, MakeNotAllowedError makeNotAllowedError) = 0;
|
||||
virtual ref<SourceAccessor>
|
||||
getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError) = 0;
|
||||
|
||||
virtual ref<GitFileSystemObjectSink> getFileSystemObjectSink() = 0;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace nix::fetchers {
|
||||
|
||||
enum class UseRegistries : int;
|
||||
struct Settings;
|
||||
|
||||
struct InputCache
|
||||
{
|
||||
@@ -15,8 +14,7 @@ struct InputCache
|
||||
Attrs extraAttrs;
|
||||
};
|
||||
|
||||
CachedResult
|
||||
getAccessor(const Settings & settings, Store & store, const Input & originalInput, UseRegistries useRegistries);
|
||||
CachedResult getAccessor(ref<Store> store, const Input & originalInput, UseRegistries useRegistries);
|
||||
|
||||
struct CachedInput
|
||||
{
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace nix::fetchers {
|
||||
|
||||
struct Registry
|
||||
{
|
||||
const Settings & settings;
|
||||
|
||||
enum RegistryType {
|
||||
Flag = 0,
|
||||
User = 1,
|
||||
@@ -32,8 +34,9 @@ struct Registry
|
||||
|
||||
std::vector<Entry> entries;
|
||||
|
||||
Registry(RegistryType type)
|
||||
: type{type}
|
||||
Registry(const Settings & settings, RegistryType type)
|
||||
: settings{settings}
|
||||
, type{type}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -54,7 +57,7 @@ std::shared_ptr<Registry> getCustomRegistry(const Settings & settings, const Pat
|
||||
|
||||
Path getUserRegistryPath();
|
||||
|
||||
Registries getRegistries(const Settings & settings, Store & store);
|
||||
Registries getRegistries(const Settings & settings, ref<Store> store);
|
||||
|
||||
void overrideRegistry(const Input & from, const Input & to, const Attrs & extraAttrs);
|
||||
|
||||
@@ -68,7 +71,6 @@ enum class UseRegistries : int {
|
||||
* Rewrite a flakeref using the registries. If `filter` is set, only
|
||||
* use the registries for which the filter function returns true.
|
||||
*/
|
||||
std::pair<Input, Attrs>
|
||||
lookupInRegistries(const Settings & settings, Store & store, const Input & input, UseRegistries useRegistries);
|
||||
std::pair<Input, Attrs> lookupInRegistries(ref<Store> store, const Input & input, UseRegistries useRegistries);
|
||||
|
||||
} // namespace nix::fetchers
|
||||
|
||||
@@ -25,7 +25,7 @@ struct DownloadFileResult
|
||||
};
|
||||
|
||||
DownloadFileResult downloadFile(
|
||||
Store & store,
|
||||
ref<Store> store,
|
||||
const Settings & settings,
|
||||
const std::string & url,
|
||||
const std::string & name,
|
||||
@@ -43,6 +43,6 @@ struct DownloadTarballResult
|
||||
* Download and import a tarball into the Git cache. The result is the
|
||||
* Git tree hash of the root directory.
|
||||
*/
|
||||
ref<SourceAccessor> downloadTarball(Store & store, const Settings & settings, const std::string & url);
|
||||
ref<SourceAccessor> downloadTarball(ref<Store> store, const Settings & settings, const std::string & url);
|
||||
|
||||
} // namespace nix::fetchers
|
||||
|
||||
@@ -44,7 +44,7 @@ struct IndirectInputScheme : InputScheme
|
||||
|
||||
// FIXME: forbid query params?
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs.insert_or_assign("type", "indirect");
|
||||
input.attrs.insert_or_assign("id", id);
|
||||
if (rev)
|
||||
@@ -60,33 +60,14 @@ struct IndirectInputScheme : InputScheme
|
||||
return "indirect";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
StringSet allowedAttrs() const override
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = {
|
||||
{
|
||||
"id",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"ref",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"rev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"narHash",
|
||||
{},
|
||||
},
|
||||
return {
|
||||
"id",
|
||||
"ref",
|
||||
"rev",
|
||||
"narHash",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::optional<Input> inputFromAttrs(const Settings & settings, const Attrs & attrs) const override
|
||||
@@ -95,7 +76,7 @@ struct IndirectInputScheme : InputScheme
|
||||
if (!std::regex_match(id, flakeRegex))
|
||||
throw BadURL("'%s' is not a valid flake ID", id);
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
return input;
|
||||
}
|
||||
@@ -125,8 +106,7 @@ struct IndirectInputScheme : InputScheme
|
||||
return input;
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & input) const override
|
||||
{
|
||||
throw Error("indirect input '%s' cannot be fetched directly", input.to_string());
|
||||
}
|
||||
|
||||
@@ -5,23 +5,23 @@
|
||||
|
||||
namespace nix::fetchers {
|
||||
|
||||
InputCache::CachedResult InputCache::getAccessor(
|
||||
const Settings & settings, Store & store, const Input & originalInput, UseRegistries useRegistries)
|
||||
InputCache::CachedResult
|
||||
InputCache::getAccessor(ref<Store> store, const Input & originalInput, UseRegistries useRegistries)
|
||||
{
|
||||
auto fetched = lookup(originalInput);
|
||||
Input resolvedInput = originalInput;
|
||||
|
||||
if (!fetched) {
|
||||
if (originalInput.isDirect()) {
|
||||
auto [accessor, lockedInput] = originalInput.getAccessor(settings, store);
|
||||
auto [accessor, lockedInput] = originalInput.getAccessor(store);
|
||||
fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor});
|
||||
} else {
|
||||
if (useRegistries != UseRegistries::No) {
|
||||
auto [res, extraAttrs] = lookupInRegistries(settings, store, originalInput, useRegistries);
|
||||
auto [res, extraAttrs] = lookupInRegistries(store, originalInput, useRegistries);
|
||||
resolvedInput = std::move(res);
|
||||
fetched = lookup(resolvedInput);
|
||||
if (!fetched) {
|
||||
auto [accessor, lockedInput] = resolvedInput.getAccessor(settings, store);
|
||||
auto [accessor, lockedInput] = resolvedInput.getAccessor(store);
|
||||
fetched.emplace(
|
||||
CachedInput{.lockedInput = lockedInput, .accessor = accessor, .extraAttrs = extraAttrs});
|
||||
}
|
||||
|
||||
@@ -68,41 +68,16 @@ struct MercurialInputScheme : InputScheme
|
||||
return "hg";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
StringSet allowedAttrs() const override
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = {
|
||||
{
|
||||
"url",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"ref",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"rev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"revCount",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"narHash",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"name",
|
||||
{},
|
||||
},
|
||||
return {
|
||||
"url",
|
||||
"ref",
|
||||
"rev",
|
||||
"revCount",
|
||||
"narHash",
|
||||
"name",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::optional<Input> inputFromAttrs(const Settings & settings, const Attrs & attrs) const override
|
||||
@@ -114,7 +89,7 @@ struct MercurialInputScheme : InputScheme
|
||||
throw BadURL("invalid Mercurial branch/tag name '%s'", *ref);
|
||||
}
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
return input;
|
||||
}
|
||||
@@ -179,7 +154,7 @@ struct MercurialInputScheme : InputScheme
|
||||
return {isLocal, isLocal ? renderUrlPathEnsureLegal(url.path) : url.to_string()};
|
||||
}
|
||||
|
||||
StorePath fetchToStore(const Settings & settings, Store & store, Input & input) const
|
||||
StorePath fetchToStore(ref<Store> store, Input & input) const
|
||||
{
|
||||
auto origRev = input.getRev();
|
||||
|
||||
@@ -201,10 +176,10 @@ struct MercurialInputScheme : InputScheme
|
||||
/* This is an unclean working tree. So copy all tracked
|
||||
files. */
|
||||
|
||||
if (!settings.allowDirty)
|
||||
if (!input.settings->allowDirty)
|
||||
throw Error("Mercurial tree '%s' is unclean", actualUrl);
|
||||
|
||||
if (settings.warnDirty)
|
||||
if (input.settings->warnDirty)
|
||||
warn("Mercurial tree '%s' is unclean", actualUrl);
|
||||
|
||||
input.attrs.insert_or_assign("ref", chomp(runHg({"branch", "-R", actualUrl})));
|
||||
@@ -230,7 +205,7 @@ struct MercurialInputScheme : InputScheme
|
||||
return files.count(file);
|
||||
};
|
||||
|
||||
auto storePath = store.addToStore(
|
||||
auto storePath = store->addToStore(
|
||||
input.getName(),
|
||||
{getFSSourceAccessor(), CanonPath(actualPath)},
|
||||
ContentAddressMethod::Raw::NixArchive,
|
||||
@@ -251,7 +226,7 @@ struct MercurialInputScheme : InputScheme
|
||||
"Hash '%s' is not supported by Mercurial. Only sha1 is supported.",
|
||||
rev.to_string(HashFormat::Base16, true));
|
||||
|
||||
return Cache::Key{"hgRev", {{"store", store.storeDir}, {"name", name}, {"rev", input.getRev()->gitRev()}}};
|
||||
return Cache::Key{"hgRev", {{"store", store->storeDir}, {"name", name}, {"rev", input.getRev()->gitRev()}}};
|
||||
};
|
||||
|
||||
auto makeResult = [&](const Attrs & infoAttrs, const StorePath & storePath) -> StorePath {
|
||||
@@ -265,13 +240,13 @@ struct MercurialInputScheme : InputScheme
|
||||
Cache::Key refToRevKey{"hgRefToRev", {{"url", actualUrl}, {"ref", *input.getRef()}}};
|
||||
|
||||
if (!input.getRev()) {
|
||||
if (auto res = settings.getCache()->lookupWithTTL(refToRevKey))
|
||||
if (auto res = input.settings->getCache()->lookupWithTTL(refToRevKey))
|
||||
input.attrs.insert_or_assign("rev", getRevAttr(*res, "rev").gitRev());
|
||||
}
|
||||
|
||||
/* If we have a rev, check if we have a cached store path. */
|
||||
if (auto rev = input.getRev()) {
|
||||
if (auto res = settings.getCache()->lookupStorePath(revInfoKey(*rev), store))
|
||||
if (auto res = input.settings->getCache()->lookupStorePath(revInfoKey(*rev), *store))
|
||||
return makeResult(res->value, res->storePath);
|
||||
}
|
||||
|
||||
@@ -325,7 +300,7 @@ struct MercurialInputScheme : InputScheme
|
||||
|
||||
/* Now that we have the rev, check the cache again for a
|
||||
cached store path. */
|
||||
if (auto res = settings.getCache()->lookupStorePath(revInfoKey(rev), store))
|
||||
if (auto res = input.settings->getCache()->lookupStorePath(revInfoKey(rev), *store))
|
||||
return makeResult(res->value, res->storePath);
|
||||
|
||||
Path tmpDir = createTempDir();
|
||||
@@ -335,39 +310,38 @@ struct MercurialInputScheme : InputScheme
|
||||
|
||||
deletePath(tmpDir + "/.hg_archival.txt");
|
||||
|
||||
auto storePath = store.addToStore(name, {getFSSourceAccessor(), CanonPath(tmpDir)});
|
||||
auto storePath = store->addToStore(name, {getFSSourceAccessor(), CanonPath(tmpDir)});
|
||||
|
||||
Attrs infoAttrs({
|
||||
{"revCount", (uint64_t) revCount},
|
||||
});
|
||||
|
||||
if (!origRev)
|
||||
settings.getCache()->upsert(refToRevKey, {{"rev", rev.gitRev()}});
|
||||
input.settings->getCache()->upsert(refToRevKey, {{"rev", rev.gitRev()}});
|
||||
|
||||
settings.getCache()->upsert(revInfoKey(rev), store, infoAttrs, storePath);
|
||||
input.settings->getCache()->upsert(revInfoKey(rev), *store, infoAttrs, storePath);
|
||||
|
||||
return makeResult(infoAttrs, std::move(storePath));
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & _input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
|
||||
{
|
||||
Input input(_input);
|
||||
|
||||
auto storePath = fetchToStore(settings, store, input);
|
||||
auto accessor = store.requireStoreObjectAccessor(storePath);
|
||||
auto storePath = fetchToStore(store, input);
|
||||
auto accessor = store->requireStoreObjectAccessor(storePath);
|
||||
|
||||
accessor->setPathDisplay("«" + input.to_string() + "»");
|
||||
|
||||
return {accessor, input};
|
||||
}
|
||||
|
||||
bool isLocked(const Settings & settings, const Input & input) const override
|
||||
bool isLocked(const Input & input) const override
|
||||
{
|
||||
return (bool) input.getRev();
|
||||
}
|
||||
|
||||
std::optional<std::string> getFingerprint(Store & store, const Input & input) const override
|
||||
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
||||
{
|
||||
if (auto rev = input.getRev())
|
||||
return rev->gitRev();
|
||||
|
||||
@@ -17,7 +17,7 @@ struct PathInputScheme : InputScheme
|
||||
if (url.authority && url.authority->host.size())
|
||||
throw Error("path URL '%s' should not have an authority ('%s')", url, *url.authority);
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs.insert_or_assign("type", "path");
|
||||
input.attrs.insert_or_assign("path", renderUrlPathEnsureLegal(url.path));
|
||||
|
||||
@@ -40,49 +40,27 @@ struct PathInputScheme : InputScheme
|
||||
return "path";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
StringSet allowedAttrs() const override
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = {
|
||||
{
|
||||
"path",
|
||||
{},
|
||||
},
|
||||
return {
|
||||
"path",
|
||||
/* Allow the user to pass in "fake" tree info
|
||||
attributes. This is useful for making a pinned tree work
|
||||
the same as the repository from which is exported (e.g.
|
||||
path:/nix/store/...-source?lastModified=1585388205&rev=b0c285...).
|
||||
*/
|
||||
{
|
||||
"rev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"revCount",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"lastModified",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"narHash",
|
||||
{},
|
||||
},
|
||||
"rev",
|
||||
"revCount",
|
||||
"lastModified",
|
||||
"narHash",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::optional<Input> inputFromAttrs(const Settings & settings, const Attrs & attrs) const override
|
||||
{
|
||||
getStrAttr(attrs, "path");
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
return input;
|
||||
}
|
||||
@@ -123,7 +101,7 @@ struct PathInputScheme : InputScheme
|
||||
return path;
|
||||
}
|
||||
|
||||
bool isLocked(const Settings & settings, const Input & input) const override
|
||||
bool isLocked(const Input & input) const override
|
||||
{
|
||||
return (bool) input.getNarHash();
|
||||
}
|
||||
@@ -138,8 +116,7 @@ struct PathInputScheme : InputScheme
|
||||
throw Error("cannot fetch input '%s' because it uses a relative path", input.to_string());
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & _input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
|
||||
{
|
||||
Input input(_input);
|
||||
auto path = getStrAttr(input.attrs, "path");
|
||||
@@ -147,31 +124,31 @@ struct PathInputScheme : InputScheme
|
||||
auto absPath = getAbsPath(input);
|
||||
|
||||
// FIXME: check whether access to 'path' is allowed.
|
||||
auto storePath = store.maybeParseStorePath(absPath.string());
|
||||
auto storePath = store->maybeParseStorePath(absPath.string());
|
||||
|
||||
if (storePath)
|
||||
store.addTempRoot(*storePath);
|
||||
store->addTempRoot(*storePath);
|
||||
|
||||
time_t mtime = 0;
|
||||
if (!storePath || storePath->name() != "source" || !store.isValidPath(*storePath)) {
|
||||
if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath)) {
|
||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying %s to the store", absPath));
|
||||
// FIXME: try to substitute storePath.
|
||||
auto src = sinkToSource(
|
||||
[&](Sink & sink) { mtime = dumpPathAndGetMtime(absPath.string(), sink, defaultPathFilter); });
|
||||
storePath = store.addToStoreFromDump(*src, "source");
|
||||
storePath = store->addToStoreFromDump(*src, "source");
|
||||
}
|
||||
|
||||
auto accessor = store.requireStoreObjectAccessor(*storePath);
|
||||
auto accessor = store->requireStoreObjectAccessor(*storePath);
|
||||
|
||||
// To prevent `fetchToStore()` copying the path again to Nix
|
||||
// store, pre-create an entry in the fetcher cache.
|
||||
auto info = store.queryPathInfo(*storePath);
|
||||
auto info = store->queryPathInfo(*storePath);
|
||||
accessor->fingerprint =
|
||||
fmt("path:%s", store.queryPathInfo(*storePath)->narHash.to_string(HashFormat::SRI, true));
|
||||
settings.getCache()->upsert(
|
||||
fmt("path:%s", store->queryPathInfo(*storePath)->narHash.to_string(HashFormat::SRI, true));
|
||||
input.settings->getCache()->upsert(
|
||||
makeFetchToStoreCacheKey(
|
||||
input.getName(), *accessor->fingerprint, ContentAddressMethod::Raw::NixArchive, "/"),
|
||||
store,
|
||||
*store,
|
||||
{},
|
||||
*storePath);
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ std::shared_ptr<Registry> Registry::read(const Settings & settings, const Source
|
||||
{
|
||||
debug("reading registry '%s'", path);
|
||||
|
||||
auto registry = std::make_shared<Registry>(type);
|
||||
auto registry = std::make_shared<Registry>(settings, type);
|
||||
|
||||
if (!path.pathExists())
|
||||
return std::make_shared<Registry>(type);
|
||||
return std::make_shared<Registry>(settings, type);
|
||||
|
||||
try {
|
||||
|
||||
@@ -125,23 +125,23 @@ std::shared_ptr<Registry> getCustomRegistry(const Settings & settings, const Pat
|
||||
return customRegistry;
|
||||
}
|
||||
|
||||
std::shared_ptr<Registry> getFlagRegistry()
|
||||
std::shared_ptr<Registry> getFlagRegistry(const Settings & settings)
|
||||
{
|
||||
static auto flagRegistry = std::make_shared<Registry>(Registry::Flag);
|
||||
static auto flagRegistry = std::make_shared<Registry>(settings, Registry::Flag);
|
||||
return flagRegistry;
|
||||
}
|
||||
|
||||
void overrideRegistry(const Input & from, const Input & to, const Attrs & extraAttrs)
|
||||
{
|
||||
getFlagRegistry()->add(from, to, extraAttrs);
|
||||
getFlagRegistry(*from.settings)->add(from, to, extraAttrs);
|
||||
}
|
||||
|
||||
static std::shared_ptr<Registry> getGlobalRegistry(const Settings & settings, Store & store)
|
||||
static std::shared_ptr<Registry> getGlobalRegistry(const Settings & settings, ref<Store> store)
|
||||
{
|
||||
static auto reg = [&]() {
|
||||
auto path = settings.flakeRegistry.get();
|
||||
if (path == "") {
|
||||
return std::make_shared<Registry>(Registry::Global); // empty registry
|
||||
return std::make_shared<Registry>(settings, Registry::Global); // empty registry
|
||||
}
|
||||
|
||||
return Registry::read(
|
||||
@@ -149,9 +149,9 @@ static std::shared_ptr<Registry> getGlobalRegistry(const Settings & settings, St
|
||||
[&] -> SourcePath {
|
||||
if (!isAbsolute(path)) {
|
||||
auto storePath = downloadFile(store, settings, path, "flake-registry.json").storePath;
|
||||
if (auto store2 = dynamic_cast<LocalFSStore *>(&store))
|
||||
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
|
||||
store2->addPermRoot(storePath, getCacheDir() + "/flake-registry.json");
|
||||
return {store.requireStoreObjectAccessor(storePath)};
|
||||
return {store->requireStoreObjectAccessor(storePath)};
|
||||
} else {
|
||||
return SourcePath{getFSSourceAccessor(), CanonPath{path}}.resolveSymlinks();
|
||||
}
|
||||
@@ -162,18 +162,17 @@ static std::shared_ptr<Registry> getGlobalRegistry(const Settings & settings, St
|
||||
return reg;
|
||||
}
|
||||
|
||||
Registries getRegistries(const Settings & settings, Store & store)
|
||||
Registries getRegistries(const Settings & settings, ref<Store> store)
|
||||
{
|
||||
Registries registries;
|
||||
registries.push_back(getFlagRegistry());
|
||||
registries.push_back(getFlagRegistry(settings));
|
||||
registries.push_back(getUserRegistry(settings));
|
||||
registries.push_back(getSystemRegistry(settings));
|
||||
registries.push_back(getGlobalRegistry(settings, store));
|
||||
return registries;
|
||||
}
|
||||
|
||||
std::pair<Input, Attrs>
|
||||
lookupInRegistries(const Settings & settings, Store & store, const Input & _input, UseRegistries useRegistries)
|
||||
std::pair<Input, Attrs> lookupInRegistries(ref<Store> store, const Input & _input, UseRegistries useRegistries)
|
||||
{
|
||||
Attrs extraAttrs;
|
||||
int n = 0;
|
||||
@@ -188,7 +187,7 @@ restart:
|
||||
if (n > 100)
|
||||
throw Error("cycle detected in flake registry for '%s'", input.to_string());
|
||||
|
||||
for (auto & registry : getRegistries(settings, store)) {
|
||||
for (auto & registry : getRegistries(*input.settings, store)) {
|
||||
if (useRegistries == UseRegistries::Limited
|
||||
&& !(registry->type == fetchers::Registry::Flag || registry->type == fetchers::Registry::Global))
|
||||
continue;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace nix::fetchers {
|
||||
|
||||
DownloadFileResult downloadFile(
|
||||
Store & store,
|
||||
ref<Store> store,
|
||||
const Settings & settings,
|
||||
const std::string & url,
|
||||
const std::string & name,
|
||||
@@ -28,7 +28,7 @@ DownloadFileResult downloadFile(
|
||||
{"name", name},
|
||||
}}};
|
||||
|
||||
auto cached = settings.getCache()->lookupStorePath(key, store);
|
||||
auto cached = settings.getCache()->lookupStorePath(key, *store);
|
||||
|
||||
auto useCached = [&]() -> DownloadFileResult {
|
||||
return {
|
||||
@@ -74,7 +74,7 @@ DownloadFileResult downloadFile(
|
||||
dumpString(res.data, sink);
|
||||
auto hash = hashString(HashAlgorithm::SHA256, res.data);
|
||||
auto info = ValidPathInfo::makeFromCA(
|
||||
store,
|
||||
*store,
|
||||
name,
|
||||
FixedOutputInfo{
|
||||
.method = FileIngestionMethod::Flat,
|
||||
@@ -84,7 +84,7 @@ DownloadFileResult downloadFile(
|
||||
hashString(HashAlgorithm::SHA256, sink.s));
|
||||
info.narSize = sink.s.size();
|
||||
auto source = StringSource{sink.s};
|
||||
store.addToStore(info, source, NoRepair, NoCheckSigs);
|
||||
store->addToStore(info, source, NoRepair, NoCheckSigs);
|
||||
storePath = std::move(info.path);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ DownloadFileResult downloadFile(
|
||||
key.second.insert_or_assign("url", url);
|
||||
assert(!res.urls.empty());
|
||||
infoAttrs.insert_or_assign("url", *res.urls.rbegin());
|
||||
settings.getCache()->upsert(key, store, infoAttrs, *storePath);
|
||||
settings.getCache()->upsert(key, *store, infoAttrs, *storePath);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -136,7 +136,7 @@ static DownloadTarballResult downloadTarball_(
|
||||
.treeHash = treeHash,
|
||||
.lastModified = (time_t) getIntAttr(infoAttrs, "lastModified"),
|
||||
.immutableUrl = maybeGetStrAttr(infoAttrs, "immutableUrl"),
|
||||
.accessor = settings.getTarballCache()->getAccessor(treeHash, {}, displayPrefix),
|
||||
.accessor = settings.getTarballCache()->getAccessor(treeHash, false, displayPrefix),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -214,7 +214,7 @@ static DownloadTarballResult downloadTarball_(
|
||||
return attrsToResult(infoAttrs);
|
||||
}
|
||||
|
||||
ref<SourceAccessor> downloadTarball(Store & store, const Settings & settings, const std::string & url)
|
||||
ref<SourceAccessor> downloadTarball(ref<Store> store, const Settings & settings, const std::string & url)
|
||||
{
|
||||
/* Go through Input::getAccessor() to ensure that the resulting
|
||||
accessor has a fingerprint. */
|
||||
@@ -224,7 +224,7 @@ ref<SourceAccessor> downloadTarball(Store & store, const Settings & settings, co
|
||||
|
||||
auto input = Input::fromAttrs(settings, std::move(attrs));
|
||||
|
||||
return input.getAccessor(settings, store).first;
|
||||
return input.getAccessor(store).first;
|
||||
}
|
||||
|
||||
// An input scheme corresponding to a curl-downloadable resource.
|
||||
@@ -252,7 +252,7 @@ struct CurlInputScheme : InputScheme
|
||||
if (!isValidURL(_url, requireTree))
|
||||
return std::nullopt;
|
||||
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
|
||||
auto url = _url;
|
||||
|
||||
@@ -278,7 +278,7 @@ struct CurlInputScheme : InputScheme
|
||||
HTTP request. Now that we've processed the Nix-specific
|
||||
attributes above, remove them so we don't also send them as
|
||||
part of the HTTP request. */
|
||||
for (auto & [param, _] : allowedAttrs())
|
||||
for (auto & param : allowedAttrs())
|
||||
url.query.erase(param);
|
||||
|
||||
input.attrs.insert_or_assign("type", std::string{schemeName()});
|
||||
@@ -286,88 +286,23 @@ struct CurlInputScheme : InputScheme
|
||||
return input;
|
||||
}
|
||||
|
||||
static const std::map<std::string, AttributeInfo> & allowedAttrsImpl()
|
||||
StringSet allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = {
|
||||
{
|
||||
"url",
|
||||
{
|
||||
.type = "String",
|
||||
.required = true,
|
||||
.doc = R"(
|
||||
Supported protocols:
|
||||
|
||||
- `https`
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "file";
|
||||
> url = "https://example.com/index.html";
|
||||
> }
|
||||
> ```
|
||||
|
||||
- `http`
|
||||
|
||||
Insecure HTTP transfer for legacy sources.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> HTTP performs no encryption or authentication.
|
||||
> Use a `narHash` known in advance to ensure the output has expected contents.
|
||||
|
||||
- `file`
|
||||
|
||||
A file on the local file system.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "file";
|
||||
> url = "file:///home/eelco/nix/README.md";
|
||||
> }
|
||||
> ```
|
||||
)",
|
||||
},
|
||||
},
|
||||
{
|
||||
"narHash",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"name",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"unpack",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"rev",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"revCount",
|
||||
{},
|
||||
},
|
||||
{
|
||||
"lastModified",
|
||||
{},
|
||||
},
|
||||
return {
|
||||
"type",
|
||||
"url",
|
||||
"narHash",
|
||||
"name",
|
||||
"unpack",
|
||||
"rev",
|
||||
"revCount",
|
||||
"lastModified",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
{
|
||||
return allowedAttrsImpl();
|
||||
}
|
||||
|
||||
std::optional<Input> inputFromAttrs(const Settings & settings, const Attrs & attrs) const override
|
||||
{
|
||||
Input input{};
|
||||
Input input{settings};
|
||||
input.attrs = attrs;
|
||||
|
||||
// input.locked = (bool) maybeGetStrAttr(input.attrs, "hash");
|
||||
@@ -384,7 +319,7 @@ struct CurlInputScheme : InputScheme
|
||||
return url;
|
||||
}
|
||||
|
||||
bool isLocked(const Settings & settings, const Input & input) const override
|
||||
bool isLocked(const Input & input) const override
|
||||
{
|
||||
return (bool) input.getNarHash();
|
||||
}
|
||||
@@ -397,14 +332,6 @@ struct FileInputScheme : CurlInputScheme
|
||||
return "file";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
{
|
||||
return stripIndentation(R"(
|
||||
Place a plain file into the Nix store.
|
||||
This is similar to [`builtins.fetchurl`](@docroot@/language/builtins.md#builtins-fetchurl)
|
||||
)");
|
||||
}
|
||||
|
||||
bool isValidURL(const ParsedURL & url, bool requireTree) const override
|
||||
{
|
||||
auto parsedUrlScheme = parseUrlScheme(url.scheme);
|
||||
@@ -413,8 +340,7 @@ struct FileInputScheme : CurlInputScheme
|
||||
: (!requireTree && !hasTarballExtension(url)));
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & _input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
|
||||
{
|
||||
auto input(_input);
|
||||
|
||||
@@ -422,12 +348,12 @@ struct FileInputScheme : CurlInputScheme
|
||||
the Nix store directly, since there is little deduplication
|
||||
benefit in using the Git cache for single big files like
|
||||
tarballs. */
|
||||
auto file = downloadFile(store, settings, getStrAttr(input.attrs, "url"), input.getName());
|
||||
auto file = downloadFile(store, *input.settings, getStrAttr(input.attrs, "url"), input.getName());
|
||||
|
||||
auto narHash = store.queryPathInfo(file.storePath)->narHash;
|
||||
auto narHash = store->queryPathInfo(file.storePath)->narHash;
|
||||
input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true));
|
||||
|
||||
auto accessor = ref{store.getFSAccessor(file.storePath)};
|
||||
auto accessor = ref{store->getFSAccessor(file.storePath)};
|
||||
|
||||
accessor->setPathDisplay("«" + input.to_string() + "»");
|
||||
|
||||
@@ -442,34 +368,6 @@ struct TarballInputScheme : CurlInputScheme
|
||||
return "tarball";
|
||||
}
|
||||
|
||||
std::string schemeDescription() const override
|
||||
{
|
||||
return stripIndentation(R"(
|
||||
Download a tar archive and extract it into the Nix store.
|
||||
This has the same underlying implementation as [`builtins.fetchTarball`](@docroot@/language/builtins.md#builtins-fetchTarball)
|
||||
)");
|
||||
}
|
||||
|
||||
const std::map<std::string, AttributeInfo> & allowedAttrs() const override
|
||||
{
|
||||
static const std::map<std::string, AttributeInfo> attrs = [] {
|
||||
auto attrs = CurlInputScheme::allowedAttrsImpl();
|
||||
// Override the "url" attribute to add tarball-specific example
|
||||
attrs["url"].doc = R"(
|
||||
> **Example**
|
||||
>
|
||||
> ```nix
|
||||
> fetchTree {
|
||||
> type = "tarball";
|
||||
> url = "https://github.com/NixOS/nixpkgs/tarball/nixpkgs-23.11";
|
||||
> }
|
||||
> ```
|
||||
)";
|
||||
return attrs;
|
||||
}();
|
||||
return attrs;
|
||||
}
|
||||
|
||||
bool isValidURL(const ParsedURL & url, bool requireTree) const override
|
||||
{
|
||||
auto parsedUrlScheme = parseUrlScheme(url.scheme);
|
||||
@@ -479,15 +377,15 @@ struct TarballInputScheme : CurlInputScheme
|
||||
: (requireTree || hasTarballExtension(url)));
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, Input>
|
||||
getAccessor(const Settings & settings, Store & store, const Input & _input) const override
|
||||
std::pair<ref<SourceAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
|
||||
{
|
||||
auto input(_input);
|
||||
|
||||
auto result = downloadTarball_(settings, getStrAttr(input.attrs, "url"), {}, "«" + input.to_string() + "»");
|
||||
auto result =
|
||||
downloadTarball_(*input.settings, getStrAttr(input.attrs, "url"), {}, "«" + input.to_string() + "»");
|
||||
|
||||
if (result.immutableUrl) {
|
||||
auto immutableInput = Input::fromURL(settings, *result.immutableUrl);
|
||||
auto immutableInput = Input::fromURL(*input.settings, *result.immutableUrl);
|
||||
// FIXME: would be nice to support arbitrary flakerefs
|
||||
// here, e.g. git flakes.
|
||||
if (immutableInput.getType() != "tarball")
|
||||
@@ -500,12 +398,14 @@ struct TarballInputScheme : CurlInputScheme
|
||||
|
||||
input.attrs.insert_or_assign(
|
||||
"narHash",
|
||||
settings.getTarballCache()->treeHashToNarHash(settings, result.treeHash).to_string(HashFormat::SRI, true));
|
||||
input.settings->getTarballCache()
|
||||
->treeHashToNarHash(*input.settings, result.treeHash)
|
||||
.to_string(HashFormat::SRI, true));
|
||||
|
||||
return {result.accessor, input};
|
||||
}
|
||||
|
||||
std::optional<std::string> getFingerprint(Store & store, const Input & input) const override
|
||||
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
||||
{
|
||||
if (auto narHash = input.getNarHash())
|
||||
return narHash->to_string(HashFormat::SRI, true);
|
||||
|
||||
@@ -200,7 +200,7 @@ nix_value * nix_locked_flake_get_output_attrs(
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
auto v = nix_alloc_value(context, evalState);
|
||||
nix::flake::callFlake(evalState->state, *lockedFlake->lockedFlake, *v->value);
|
||||
nix::flake::callFlake(evalState->state, *lockedFlake->lockedFlake, v->value);
|
||||
return v;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
|
||||
@@ -10,6 +10,9 @@ lockFileStr:
|
||||
# unlocked trees.
|
||||
overrides:
|
||||
|
||||
# This is `prim_fetchFinalTree`.
|
||||
fetchTreeFinal:
|
||||
|
||||
let
|
||||
inherit (builtins) mapAttrs;
|
||||
|
||||
@@ -49,7 +52,7 @@ let
|
||||
else
|
||||
# FIXME: remove obsolete node.info.
|
||||
# Note: lock file entries are always final.
|
||||
builtins.fetchFinalTree (node.info or { } // removeAttrs node.locked [ "dir" ]);
|
||||
fetchTreeFinal (node.info or { } // removeAttrs node.locked [ "dir" ]);
|
||||
|
||||
subdir = overrides.${key}.dir or node.locked.dir or "";
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PrimOp getFlake(const Settings & settings)
|
||||
std::string flakeRefS(
|
||||
state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.getFlake"));
|
||||
auto flakeRef = nix::parseFlakeRef(state.fetchSettings, flakeRefS, {}, true);
|
||||
if (state.settings.pureEval && !flakeRef.input.isLocked(state.fetchSettings))
|
||||
if (state.settings.pureEval && !flakeRef.input.isLocked())
|
||||
throw Error(
|
||||
"cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)",
|
||||
flakeRefS,
|
||||
@@ -93,7 +93,7 @@ static void prim_parseFlakeRef(EvalState & state, const PosIdx pos, Value ** arg
|
||||
auto & vv = binds.alloc(s);
|
||||
std::visit(
|
||||
overloaded{
|
||||
[&vv, &state](const std::string & value) { vv.mkString(value, state.mem); },
|
||||
[&vv](const std::string & value) { vv.mkString(value); },
|
||||
[&vv](const uint64_t & value) { vv.mkInt(value); },
|
||||
[&vv](const Explicit<bool> & value) { vv.mkBool(value.t); }},
|
||||
value);
|
||||
@@ -156,7 +156,7 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
|
||||
}
|
||||
}
|
||||
auto flakeRef = FlakeRef::fromAttrs(state.fetchSettings, attrs);
|
||||
v.mkString(flakeRef.to_string(), state.mem);
|
||||
v.mkString(flakeRef.to_string());
|
||||
}
|
||||
|
||||
nix::PrimOp flakeRefToString({
|
||||
|
||||
@@ -372,8 +372,7 @@ static Flake getFlake(
|
||||
const InputAttrPath & lockRootAttrPath)
|
||||
{
|
||||
// Fetch a lazy tree first.
|
||||
auto cachedInput =
|
||||
state.inputCache->getAccessor(state.fetchSettings, *state.store, originalRef.input, useRegistries);
|
||||
auto cachedInput = state.inputCache->getAccessor(state.store, originalRef.input, useRegistries);
|
||||
|
||||
auto subdir = fetchers::maybeGetStrAttr(cachedInput.extraAttrs, "dir").value_or(originalRef.subdir);
|
||||
auto resolvedRef = FlakeRef(std::move(cachedInput.resolvedInput), subdir);
|
||||
@@ -389,8 +388,7 @@ static Flake getFlake(
|
||||
debug("refetching input '%s' due to self attribute", newLockedRef);
|
||||
// FIXME: need to remove attrs that are invalidated by the changed input attrs, such as 'narHash'.
|
||||
newLockedRef.input.attrs.erase("narHash");
|
||||
auto cachedInput2 = state.inputCache->getAccessor(
|
||||
state.fetchSettings, *state.store, newLockedRef.input, fetchers::UseRegistries::No);
|
||||
auto cachedInput2 = state.inputCache->getAccessor(state.store, newLockedRef.input, fetchers::UseRegistries::No);
|
||||
cachedInput.accessor = cachedInput2.accessor;
|
||||
lockedRef = FlakeRef(std::move(cachedInput2.lockedInput), newLockedRef.subdir);
|
||||
}
|
||||
@@ -706,8 +704,7 @@ lockFlake(const Settings & settings, EvalState & state, const FlakeRef & topRef,
|
||||
this input. */
|
||||
debug("creating new input '%s'", inputAttrPathS);
|
||||
|
||||
if (!lockFlags.allowUnlocked && !input.ref->input.isLocked(state.fetchSettings)
|
||||
&& !input.ref->input.isRelative())
|
||||
if (!lockFlags.allowUnlocked && !input.ref->input.isLocked() && !input.ref->input.isRelative())
|
||||
throw Error("cannot update unlocked flake input '%s' in pure mode", inputAttrPathS);
|
||||
|
||||
/* Note: in case of an --override-input, we use
|
||||
@@ -756,7 +753,7 @@ lockFlake(const Settings & settings, EvalState & state, const FlakeRef & topRef,
|
||||
return {*resolvedPath, *input.ref};
|
||||
} else {
|
||||
auto cachedInput = state.inputCache->getAccessor(
|
||||
state.fetchSettings, *state.store, input.ref->input, useRegistriesInputs);
|
||||
state.store, input.ref->input, useRegistriesInputs);
|
||||
|
||||
auto lockedRef = FlakeRef(std::move(cachedInput.lockedInput), input.ref->subdir);
|
||||
|
||||
@@ -956,7 +953,7 @@ void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & vRes)
|
||||
auto key = keyMap.find(node);
|
||||
assert(key != keyMap.end());
|
||||
|
||||
override.alloc(state.symbols.create("dir")).mkString(CanonPath(subdir).rel(), state.mem);
|
||||
override.alloc(state.symbols.create("dir")).mkString(CanonPath(subdir).rel());
|
||||
|
||||
overrides.alloc(state.symbols.create(key->second)).mkAttrs(override);
|
||||
}
|
||||
@@ -966,13 +963,16 @@ void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & vRes)
|
||||
Value * vCallFlake = requireInternalFile(state, CanonPath("call-flake.nix"));
|
||||
|
||||
auto vLocks = state.allocValue();
|
||||
vLocks->mkString(lockFileStr, state.mem);
|
||||
vLocks->mkString(lockFileStr);
|
||||
|
||||
Value * args[] = {vLocks, &vOverrides};
|
||||
auto vFetchFinalTree = get(state.internalPrimOps, "fetchFinalTree");
|
||||
assert(vFetchFinalTree);
|
||||
|
||||
Value * args[] = {vLocks, &vOverrides, *vFetchFinalTree};
|
||||
state.callFunction(*vCallFlake, args, vRes, noPos);
|
||||
}
|
||||
|
||||
std::optional<Fingerprint> LockedFlake::getFingerprint(Store & store, const fetchers::Settings & fetchSettings) const
|
||||
std::optional<Fingerprint> LockedFlake::getFingerprint(ref<Store> store, const fetchers::Settings & fetchSettings) const
|
||||
{
|
||||
if (lockFile.isUnlocked(fetchSettings))
|
||||
return std::nullopt;
|
||||
@@ -1002,7 +1002,7 @@ Flake::~Flake() {}
|
||||
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, ref<const LockedFlake> lockedFlake)
|
||||
{
|
||||
auto fingerprint = state.settings.useEvalCache && state.settings.pureEval
|
||||
? lockedFlake->getFingerprint(*state.store, state.fetchSettings)
|
||||
? lockedFlake->getFingerprint(state.store, state.fetchSettings)
|
||||
: std::nullopt;
|
||||
auto rootLoader = [&state, lockedFlake]() {
|
||||
/* For testing whether the evaluation cache is
|
||||
|
||||
@@ -64,10 +64,9 @@ std::ostream & operator<<(std::ostream & str, const FlakeRef & flakeRef)
|
||||
return str;
|
||||
}
|
||||
|
||||
FlakeRef
|
||||
FlakeRef::resolve(const fetchers::Settings & fetchSettings, Store & store, fetchers::UseRegistries useRegistries) const
|
||||
FlakeRef FlakeRef::resolve(ref<Store> store, fetchers::UseRegistries useRegistries) const
|
||||
{
|
||||
auto [input2, extraAttrs] = lookupInRegistries(fetchSettings, store, input, useRegistries);
|
||||
auto [input2, extraAttrs] = lookupInRegistries(store, input, useRegistries);
|
||||
return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir));
|
||||
}
|
||||
|
||||
@@ -288,10 +287,9 @@ FlakeRef FlakeRef::fromAttrs(const fetchers::Settings & fetchSettings, const fet
|
||||
fetchers::maybeGetStrAttr(attrs, "dir").value_or(""));
|
||||
}
|
||||
|
||||
std::pair<ref<SourceAccessor>, FlakeRef>
|
||||
FlakeRef::lazyFetch(const fetchers::Settings & fetchSettings, Store & store) const
|
||||
std::pair<ref<SourceAccessor>, FlakeRef> FlakeRef::lazyFetch(ref<Store> store) const
|
||||
{
|
||||
auto [accessor, lockedInput] = input.getAccessor(fetchSettings, store);
|
||||
auto [accessor, lockedInput] = input.getAccessor(store);
|
||||
return {accessor, FlakeRef(std::move(lockedInput), subdir)};
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ struct LockedFlake
|
||||
*/
|
||||
std::map<ref<Node>, SourcePath> nodePaths;
|
||||
|
||||
std::optional<Fingerprint> getFingerprint(Store & store, const fetchers::Settings & fetchSettings) const;
|
||||
std::optional<Fingerprint> getFingerprint(ref<Store> store, const fetchers::Settings & fetchSettings) const;
|
||||
};
|
||||
|
||||
struct LockFlags
|
||||
|
||||
@@ -71,14 +71,11 @@ struct FlakeRef
|
||||
|
||||
fetchers::Attrs toAttrs() const;
|
||||
|
||||
FlakeRef resolve(
|
||||
const fetchers::Settings & fetchSettings,
|
||||
Store & store,
|
||||
fetchers::UseRegistries useRegistries = fetchers::UseRegistries::All) const;
|
||||
FlakeRef resolve(ref<Store> store, fetchers::UseRegistries useRegistries = fetchers::UseRegistries::All) const;
|
||||
|
||||
static FlakeRef fromAttrs(const fetchers::Settings & fetchSettings, const fetchers::Attrs & attrs);
|
||||
|
||||
std::pair<ref<SourceAccessor>, FlakeRef> lazyFetch(const fetchers::Settings & fetchSettings, Store & store) const;
|
||||
std::pair<ref<SourceAccessor>, FlakeRef> lazyFetch(ref<Store> store) const;
|
||||
|
||||
/**
|
||||
* Canonicalize a flakeref for the purpose of comparing "old" and
|
||||
|
||||
@@ -74,7 +74,7 @@ LockedNode::LockedNode(const fetchers::Settings & fetchSettings, const nlohmann:
|
||||
, parentInputAttrPath(
|
||||
json.find("parent") != json.end() ? (std::optional<InputAttrPath>) json["parent"] : std::nullopt)
|
||||
{
|
||||
if (!lockedRef.input.isLocked(fetchSettings) && !lockedRef.input.isRelative()) {
|
||||
if (!lockedRef.input.isLocked() && !lockedRef.input.isRelative()) {
|
||||
if (lockedRef.input.getNarHash())
|
||||
warn(
|
||||
"Lock file entry '%s' is unlocked (e.g. lacks a Git revision) but is checked by NAR hash. "
|
||||
@@ -282,7 +282,7 @@ std::optional<FlakeRef> LockFile::isUnlocked(const fetchers::Settings & fetchSet
|
||||
latter case, we can verify the input but we may not be able to
|
||||
fetch it from anywhere. */
|
||||
auto isConsideredLocked = [&](const fetchers::Input & input) {
|
||||
return input.isLocked(fetchSettings) || (fetchSettings.allowDirtyLocks && input.getNarHash());
|
||||
return input.isLocked() || (fetchSettings.allowDirtyLocks && input.getNarHash());
|
||||
};
|
||||
|
||||
for (auto & i : nodes) {
|
||||
|
||||
@@ -35,8 +35,6 @@ include_dirs = [ include_directories('.') ]
|
||||
|
||||
headers = files(
|
||||
'nix_api_store.h',
|
||||
'nix_api_store/derivation.h',
|
||||
'nix_api_store/store_path.h',
|
||||
)
|
||||
|
||||
# TODO don't install this once tests don't use it and/or move the header into `libstore`, non-`c`
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
*/
|
||||
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_store/store_path.h"
|
||||
#include "nix_api_store/derivation.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -23,6 +21,10 @@ extern "C" {
|
||||
|
||||
/** @brief Reference to a Nix store */
|
||||
typedef struct Store Store;
|
||||
/** @brief Nix store path */
|
||||
typedef struct StorePath StorePath;
|
||||
/** @brief Nix Derivation */
|
||||
typedef struct nix_derivation nix_derivation;
|
||||
|
||||
/**
|
||||
* @brief Initializes the Nix store library
|
||||
@@ -116,6 +118,30 @@ nix_store_get_storedir(nix_c_context * context, Store * store, nix_get_string_ca
|
||||
*/
|
||||
StorePath * nix_store_parse_path(nix_c_context * context, Store * store, const char * path);
|
||||
|
||||
/**
|
||||
* @brief Get the path name (e.g. "name" in /nix/store/...-name)
|
||||
*
|
||||
* @param[in] store_path the path to get the name from
|
||||
* @param[in] callback called with the name
|
||||
* @param[in] user_data arbitrary data, passed to the callback when it's called.
|
||||
*/
|
||||
void nix_store_path_name(const StorePath * store_path, nix_get_string_callback callback, void * user_data);
|
||||
|
||||
/**
|
||||
* @brief Copy a StorePath
|
||||
*
|
||||
* @param[in] p the path to copy
|
||||
* @return a new StorePath
|
||||
*/
|
||||
StorePath * nix_store_path_clone(const StorePath * p);
|
||||
|
||||
/** @brief Deallocate a StorePath
|
||||
*
|
||||
* Does not fail.
|
||||
* @param[in] p the path to free
|
||||
*/
|
||||
void nix_store_path_free(StorePath * p);
|
||||
|
||||
/**
|
||||
* @brief Check if a StorePath is valid (i.e. that corresponding store object and its closure of references exists in
|
||||
* the store)
|
||||
@@ -203,6 +229,14 @@ nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store
|
||||
*/
|
||||
StorePath * nix_add_derivation(nix_c_context * context, Store * store, nix_derivation * derivation);
|
||||
|
||||
/**
|
||||
* @brief Deallocate a `nix_derivation`
|
||||
*
|
||||
* Does not fail.
|
||||
* @param[in] drv the derivation to free
|
||||
*/
|
||||
void nix_derivation_free(nix_derivation * drv);
|
||||
|
||||
/**
|
||||
* @brief Copy the closure of `path` from `srcStore` to `dstStore`.
|
||||
*
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef NIX_API_STORE_DERIVATION_H
|
||||
#define NIX_API_STORE_DERIVATION_H
|
||||
/**
|
||||
* @defgroup libstore_derivation Derivation
|
||||
* @ingroup libstore
|
||||
* @brief Derivation operations that don't require a Store
|
||||
* @{
|
||||
*/
|
||||
/** @file
|
||||
* @brief Derivation operations
|
||||
*/
|
||||
|
||||
#include "nix_api_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// cffi start
|
||||
|
||||
/** @brief Nix Derivation */
|
||||
typedef struct nix_derivation nix_derivation;
|
||||
|
||||
/**
|
||||
* @brief Deallocate a `nix_derivation`
|
||||
*
|
||||
* Does not fail.
|
||||
* @param[in] drv the derivation to free
|
||||
*/
|
||||
void nix_derivation_free(nix_derivation * drv);
|
||||
|
||||
// cffi end
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif // NIX_API_STORE_DERIVATION_H
|
||||
@@ -1,54 +0,0 @@
|
||||
#ifndef NIX_API_STORE_STORE_PATH_H
|
||||
#define NIX_API_STORE_STORE_PATH_H
|
||||
/**
|
||||
* @defgroup libstore_storepath StorePath
|
||||
* @ingroup libstore
|
||||
* @brief Store path operations that don't require a Store
|
||||
* @{
|
||||
*/
|
||||
/** @file
|
||||
* @brief Store path operations
|
||||
*/
|
||||
|
||||
#include "nix_api_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// cffi start
|
||||
|
||||
/** @brief Nix store path */
|
||||
typedef struct StorePath StorePath;
|
||||
|
||||
/**
|
||||
* @brief Copy a StorePath
|
||||
*
|
||||
* @param[in] p the path to copy
|
||||
* @return a new StorePath
|
||||
*/
|
||||
StorePath * nix_store_path_clone(const StorePath * p);
|
||||
|
||||
/** @brief Deallocate a StorePath
|
||||
*
|
||||
* Does not fail.
|
||||
* @param[in] p the path to free
|
||||
*/
|
||||
void nix_store_path_free(StorePath * p);
|
||||
|
||||
/**
|
||||
* @brief Get the path name (e.g. "<name>" in /nix/store/<hash>-<name>)
|
||||
*
|
||||
* @param[in] store_path the path to get the name from
|
||||
* @param[in] callback called with the name
|
||||
* @param[in] user_data arbitrary data, passed to the callback when it's called.
|
||||
*/
|
||||
void nix_store_path_name(const StorePath * store_path, nix_get_string_callback callback, void * user_data);
|
||||
|
||||
// cffi end
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif // NIX_API_STORE_STORE_PATH_H
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "nix/store/tests/libstore.hh"
|
||||
#include "nix/util/tests/characterization.hh"
|
||||
#include "nix/util/tests/json-characterization.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -17,30 +16,12 @@ class ProtoTest : public CharacterizationTest
|
||||
|
||||
std::filesystem::path goldenMaster(std::string_view testStem) const override
|
||||
{
|
||||
return unitTestData / testStem;
|
||||
return unitTestData / (std::string{testStem + ".bin"});
|
||||
}
|
||||
|
||||
public:
|
||||
Path storeDir = "/nix/store";
|
||||
StoreDirConfig store{storeDir};
|
||||
|
||||
/**
|
||||
* Golden test for `T` JSON reading
|
||||
*/
|
||||
template<typename T>
|
||||
void readJsonTest(PathView testStem, const T & expected)
|
||||
{
|
||||
nix::readJsonTest(*this, testStem, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Golden test for `T` JSON write
|
||||
*/
|
||||
template<typename T>
|
||||
void writeJsonTest(PathView testStem, const T & decoded)
|
||||
{
|
||||
nix::writeJsonTest(*this, testStem, decoded);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Proto, const char * protocolDir>
|
||||
@@ -53,7 +34,7 @@ public:
|
||||
template<typename T>
|
||||
void readProtoTest(PathView testStem, typename Proto::Version version, T expected)
|
||||
{
|
||||
CharacterizationTest::readTest(std::string{testStem + ".bin"}, [&](const auto & encoded) {
|
||||
CharacterizationTest::readTest(testStem, [&](const auto & encoded) {
|
||||
T got = ({
|
||||
StringSource from{encoded};
|
||||
Proto::template Serialise<T>::read(
|
||||
@@ -74,7 +55,7 @@ public:
|
||||
template<typename T>
|
||||
void writeProtoTest(PathView testStem, typename Proto::Version version, const T & decoded)
|
||||
{
|
||||
CharacterizationTest::writeTest(std::string{testStem + ".bin"}, [&]() {
|
||||
CharacterizationTest::writeTest(testStem, [&]() {
|
||||
StringSink to;
|
||||
Proto::template Serialise<T>::write(
|
||||
this->store,
|
||||
@@ -88,25 +69,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#define VERSIONED_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
|
||||
TEST_F(FIXTURE, NAME##_read) \
|
||||
{ \
|
||||
readProtoTest(STEM, VERSION, VALUE); \
|
||||
} \
|
||||
TEST_F(FIXTURE, NAME##_write) \
|
||||
{ \
|
||||
writeProtoTest(STEM, VERSION, VALUE); \
|
||||
}
|
||||
|
||||
#define VERSIONED_CHARACTERIZATION_TEST(FIXTURE, NAME, STEM, VERSION, VALUE) \
|
||||
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
|
||||
TEST_F(FIXTURE, NAME##_json_read) \
|
||||
{ \
|
||||
readJsonTest(STEM, VALUE); \
|
||||
} \
|
||||
TEST_F(FIXTURE, NAME##_json_write) \
|
||||
{ \
|
||||
writeJsonTest(STEM, VALUE); \
|
||||
#define VERSIONED_CHARACTERIZATION_TEST(FIXTURE, NAME, STEM, VERSION, VALUE) \
|
||||
TEST_F(FIXTURE, NAME##_read) \
|
||||
{ \
|
||||
readProtoTest(STEM, VERSION, VALUE); \
|
||||
} \
|
||||
TEST_F(FIXTURE, NAME##_write) \
|
||||
{ \
|
||||
writeProtoTest(STEM, VERSION, VALUE); \
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/util/json-utils.hh"
|
||||
#include "nix/store/common-protocol.hh"
|
||||
#include "nix/store/common-protocol-impl.hh"
|
||||
#include "nix/store/build-result.hh"
|
||||
@@ -23,7 +22,7 @@ public:
|
||||
template<typename T>
|
||||
void readProtoTest(PathView testStem, const T & expected)
|
||||
{
|
||||
CharacterizationTest::readTest(std::string{testStem + ".bin"}, [&](const auto & encoded) {
|
||||
CharacterizationTest::readTest(testStem, [&](const auto & encoded) {
|
||||
T got = ({
|
||||
StringSource from{encoded};
|
||||
CommonProto::Serialise<T>::read(store, CommonProto::ReadConn{.from = from});
|
||||
@@ -39,7 +38,7 @@ public:
|
||||
template<typename T>
|
||||
void writeProtoTest(PathView testStem, const T & decoded)
|
||||
{
|
||||
CharacterizationTest::writeTest(std::string{testStem + ".bin"}, [&]() -> std::string {
|
||||
CharacterizationTest::writeTest(testStem, [&]() -> std::string {
|
||||
StringSink to;
|
||||
CommonProto::Serialise<T>::write(store, CommonProto::WriteConn{.to = to}, decoded);
|
||||
return to.s;
|
||||
@@ -55,14 +54,6 @@ public:
|
||||
TEST_F(CommonProtoTest, NAME##_write) \
|
||||
{ \
|
||||
writeProtoTest(STEM, VALUE); \
|
||||
} \
|
||||
TEST_F(CommonProtoTest, NAME##_json_read) \
|
||||
{ \
|
||||
readJsonTest(STEM, VALUE); \
|
||||
} \
|
||||
TEST_F(CommonProtoTest, NAME##_json_write) \
|
||||
{ \
|
||||
writeJsonTest(STEM, VALUE); \
|
||||
}
|
||||
|
||||
CHARACTERIZATION_TEST(
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
[
|
||||
{
|
||||
"hash": {
|
||||
"algorithm": "sha256",
|
||||
"format": "base64",
|
||||
"hash": "+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0="
|
||||
},
|
||||
"method": "text"
|
||||
},
|
||||
{
|
||||
"hash": {
|
||||
"algorithm": "sha1",
|
||||
"format": "base64",
|
||||
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
|
||||
},
|
||||
"method": "flat"
|
||||
},
|
||||
{
|
||||
"hash": {
|
||||
"algorithm": "sha256",
|
||||
"format": "base64",
|
||||
"hash": "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM="
|
||||
},
|
||||
"method": "nar"
|
||||
}
|
||||
]
|
||||
@@ -1,4 +0,0 @@
|
||||
[
|
||||
"sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
|
||||
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux"
|
||||
]
|
||||
@@ -1,11 +0,0 @@
|
||||
[
|
||||
null,
|
||||
{
|
||||
"hash": {
|
||||
"algorithm": "sha1",
|
||||
"format": "base64",
|
||||
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
|
||||
},
|
||||
"method": "flat"
|
||||
}
|
||||
]
|
||||
@@ -1,4 +0,0 @@
|
||||
[
|
||||
null,
|
||||
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
|
||||
]
|
||||
@@ -1,13 +0,0 @@
|
||||
[
|
||||
{
|
||||
"dependentRealisations": {
|
||||
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
|
||||
},
|
||||
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
|
||||
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
|
||||
"signatures": [
|
||||
"asdf",
|
||||
"qwer"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
[
|
||||
{
|
||||
"dependentRealisations": {},
|
||||
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
|
||||
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
|
||||
"signatures": []
|
||||
},
|
||||
{
|
||||
"dependentRealisations": {},
|
||||
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
|
||||
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
|
||||
"signatures": [
|
||||
"asdf",
|
||||
"qwer"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
[
|
||||
[],
|
||||
[
|
||||
""
|
||||
],
|
||||
[
|
||||
"",
|
||||
"bar",
|
||||
"foo"
|
||||
],
|
||||
[
|
||||
[],
|
||||
[
|
||||
""
|
||||
],
|
||||
[
|
||||
"",
|
||||
"1",
|
||||
"2"
|
||||
]
|
||||
]
|
||||
]
|
||||
@@ -1,4 +0,0 @@
|
||||
[
|
||||
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
|
||||
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
|
||||
]
|
||||
@@ -1,7 +0,0 @@
|
||||
[
|
||||
"",
|
||||
"hi",
|
||||
"white rabbit",
|
||||
"大白兔",
|
||||
"oh no "
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
[
|
||||
[],
|
||||
[
|
||||
""
|
||||
],
|
||||
[
|
||||
"",
|
||||
"foo",
|
||||
"bar"
|
||||
],
|
||||
[
|
||||
[],
|
||||
[
|
||||
""
|
||||
],
|
||||
[
|
||||
"",
|
||||
"1",
|
||||
"2"
|
||||
]
|
||||
]
|
||||
]
|
||||
@@ -4,13 +4,10 @@
|
||||
"allowSubstitutes": false,
|
||||
"exportReferencesGraph": {
|
||||
"refs1": [
|
||||
{
|
||||
"drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",
|
||||
"output": "out"
|
||||
}
|
||||
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
|
||||
],
|
||||
"refs2": [
|
||||
"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
|
||||
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
|
||||
]
|
||||
},
|
||||
"impureEnvVars": [
|
||||
@@ -23,36 +20,18 @@
|
||||
"outputChecks": {
|
||||
"forAllOutputs": {
|
||||
"allowedReferences": [
|
||||
{
|
||||
"drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",
|
||||
"output": "out"
|
||||
}
|
||||
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
|
||||
],
|
||||
"allowedRequisites": [
|
||||
{
|
||||
"drvPath": "self",
|
||||
"output": "bin"
|
||||
},
|
||||
{
|
||||
"drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",
|
||||
"output": "dev"
|
||||
}
|
||||
"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z",
|
||||
"bin"
|
||||
],
|
||||
"disallowedReferences": [
|
||||
{
|
||||
"drvPath": "self",
|
||||
"output": "dev"
|
||||
},
|
||||
{
|
||||
"drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",
|
||||
"output": "out"
|
||||
}
|
||||
"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g",
|
||||
"dev"
|
||||
],
|
||||
"disallowedRequisites": [
|
||||
{
|
||||
"drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",
|
||||
"output": "dev"
|
||||
}
|
||||
"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"
|
||||
],
|
||||
"ignoreSelfRefs": true,
|
||||
"maxClosureSize": null,
|
||||
|
||||
@@ -4,13 +4,10 @@
|
||||
"allowSubstitutes": false,
|
||||
"exportReferencesGraph": {
|
||||
"refs1": [
|
||||
{
|
||||
"drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",
|
||||
"output": "out"
|
||||
}
|
||||
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
|
||||
],
|
||||
"refs2": [
|
||||
"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
|
||||
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
|
||||
]
|
||||
},
|
||||
"impureEnvVars": [
|
||||
@@ -26,20 +23,11 @@
|
||||
"allowedReferences": null,
|
||||
"allowedRequisites": null,
|
||||
"disallowedReferences": [
|
||||
{
|
||||
"drvPath": "self",
|
||||
"output": "dev"
|
||||
},
|
||||
{
|
||||
"drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",
|
||||
"output": "out"
|
||||
}
|
||||
"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g",
|
||||
"dev"
|
||||
],
|
||||
"disallowedRequisites": [
|
||||
{
|
||||
"drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",
|
||||
"output": "dev"
|
||||
}
|
||||
"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"
|
||||
],
|
||||
"ignoreSelfRefs": false,
|
||||
"maxClosureSize": null,
|
||||
@@ -56,20 +44,11 @@
|
||||
},
|
||||
"out": {
|
||||
"allowedReferences": [
|
||||
{
|
||||
"drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",
|
||||
"output": "out"
|
||||
}
|
||||
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
|
||||
],
|
||||
"allowedRequisites": [
|
||||
{
|
||||
"drvPath": "self",
|
||||
"output": "bin"
|
||||
},
|
||||
{
|
||||
"drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",
|
||||
"output": "dev"
|
||||
}
|
||||
"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z",
|
||||
"bin"
|
||||
],
|
||||
"disallowedReferences": [],
|
||||
"disallowedRequisites": [],
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
"allowSubstitutes": false,
|
||||
"exportReferencesGraph": {
|
||||
"refs1": [
|
||||
"p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
|
||||
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
|
||||
],
|
||||
"refs2": [
|
||||
"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
|
||||
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
|
||||
]
|
||||
},
|
||||
"impureEnvVars": [
|
||||
@@ -20,24 +20,18 @@
|
||||
"outputChecks": {
|
||||
"forAllOutputs": {
|
||||
"allowedReferences": [
|
||||
"p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
|
||||
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
|
||||
],
|
||||
"allowedRequisites": [
|
||||
{
|
||||
"drvPath": "self",
|
||||
"output": "bin"
|
||||
},
|
||||
"z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"
|
||||
"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev",
|
||||
"bin"
|
||||
],
|
||||
"disallowedReferences": [
|
||||
{
|
||||
"drvPath": "self",
|
||||
"output": "dev"
|
||||
},
|
||||
"r5cff30838majxk5mp3ip2diffi8vpaj-bar"
|
||||
"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar",
|
||||
"dev"
|
||||
],
|
||||
"disallowedRequisites": [
|
||||
"9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"
|
||||
"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"
|
||||
],
|
||||
"ignoreSelfRefs": true,
|
||||
"maxClosureSize": null,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user