diff --git a/doc/manual/meson.build b/doc/manual/meson.build index 231f7b9f8..93c2f24d1 100644 --- a/doc/manual/meson.build +++ b/doc/manual/meson.build @@ -88,7 +88,7 @@ manual = custom_target( @0@ @INPUT0@ @CURRENT_SOURCE_DIR@ > @DEPFILE@ @0@ @INPUT1@ summary @2@ < @CURRENT_SOURCE_DIR@/source/SUMMARY.md.in > @2@/source/SUMMARY.md sed -e 's|@version@|@3@|g' < @INPUT2@ > @2@/book.toml - @4@ -r -L --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/ + @4@ -r -L --exclude='*.drv' --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/ (cd @2@; RUST_LOG=warn @1@ build -d @2@ 3>&2 2>&1 1>&3) | { grep -Fv "because fragment resolution isn't implemented" || :; } 3>&2 2>&1 1>&3 rm -rf @2@/manual mv @2@/html @2@/manual diff --git a/doc/manual/package.nix b/doc/manual/package.nix index 81061b7a1..c140b8fda 100644 --- a/doc/manual/package.nix +++ b/doc/manual/package.nix @@ -41,6 +41,7 @@ mkMesonDerivation (finalAttrs: { ../../src/libstore-tests/data/content-address ../../src/libstore-tests/data/store-path ../../src/libstore-tests/data/realisation + ../../src/libstore-tests/data/derivation ../../src/libstore-tests/data/derived-path ../../src/libstore-tests/data/path-info ../../src/libstore-tests/data/nar-info diff --git a/doc/manual/source/SUMMARY.md.in b/doc/manual/source/SUMMARY.md.in index 5be3d6a90..4d938da8e 100644 --- a/doc/manual/source/SUMMARY.md.in +++ b/doc/manual/source/SUMMARY.md.in @@ -125,6 +125,7 @@ - [Store Path](protocols/json/store-path.md) - [Store Object Info](protocols/json/store-object-info.md) - [Derivation](protocols/json/derivation.md) + - [Derivation Options](protocols/json/derivation-options.md) - [Deriving Path](protocols/json/deriving-path.md) - [Build Trace Entry](protocols/json/build-trace-entry.md) - [Build Result](protocols/json/build-result.md) diff --git a/doc/manual/source/protocols/json/derivation-options.md b/doc/manual/source/protocols/json/derivation-options.md new file mode 100644 index 000000000..1743fb7f6 --- /dev/null +++ b/doc/manual/source/protocols/json/derivation-options.md @@ -0,0 +1,49 @@ +{{#include derivation-options-v1-fixed.md}} + +## Examples + +### Input-addressed derivations + +#### Default options + +```json +{{#include schema/derivation-options-v1/ia/defaults.json}} +``` + +#### All options set + +```json +{{#include schema/derivation-options-v1/ia/all_set.json}} +``` + +#### Default options (structured attributes) + +```json +{{#include schema/derivation-options-v1/ia/structuredAttrs_defaults.json}} +``` + +#### All options set (structured attributes) + +```json +{{#include schema/derivation-options-v1/ia/structuredAttrs_all_set.json}} +``` + +### Content-addressed derivations + +#### All options set + +```json +{{#include schema/derivation-options-v1/ca/all_set.json}} +``` + +#### All options set (structured attributes) + +```json +{{#include schema/derivation-options-v1/ca/structuredAttrs_all_set.json}} +``` + + diff --git a/doc/manual/source/protocols/json/meson.build b/doc/manual/source/protocols/json/meson.build index 4ab94c63b..babf68a93 100644 --- a/doc/manual/source/protocols/json/meson.build +++ b/doc/manual/source/protocols/json/meson.build @@ -14,6 +14,7 @@ schemas = [ 'store-path-v1', 'store-object-info-v2', 'derivation-v4', + 'derivation-options-v1', 'deriving-path-v1', 'build-trace-entry-v1', 'build-result-v1', diff --git a/doc/manual/source/protocols/json/schema/derivation-options-v1 b/doc/manual/source/protocols/json/schema/derivation-options-v1 new file mode 120000 index 000000000..9332a5390 --- /dev/null +++ b/doc/manual/source/protocols/json/schema/derivation-options-v1 @@ -0,0 +1 @@ +../../../../../../src/libstore-tests/data/derivation \ No newline at end of file diff --git a/doc/manual/source/protocols/json/schema/derivation-options-v1.yaml b/doc/manual/source/protocols/json/schema/derivation-options-v1.yaml new file mode 100644 index 000000000..58ff07088 --- /dev/null +++ b/doc/manual/source/protocols/json/schema/derivation-options-v1.yaml @@ -0,0 +1,242 @@ +"$schema": "http://json-schema.org/draft-04/schema" +"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/derivation-options-v1.json" +title: Derivation Options +description: | + JSON representation of Nix's `DerivationOptions` type. + + This schema describes various build-time options and constraints that can be specified for a derivation. + + > **Warning** + > + > This JSON format is currently + > [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command) + > and subject to change. + +type: object +required: + - outputChecks + - unsafeDiscardReferences + - passAsFile + - exportReferencesGraph + - additionalSandboxProfile + - noChroot + - impureHostDeps + - impureEnvVars + - allowLocalNetworking + - requiredSystemFeatures + - preferLocalBuild + - allowSubstitutes +properties: + outputChecks: + type: object + title: Output Check + description: | + Constraints on what the derivation's outputs can and cannot reference. + Can either apply to all outputs or be specified per output. + oneOf: + - title: Output Checks For All Outputs + description: | + Output checks that apply to all outputs of the derivation. + required: + - forAllOutputs + properties: + forAllOutputs: + "$ref": "#/$defs/outputCheckSpec" + additionalProperties: false + + - title: Output Checks Per Output + description: | + Output checks specified individually for each output. + required: + - perOutput + properties: + perOutput: + type: object + additionalProperties: + "$ref": "#/$defs/outputCheckSpec" + additionalProperties: false + + unsafeDiscardReferences: + type: object + title: Unsafe Discard References + description: | + A map specifying which references should be unsafely discarded from each output. + This is generally not recommended and requires special permissions. + additionalProperties: + type: array + items: + type: string + + passAsFile: + type: array + title: Pass As File + description: | + List of environment variable names whose values should be passed as files rather than directly. + items: + type: string + + exportReferencesGraph: + type: object + title: Export References Graph + description: | + Specify paths whose references graph should be exported to files. + additionalProperties: + type: array + items: + "$ref": "deriving-path-v1.yaml" + + additionalSandboxProfile: + type: string + title: Additional Sandbox Profile + description: | + Additional sandbox profile directives (macOS specific). + + noChroot: + type: boolean + title: No Chroot + description: | + Whether to disable the build sandbox, if allowed. + + impureHostDeps: + type: array + title: Impure Host Dependencies + description: | + List of host paths that the build can access. + items: + type: string + + impureEnvVars: + type: array + title: Impure Environment Variables + description: | + List of environment variable names that should be passed through to the build from the calling environment. + items: + type: string + + allowLocalNetworking: + type: boolean + title: Allow Local Networking + description: | + Whether the build should have access to local network (macOS specific). + + requiredSystemFeatures: + type: array + title: Required System Features + description: | + List of system features required to build this derivation (e.g., "kvm", "nixos-test"). + items: + type: string + + preferLocalBuild: + type: boolean + title: Prefer Local Build + description: | + Whether this derivation should preferably be built locally rather than its outputs substituted. + + allowSubstitutes: + type: boolean + title: Allow Substitutes + description: | + Whether substituting from other stores should be allowed for this derivation's outputs. + +additionalProperties: false + +$defs: + + outputCheckSpec: + type: object + title: Output Check Specification + description: | + Constraints on what a specific output can reference. + required: + - ignoreSelfRefs + - maxSize + - maxClosureSize + - allowedReferences + - allowedRequisites + - disallowedReferences + - disallowedRequisites + properties: + ignoreSelfRefs: + type: boolean + title: Ignore Self References + description: | + Whether references from this output to itself should be ignored when checking references. + + maxSize: + type: ["integer", "null"] + title: Maximum Size + description: | + Maximum allowed size of this output in bytes, or null for no limit. + minimum: 0 + + maxClosureSize: + type: ["integer", "null"] + title: Maximum Closure Size + description: | + Maximum allowed size of this output's closure in bytes, or null for no limit. + minimum: 0 + + allowedReferences: + oneOf: + - type: array + items: + "$ref": "#/$defs/drvRef" + - type: "null" + title: Allowed References + description: | + If set, the output can only reference paths in this list. + If null, no restrictions apply. + + allowedRequisites: + oneOf: + - type: array + items: + "$ref": "#/$defs/drvRef" + - type: "null" + title: Allowed Requisites + description: | + If set, the output's closure can only contain paths in this list. + If null, no restrictions apply. + + disallowedReferences: + type: array + title: Disallowed References + description: | + The output must not reference any paths in this list. + items: + "$ref": "#/$defs/drvRef" + + disallowedRequisites: + type: array + title: Disallowed Requisites + description: | + The output's closure must not contain any paths in this list. + items: + "$ref": "#/$defs/drvRef" + additionalProperties: false + + drvRef: + # TODO fix bug in checker, should be `oneOf` + anyOf: + - type: object + title: Current derivation Output Reference + description: | + A reference to a specific output of the current derivation. + required: + - drvPath + - output + properties: + drvPath: + type: string + const: "self" + title: This derivation + description: | + Won't be confused for a deriving path + output: + type: string + title: Output Name + description: | + The name of the output being referenced. + additionalProperties: false + - "$ref": "deriving-path-v1.yaml" diff --git a/src/json-schema-checks/derivation-options b/src/json-schema-checks/derivation-options new file mode 120000 index 000000000..00c6cde65 --- /dev/null +++ b/src/json-schema-checks/derivation-options @@ -0,0 +1 @@ +../libstore-tests/data/derivation \ No newline at end of file diff --git a/src/json-schema-checks/meson.build b/src/json-schema-checks/meson.build index f72affb0b..991facf12 100644 --- a/src/json-schema-checks/meson.build +++ b/src/json-schema-checks/meson.build @@ -63,6 +63,19 @@ schemas = [ 'with-signature.json', ], }, + # Derivation options + { + 'stem' : 'derivation-options', + 'schema' : schema_dir / 'derivation-options-v1.yaml', + 'files' : [ + 'ia' / 'defaults.json', + 'ia' / 'all_set.json', + 'ia' / 'structuredAttrs_defaults.json', + 'ia' / 'structuredAttrs_all_set.json', + 'ca' / 'all_set.json', + 'ca' / 'structuredAttrs_all_set.json', + ], + }, ] # Derivation and Derivation output diff --git a/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json b/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json index 2a4e70558..95122ad41 100644 --- a/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json +++ b/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json @@ -69,7 +69,8 @@ "outputChecks": { "bin": { "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g" + "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + "dev" ], "disallowedRequisites": [ "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" @@ -84,7 +85,8 @@ "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z" + "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + "bin" ] } }, diff --git a/src/libstore-tests/data/derivation/ca/advanced-attributes.json b/src/libstore-tests/data/derivation/ca/advanced-attributes.json index 55dbe62e0..6b77459bc 100644 --- a/src/libstore-tests/data/derivation/ca/advanced-attributes.json +++ b/src/libstore-tests/data/derivation/ca/advanced-attributes.json @@ -11,9 +11,9 @@ "__sandboxProfile": "sandcastle", "allowSubstitutes": "", "allowedReferences": "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9", - "allowedRequisites": "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + "allowedRequisites": "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z bin", "builder": "/bin/bash", - "disallowedReferences": "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + "disallowedReferences": "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g dev", "disallowedRequisites": "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8", "exportReferencesGraph": "refs1 /164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9 refs2 /nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", "impureEnvVars": "UNICORN", diff --git a/src/libstore-tests/data/derivation/ca/all_set.json b/src/libstore-tests/data/derivation/ca/all_set.json index e06eada01..8086c752c 100644 --- a/src/libstore-tests/data/derivation/ca/all_set.json +++ b/src/libstore-tests/data/derivation/ca/all_set.json @@ -4,10 +4,13 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "refs2": [ - "/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" + "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" ] }, "impureEnvVars": [ @@ -20,16 +23,36 @@ "outputChecks": { "forAllOutputs": { "allowedReferences": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z" + { + "drvPath": "self", + "output": "bin" + }, + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "dev" + } ], "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g" + { + "drvPath": "self", + "output": "dev" + }, + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "out" + } ], "disallowedRequisites": [ - "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "dev" + } ], "ignoreSelfRefs": true, "maxClosureSize": null, diff --git a/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json b/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json index 2a321897c..e29447b6a 100644 --- a/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json +++ b/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json @@ -4,10 +4,13 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "refs2": [ - "/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" + "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" ] }, "impureEnvVars": [ @@ -23,10 +26,20 @@ "allowedReferences": null, "allowedRequisites": null, "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g" + { + "drvPath": "self", + "output": "dev" + }, + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "out" + } ], "disallowedRequisites": [ - "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "dev" + } ], "ignoreSelfRefs": false, "maxClosureSize": null, @@ -43,10 +56,20 @@ }, "out": { "allowedReferences": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z" + { + "drvPath": "self", + "output": "bin" + }, + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "dev" + } ], "disallowedReferences": [], "disallowedRequisites": [], diff --git a/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json b/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json index e07d1294b..bbd68e087 100644 --- a/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json +++ b/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json @@ -5,9 +5,9 @@ ], "builder": "/bin/bash", "env": { - "bin": "/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin", - "dev": "/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev", - "out": "/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs" + "bin": "/nix/store/cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin", + "dev": "/nix/store/ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev", + "out": "/nix/store/h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs" }, "inputs": { "drvs": { @@ -33,13 +33,13 @@ "name": "advanced-attributes-structured-attrs", "outputs": { "bin": { - "path": "33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin" + "path": "cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin" }, "dev": { - "path": "wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev" + "path": "ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev" }, "out": { - "path": "7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs" + "path": "h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs" } }, "structuredAttrs": { @@ -66,7 +66,8 @@ "outputChecks": { "bin": { "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar" + "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + "dev" ], "disallowedRequisites": [ "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" @@ -81,7 +82,8 @@ "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" + "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + "bin" ] } }, diff --git a/src/libstore-tests/data/derivation/ia/advanced-attributes.json b/src/libstore-tests/data/derivation/ia/advanced-attributes.json index 372b4fbb9..e2de9431b 100644 --- a/src/libstore-tests/data/derivation/ia/advanced-attributes.json +++ b/src/libstore-tests/data/derivation/ia/advanced-attributes.json @@ -11,14 +11,14 @@ "__sandboxProfile": "sandcastle", "allowSubstitutes": "", "allowedReferences": "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo", - "allowedRequisites": "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + "allowedRequisites": "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev bin", "builder": "/bin/bash", - "disallowedReferences": "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + "disallowedReferences": "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar dev", "disallowedRequisites": "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev", "exportReferencesGraph": "refs1 /nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo refs2 /nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv", "impureEnvVars": "UNICORN", "name": "advanced-attributes", - "out": "/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes", + "out": "/nix/store/ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes", "preferLocalBuild": "1", "requiredSystemFeatures": "rainbow uid-range", "system": "my-system" @@ -47,7 +47,7 @@ "name": "advanced-attributes", "outputs": { "out": { - "path": "wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes" + "path": "ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes" } }, "system": "my-system", diff --git a/src/libstore-tests/data/derivation/ia/all_set.json b/src/libstore-tests/data/derivation/ia/all_set.json index 62b6cdf97..2e1c848da 100644 --- a/src/libstore-tests/data/derivation/ia/all_set.json +++ b/src/libstore-tests/data/derivation/ia/all_set.json @@ -4,10 +4,10 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "refs2": [ - "/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" + "vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" ] }, "impureEnvVars": [ @@ -20,16 +20,24 @@ "outputChecks": { "forAllOutputs": { "allowedReferences": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" + { + "drvPath": "self", + "output": "bin" + }, + "z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" ], "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar" + { + "drvPath": "self", + "output": "dev" + }, + "r5cff30838majxk5mp3ip2diffi8vpaj-bar" ], "disallowedRequisites": [ - "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" + "9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" ], "ignoreSelfRefs": true, "maxClosureSize": null, diff --git a/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json b/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json index 0fa383589..a29699b5d 100644 --- a/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json +++ b/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json @@ -4,10 +4,10 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "refs2": [ - "/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" + "vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" ] }, "impureEnvVars": [ @@ -23,10 +23,14 @@ "allowedReferences": null, "allowedRequisites": null, "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar" + { + "drvPath": "self", + "output": "dev" + }, + "r5cff30838majxk5mp3ip2diffi8vpaj-bar" ], "disallowedRequisites": [ - "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" + "9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" ], "ignoreSelfRefs": false, "maxClosureSize": null, @@ -43,10 +47,14 @@ }, "out": { "allowedReferences": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" + { + "drvPath": "self", + "output": "bin" + }, + "z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" ], "disallowedReferences": [], "disallowedRequisites": [], diff --git a/src/libstore-tests/derivation-advanced-attrs.cc b/src/libstore-tests/derivation-advanced-attrs.cc index 41538cdcc..27b8aba16 100644 --- a/src/libstore-tests/derivation-advanced-attrs.cc +++ b/src/libstore-tests/derivation-advanced-attrs.cc @@ -3,7 +3,7 @@ #include "nix/util/experimental-features.hh" #include "nix/store/derivations.hh" -#include "nix/store/derivations.hh" +#include "nix/store/derived-path.hh" #include "nix/store/derivation-options.hh" #include "nix/store/parsed-derivations.hh" #include "nix/util/types.hh" @@ -17,7 +17,7 @@ namespace nix { using namespace nlohmann; class DerivationAdvancedAttrsTest : public JsonCharacterizationTest, - public JsonCharacterizationTest, + public JsonCharacterizationTest>, public LibStoreTest { protected: @@ -42,7 +42,8 @@ public: { this->readTest(fileName, [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_EQ(options.getRequiredSystemFeatures(got), expectedFeatures); }); } @@ -51,11 +52,14 @@ public: * Helper function to test DerivationOptions parsing and comparison */ void testDerivationOptions( - const std::string & fileName, const DerivationOptions & expected, const StringSet & expectedSystemFeatures) + const std::string & fileName, + const DerivationOptions & expected, + const StringSet & expectedSystemFeatures) { this->readTest(fileName, [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_EQ(options, expected); EXPECT_EQ(options.getRequiredSystemFeatures(got), expectedSystemFeatures); @@ -127,11 +131,42 @@ TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attribute #undef TEST_ATERM_JSON -using ExportReferencesMap = decltype(DerivationOptions::exportReferencesGraph); +/** + * Since these are both repeated and sensative opaque values, it makes + * sense to give them names in this file. + */ +static SingleDerivedPath + pathFoo = SingleDerivedPath::Opaque{StorePath{"p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}}, + pathFooDev = SingleDerivedPath::Opaque{StorePath{"z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"}}, + pathBar = SingleDerivedPath::Opaque{StorePath{"r5cff30838majxk5mp3ip2diffi8vpaj-bar"}}, + pathBarDev = SingleDerivedPath::Opaque{StorePath{"9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"}}, + pathBarDrvIA = SingleDerivedPath::Opaque{StorePath{"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}}, + pathBarDrvCA = SingleDerivedPath::Opaque{StorePath{"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}}, + placeholderFoo = + SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv"}), + .output = "out", + }, + placeholderFooDev = + SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv"}), + .output = "dev", + }, + placeholderBar = + SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}), + .output = "out", + }, + placeholderBarDev = SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}), + .output = "dev", + }; -static const DerivationOptions advancedAttributes_defaults = { +using ExportReferencesMap = decltype(DerivationOptions::exportReferencesGraph); + +static const DerivationOptions advancedAttributes_defaults = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, }, .unsafeDiscardReferences = {}, @@ -152,7 +187,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults) this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(!got.structuredAttrs); @@ -177,9 +213,9 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_defaults) TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes) { - DerivationOptions expected = { + DerivationOptions expected = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, }, .unsafeDiscardReferences = {}, @@ -197,12 +233,13 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes) this->readTest("advanced-attributes.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(!got.structuredAttrs); // Reset fields that vary between test cases to enable whole-object comparison - options.outputChecks = DerivationOptions::OutputChecks{.ignoreSelfRefs = true}; + options.outputChecks = DerivationOptions::OutputChecks{.ignoreSelfRefs = true}; options.exportReferencesGraph = {}; EXPECT_EQ(options, expected); @@ -212,20 +249,20 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes) }); }; -DerivationOptions advancedAttributes_ia = { +DerivationOptions advancedAttributes_ia = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, - .allowedReferences = StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}, - .disallowedReferences = StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"}, - .allowedRequisites = StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"}, - .disallowedRequisites = StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"}, + .allowedReferences = std::set>{pathFoo}, + .disallowedReferences = std::set>{pathBar, OutputName{"dev"}}, + .allowedRequisites = std::set>{pathFooDev, OutputName{"bin"}}, + .disallowedRequisites = std::set>{pathBarDev}, }, .unsafeDiscardReferences = {}, .passAsFile = {}, .exportReferencesGraph{ - {"refs1", {"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}}, - {"refs2", {"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}}, + {"refs1", {pathFoo}}, + {"refs2", {pathBarDrvIA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -242,20 +279,20 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_ia) testDerivationOptions("advanced-attributes.drv", advancedAttributes_ia, {"rainbow", "uid-range"}); }; -DerivationOptions advancedAttributes_ca = { +DerivationOptions advancedAttributes_ca = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, - .allowedReferences = StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}, - .disallowedReferences = StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"}, - .allowedRequisites = StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"}, - .disallowedRequisites = StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"}, + .allowedReferences = std::set>{placeholderFoo}, + .disallowedReferences = std::set>{placeholderBar, OutputName{"dev"}}, + .allowedRequisites = std::set>{placeholderFooDev, OutputName{"bin"}}, + .disallowedRequisites = std::set>{placeholderBarDev}, }, .unsafeDiscardReferences = {}, .passAsFile = {}, .exportReferencesGraph{ - {"refs1", {"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}}, - {"refs2", {"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}}, + {"refs1", {placeholderFoo}}, + {"refs2", {pathBarDrvCA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -272,8 +309,8 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes) testDerivationOptions("advanced-attributes.drv", advancedAttributes_ca, {"rainbow", "uid-range", "ca-derivations"}); }; -DerivationOptions advancedAttributes_structuredAttrs_defaults = { - .outputChecks = std::map{}, +DerivationOptions advancedAttributes_structuredAttrs_defaults = { + .outputChecks = std::map::OutputChecks>{}, .unsafeDiscardReferences = {}, .passAsFile = {}, .exportReferencesGraph = {}, @@ -292,7 +329,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_d this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(got.structuredAttrs); @@ -317,11 +355,11 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_default TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) { - DerivationOptions expected = { + DerivationOptions expected = { .outputChecks = - std::map{ + std::map::OutputChecks>{ {"dev", - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .maxSize = 789, .maxClosureSize = 5909, }}, @@ -342,7 +380,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(got.structuredAttrs); @@ -350,7 +389,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) { // Delete all keys but "dev" in options.outputChecks auto * outputChecksMapP = - std::get_if>(&options.outputChecks); + std::get_if::OutputChecks>>( + &options.outputChecks); ASSERT_TRUE(outputChecksMapP); auto & outputChecksMap = *outputChecksMapP; auto devEntry = outputChecksMap.find("dev"); @@ -370,21 +410,21 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) }); }; -DerivationOptions advancedAttributes_structuredAttrs_ia = { +DerivationOptions advancedAttributes_structuredAttrs_ia = { .outputChecks = - std::map{ + std::map::OutputChecks>{ {"out", - DerivationOptions::OutputChecks{ - .allowedReferences = StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}, - .allowedRequisites = StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"}, + DerivationOptions::OutputChecks{ + .allowedReferences = std::set>{pathFoo}, + .allowedRequisites = std::set>{pathFooDev, OutputName{"bin"}}, }}, {"bin", - DerivationOptions::OutputChecks{ - .disallowedReferences = StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"}, - .disallowedRequisites = StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"}, + DerivationOptions::OutputChecks{ + .disallowedReferences = std::set>{pathBar, OutputName{"dev"}}, + .disallowedRequisites = std::set>{pathBarDev}, }}, {"dev", - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .maxSize = 789, .maxClosureSize = 5909, }}, @@ -393,8 +433,8 @@ DerivationOptions advancedAttributes_structuredAttrs_ia = { .passAsFile = {}, .exportReferencesGraph = { - {"refs1", {"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}}, - {"refs2", {"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}}, + {"refs1", {pathFoo}}, + {"refs2", {pathBarDrvIA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -412,21 +452,21 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs) "advanced-attributes-structured-attrs.drv", advancedAttributes_structuredAttrs_ia, {"rainbow", "uid-range"}); }; -DerivationOptions advancedAttributes_structuredAttrs_ca = { +DerivationOptions advancedAttributes_structuredAttrs_ca = { .outputChecks = - std::map{ + std::map::OutputChecks>{ {"out", - DerivationOptions::OutputChecks{ - .allowedReferences = StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}, - .allowedRequisites = StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"}, + DerivationOptions::OutputChecks{ + .allowedReferences = std::set>{placeholderFoo}, + .allowedRequisites = std::set>{placeholderFooDev, OutputName{"bin"}}, }}, {"bin", - DerivationOptions::OutputChecks{ - .disallowedReferences = StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"}, - .disallowedRequisites = StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"}, + DerivationOptions::OutputChecks{ + .disallowedReferences = std::set>{placeholderBar, OutputName{"dev"}}, + .disallowedRequisites = std::set>{placeholderBarDev}, }}, {"dev", - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .maxSize = 789, .maxClosureSize = 5909, }}, @@ -435,8 +475,8 @@ DerivationOptions advancedAttributes_structuredAttrs_ca = { .passAsFile = {}, .exportReferencesGraph = { - {"refs1", {"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}}, - {"refs2", {"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}}, + {"refs1", {placeholderFoo}}, + {"refs2", {pathBarDrvCA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -456,14 +496,16 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs) {"rainbow", "uid-range", "ca-derivations"}); }; -#define TEST_JSON_OPTIONS(FIXUTURE, VAR, VAR2) \ - TEST_F(FIXUTURE, DerivationOptions_##VAR##_from_json) \ - { \ - this->JsonCharacterizationTest::readJsonTest(#VAR, advancedAttributes_##VAR2); \ - } \ - TEST_F(FIXUTURE, DerivationOptions_##VAR##_to_json) \ - { \ - this->JsonCharacterizationTest::writeJsonTest(#VAR, advancedAttributes_##VAR2); \ +#define TEST_JSON_OPTIONS(FIXUTURE, VAR, VAR2) \ + TEST_F(FIXUTURE, DerivationOptions_##VAR##_from_json) \ + { \ + this->JsonCharacterizationTest>::readJsonTest( \ + #VAR, advancedAttributes_##VAR2); \ + } \ + TEST_F(FIXUTURE, DerivationOptions_##VAR##_to_json) \ + { \ + this->JsonCharacterizationTest>::writeJsonTest( \ + #VAR, advancedAttributes_##VAR2); \ } TEST_JSON_OPTIONS(DerivationAdvancedAttrsTest, defaults, defaults) diff --git a/src/libstore/build/derivation-building-goal.cc b/src/libstore/build/derivation-building-goal.cc index c72130142..41d76fbba 100644 --- a/src/libstore/build/derivation-building-goal.cc +++ b/src/libstore/build/derivation-building-goal.cc @@ -32,14 +32,27 @@ DerivationBuildingGoal::DerivationBuildingGoal( , drv{std::make_unique(drv)} , buildMode(buildMode) { + DerivationOptions temp; try { - drvOptions = - std::make_unique(DerivationOptions::fromStructuredAttrs(drv.env, drv.structuredAttrs)); + temp = derivationOptionsFromStructuredAttrs(worker.store, drv.inputDrvs, drv.env, drv.structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", worker.store.printStorePath(drvPath)); throw; } + auto x = tryResolve( + temp, [&](ref drvPath, const std::string & outputName) -> std::optional { + try { + return resolveDerivedPath( + worker.store, SingleDerivedPath::Built{drvPath, outputName}, &worker.evalStore); + } catch (Error &) { + return std::nullopt; + } + }); + + assert(x); + drvOptions = std::make_unique>(*x); + name = fmt("building derivation '%s'", worker.store.printStorePath(drvPath)); trace("created"); diff --git a/src/libstore/build/derivation-check.cc b/src/libstore/build/derivation-check.cc index 181221ba5..e56b9fe49 100644 --- a/src/libstore/build/derivation-check.cc +++ b/src/libstore/build/derivation-check.cc @@ -11,7 +11,7 @@ void checkOutputs( Store & store, const StorePath & drvPath, const decltype(Derivation::outputs) & drvOutputs, - const decltype(DerivationOptions::outputChecks) & outputChecks, + const decltype(DerivationOptions::outputChecks) & outputChecks, const std::map & outputs) { std::map outputsByPath; @@ -85,7 +85,7 @@ void checkOutputs( return std::make_pair(std::move(pathsDone), closureSize); }; - auto applyChecks = [&](const DerivationOptions::OutputChecks & checks) { + auto applyChecks = [&](const DerivationOptions::OutputChecks & checks) { if (checks.maxSize && info.narSize > *checks.maxSize) throw BuildError( BuildResult::Failure::OutputRejected, @@ -105,28 +105,33 @@ void checkOutputs( *checks.maxClosureSize); } - auto checkRefs = [&](const StringSet & value, bool allowed, bool recursive) { + auto checkRefs = [&](const std::set> & value, bool allowed, bool recursive) { /* Parse a list of reference specifiers. Each element must either be a store path, or the symbolic name of the output of the derivation (such as `out'). */ StorePathSet spec; for (auto & i : value) { - if (store.isStorePath(i)) - spec.insert(store.parseStorePath(i)); - else if (auto output = get(outputs, i)) - spec.insert(output->path); - else { - std::string outputsListing = - concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); - throw BuildError( - BuildResult::Failure::OutputRejected, - "derivation '%s' output check for '%s' contains an illegal reference specifier '%s'," - " expected store path or output name (one of [%s])", - store.printStorePath(drvPath), - outputName, - i, - outputsListing); - } + std::visit( + overloaded{ + [&](const StorePath & path) { spec.insert(path); }, + [&](const OutputName & refOutputName) { + if (auto output = get(outputs, refOutputName)) + spec.insert(output->path); + else { + std::string outputsListing = + concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); + throw BuildError( + BuildResult::Failure::OutputRejected, + "derivation '%s' output check for '%s' contains output name '%s'," + " but this is not a valid output of this derivation." + " (Valid outputs are [%s].)", + store.printStorePath(drvPath), + outputName, + refOutputName, + outputsListing); + } + }}, + i); } auto used = recursive ? getClosure(info.path).first : info.references; @@ -180,8 +185,8 @@ void checkOutputs( std::visit( overloaded{ - [&](const DerivationOptions::OutputChecks & checks) { applyChecks(checks); }, - [&](const std::map & checksPerOutput) { + [&](const DerivationOptions::OutputChecks & checks) { applyChecks(checks); }, + [&](const std::map::OutputChecks> & checksPerOutput) { if (auto outputChecks = get(checksPerOutput, outputName)) applyChecks(*outputChecks); diff --git a/src/libstore/build/derivation-check.hh b/src/libstore/build/derivation-check.hh index b425c2ac5..01e6c5d56 100644 --- a/src/libstore/build/derivation-check.hh +++ b/src/libstore/build/derivation-check.hh @@ -21,7 +21,7 @@ void checkOutputs( Store & store, const StorePath & drvPath, const decltype(Derivation::outputs) & drvOutputs, - const decltype(DerivationOptions::outputChecks) & drvOptions, + const decltype(DerivationOptions::outputChecks) & drvOptions, const std::map & outputs); } // namespace nix diff --git a/src/libstore/build/derivation-env-desugar.cc b/src/libstore/build/derivation-env-desugar.cc index 8d552fc4d..75b62c116 100644 --- a/src/libstore/build/derivation-env-desugar.cc +++ b/src/libstore/build/derivation-env-desugar.cc @@ -18,7 +18,10 @@ std::string & DesugaredEnv::atFileEnvPair(std::string_view name, std::string fil } DesugaredEnv DesugaredEnv::create( - Store & store, const Derivation & drv, const DerivationOptions & drvOptions, const StorePathSet & inputPaths) + Store & store, + const Derivation & drv, + const DerivationOptions & drvOptions, + const StorePathSet & inputPaths) { DesugaredEnv res; @@ -46,7 +49,7 @@ DesugaredEnv DesugaredEnv::create( } /* Handle exportReferencesGraph(), if set. */ - for (auto & [fileName, storePaths] : drvOptions.getParsedExportReferencesGraph(store)) { + for (auto & [fileName, storePaths] : drvOptions.exportReferencesGraph) { /* Write closure info to . */ res.extraFiles.insert_or_assign( fileName, store.makeValidityRegistration(store.exportReferences(storePaths, inputPaths), false, false)); diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 14aa044ea..a44b79f57 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -64,9 +64,9 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation) { trace("have derivation"); - auto drvOptions = [&]() -> DerivationOptions { + auto drvOptions = [&]() -> DerivationOptions { try { - return DerivationOptions::fromStructuredAttrs(drv->env, drv->structuredAttrs); + return derivationOptionsFromStructuredAttrs(worker.store, drv->inputDrvs, drv->env, drv->structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", worker.store.printStorePath(drvPath)); throw; diff --git a/src/libstore/derivation-options.cc b/src/libstore/derivation-options.cc index 75313841c..8c71ef4b1 100644 --- a/src/libstore/derivation-options.cc +++ b/src/libstore/derivation-options.cc @@ -2,15 +2,18 @@ #include "nix/util/json-utils.hh" #include "nix/store/parsed-derivations.hh" #include "nix/store/derivations.hh" +#include "nix/store/derived-path.hh" #include "nix/store/store-api.hh" #include "nix/util/types.hh" #include "nix/util/util.hh" #include "nix/store/globals.hh" +#include "nix/util/variant-wrapper.hh" #include #include #include #include +#include namespace nix { @@ -90,14 +93,60 @@ getStringSetAttr(const StringMap & env, const StructuredAttrs * parsed, const st return ss ? (std::optional{StringSet{ss->begin(), ss->end()}}) : (std::optional{}); } -using OutputChecks = DerivationOptions::OutputChecks; +template +using OutputChecks = DerivationOptions::OutputChecks; -using OutputChecksVariant = std::variant>; +template +using OutputChecksVariant = std::variant, std::map>>; -DerivationOptions DerivationOptions::fromStructuredAttrs( - const StringMap & env, const std::optional & parsed, bool shouldWarn) +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) { - return fromStructuredAttrs(env, parsed ? &*parsed : nullptr); + /* Use the SingleDerivedPath version with empty inputDrvs, then + resolve. */ + DerivedPathMap emptyInputDrvs{}; + auto singleDerivedPathOptions = + derivationOptionsFromStructuredAttrs(store, emptyInputDrvs, env, parsed, shouldWarn, mockXpSettings); + + /* "Resolve" all SingleDerivedPath inputs to StorePath. */ + auto resolved = tryResolve( + singleDerivedPathOptions, + [&](ref drvPath, const std::string & outputName) -> std::optional { + // there should be nothing to resolve + assert(false); + }); + + /* Since we should never need to call the call back, there should be + no way it fails. */ + assert(resolved); + + return *resolved; +} + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) +{ + return derivationOptionsFromStructuredAttrs(store, env, parsed ? &*parsed : nullptr, shouldWarn, mockXpSettings); +} + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) +{ + return derivationOptionsFromStructuredAttrs( + store, inputDrvs, env, parsed ? &*parsed : nullptr, shouldWarn, mockXpSettings); } static void flatten(const nlohmann::json & value, StringSet & res) @@ -111,10 +160,63 @@ static void flatten(const nlohmann::json & value, StringSet & res) throw Error("'exportReferencesGraph' value is not an array or a string"); } -DerivationOptions -DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn) +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) { - DerivationOptions defaults = {}; + DerivationOptions defaults = {}; + + std::map placeholders; + if (mockXpSettings.isEnabled(Xp::CaDerivations)) { + /* Initialize placeholder map from inputDrvs */ + auto initPlaceholders = [&](this const auto & initPlaceholders, + ref basePath, + const DerivedPathMap::ChildNode & node) -> void { + for (const auto & outputName : node.value) { + auto built = SingleDerivedPath::Built{ + .drvPath = basePath, + .output = outputName, + }; + placeholders.insert_or_assign( + DownstreamPlaceholder::fromSingleDerivedPathBuilt(built, mockXpSettings).render(), + std::move(built)); + } + + for (const auto & [outputName, childNode] : node.childMap) { + initPlaceholders( + make_ref(SingleDerivedPath::Built{ + .drvPath = basePath, + .output = outputName, + }), + childNode); + } + }; + + for (const auto & [drvPath, outputs] : inputDrvs.map) { + auto basePath = make_ref(SingleDerivedPath::Opaque{drvPath}); + initPlaceholders(basePath, outputs); + } + } + + auto parseSingleDerivedPath = [&](const std::string & pathS) -> SingleDerivedPath { + if (auto it = placeholders.find(pathS); it != placeholders.end()) + return it->second; + else + return SingleDerivedPath::Opaque{store.toStorePath(pathS).first}; + }; + + auto parseRef = [&](const std::string & pathS) -> DrvRef { + if (auto it = placeholders.find(pathS); it != placeholders.end()) + return it->second; + if (store.isStorePath(pathS)) + return SingleDerivedPath::Opaque{store.toStorePath(pathS).first}; + else + return pathS; + }; if (shouldWarn && parsed) { auto & structuredAttrs = parsed->structuredAttrs; @@ -146,14 +248,14 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt } return { - .outputChecks = [&]() -> OutputChecksVariant { + .outputChecks = [&]() -> OutputChecksVariant { if (parsed) { auto & structuredAttrs = parsed->structuredAttrs; - std::map res; + std::map> res; if (auto * outputChecks = get(structuredAttrs, "outputChecks")) { for (auto & [outputName, output_] : getObject(*outputChecks)) { - OutputChecks checks; + OutputChecks checks; auto & output = getObject(output_); @@ -163,13 +265,14 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt if (auto maxClosureSize = get(output, "maxClosureSize")) checks.maxClosureSize = maxClosureSize->get(); - auto get_ = [&output = output](const std::string & name) -> std::optional { + auto get_ = + [&](const std::string & name) -> std::optional>> { if (auto i = get(output, name)) { - StringSet res; + std::set> res; for (auto j = i->begin(); j != i->end(); ++j) { if (!j->is_string()) throw Error("attribute '%s' must be a list of strings", name); - res.insert(j->get()); + res.insert(parseRef(j->get())); } return res; } @@ -178,7 +281,7 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt res.insert_or_assign( outputName, - OutputChecks{ + OutputChecks{ .maxSize = [&]() -> std::optional { if (auto maxSize = get(output, "maxSize")) return maxSize->get(); @@ -192,21 +295,32 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt return std::nullopt; }(), .allowedReferences = get_("allowedReferences"), - .disallowedReferences = get_("disallowedReferences").value_or(StringSet{}), + .disallowedReferences = + get_("disallowedReferences").value_or(std::set>{}), .allowedRequisites = get_("allowedRequisites"), - .disallowedRequisites = get_("disallowedRequisites").value_or(StringSet{}), + .disallowedRequisites = + get_("disallowedRequisites").value_or(std::set>{}), }); } } return res; } else { - return OutputChecks{ + auto parseRefSet = [&](const std::optional optionalStringSet) + -> std::optional>> { + if (!optionalStringSet) + return std::nullopt; + auto range = *optionalStringSet | std::views::transform(parseRef); + return std::set>(range.begin(), range.end()); + }; + return OutputChecks{ // legacy non-structured-attributes case .ignoreSelfRefs = true, - .allowedReferences = getStringSetAttr(env, parsed, "allowedReferences"), - .disallowedReferences = getStringSetAttr(env, parsed, "disallowedReferences").value_or(StringSet{}), - .allowedRequisites = getStringSetAttr(env, parsed, "allowedRequisites"), - .disallowedRequisites = getStringSetAttr(env, parsed, "disallowedRequisites").value_or(StringSet{}), + .allowedReferences = parseRefSet(getStringSetAttr(env, parsed, "allowedReferences")), + .disallowedReferences = parseRefSet(getStringSetAttr(env, parsed, "disallowedReferences")) + .value_or(std::set>{}), + .allowedRequisites = parseRefSet(getStringSetAttr(env, parsed, "allowedRequisites")), + .disallowedRequisites = parseRefSet(getStringSetAttr(env, parsed, "disallowedRequisites")) + .value_or(std::set>{}), }; } }(), @@ -245,16 +359,19 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt }(), .exportReferencesGraph = [&] { - std::map ret; + std::map> ret; if (parsed) { auto * e = optionalValueAt(parsed->structuredAttrs, "exportReferencesGraph"); if (!e || !e->is_object()) return ret; - for (auto & [key, value] : getObject(*e)) { + for (auto & [key, storePathsJson] : getObject(*e)) { StringSet ss; - flatten(value, ss); - ret.insert_or_assign(key, std::move(ss)); + flatten(storePathsJson, ss); + std::set storePaths; + for (auto & s : ss) + storePaths.insert(parseSingleDerivedPath(s)); + ret.insert_or_assign(key, std::move(storePaths)); } } else { auto s = getOr(env, "exportReferencesGraph", ""); @@ -268,7 +385,7 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt throw Error("invalid file name '%s' in 'exportReferencesGraph'", fileName); auto & storePathS = *i++; - ret.insert_or_assign(std::move(fileName), StringSet{storePathS}); + ret.insert_or_assign(std::move(fileName), std::set{parseSingleDerivedPath(storePathS)}); } } return ret; @@ -286,28 +403,8 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt }; } -std::map -DerivationOptions::getParsedExportReferencesGraph(const StoreDirConfig & store) const -{ - std::map res; - - for (auto & [fileName, ss] : exportReferencesGraph) { - StorePathSet storePaths; - for (auto & storePathS : ss) { - if (!store.isInStore(storePathS)) - throw BuildError( - BuildResult::Failure::InputRejected, - "'exportReferencesGraph' contains a non-store path '%1%'", - storePathS); - storePaths.insert(store.toStorePath(storePathS).first); - } - res.insert_or_assign(fileName, storePaths); - } - - return res; -} - -StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & drv) const +template +StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & drv) const { // FIXME: cache this? StringSet res; @@ -318,7 +415,8 @@ StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & d return res; } -bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivation & drv) const +template +bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivation & drv) const { if (drv.platform != settings.thisSystem.get() && !settings.extraPlatforms.get().count(drv.platform) && !drv.isBuiltin()) @@ -334,42 +432,194 @@ bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivatio return true; } -bool DerivationOptions::willBuildLocally(Store & localStore, const BasicDerivation & drv) const +template +bool DerivationOptions::willBuildLocally(Store & localStore, const BasicDerivation & drv) const { return preferLocalBuild && canBuildLocally(localStore, drv); } -bool DerivationOptions::substitutesAllowed() const +template +bool DerivationOptions::substitutesAllowed() const { return settings.alwaysAllowSubstitutes ? true : allowSubstitutes; } -bool DerivationOptions::useUidRange(const BasicDerivation & drv) const +template +bool DerivationOptions::useUidRange(const BasicDerivation & drv) const { return getRequiredSystemFeatures(drv).count("uid-range"); } +std::optional> tryResolve( + const DerivationOptions & drvOptions, + std::function(ref drvPath, const std::string & outputName)> + queryResolutionChain) +{ + auto tryResolvePath = [&](const SingleDerivedPath & input) -> std::optional { + return std::visit( + overloaded{ + [](const SingleDerivedPath::Opaque & p) -> std::optional { return p.path; }, + [&](const SingleDerivedPath::Built & p) -> std::optional { + return queryResolutionChain(p.drvPath, p.output); + }}, + input.raw()); + }; + + auto tryResolveRef = [&](const DrvRef & ref) -> std::optional> { + return std::visit( + overloaded{ + [](const OutputName & outputName) -> std::optional> { return outputName; }, + [&](const SingleDerivedPath & input) -> std::optional> { + return tryResolvePath(input); + }}, + ref); + }; + + auto tryResolveRefSet = + [&](const std::set> & refSet) -> std::optional>> { + std::set> resolvedSet; + for (const auto & ref : refSet) { + auto resolvedRef = tryResolveRef(ref); + if (!resolvedRef) + return std::nullopt; + resolvedSet.insert(*resolvedRef); + } + return resolvedSet; + }; + + // Helper function to try resolving OutputChecks using functional style + auto tryResolveOutputChecks = [&](const DerivationOptions::OutputChecks & checks) + -> std::optional::OutputChecks> { + std::optional>> resolvedAllowedReferences; + if (checks.allowedReferences) { + resolvedAllowedReferences = tryResolveRefSet(*checks.allowedReferences); + if (!resolvedAllowedReferences) + return std::nullopt; + } + + std::optional>> resolvedAllowedRequisites; + if (checks.allowedRequisites) { + resolvedAllowedRequisites = tryResolveRefSet(*checks.allowedRequisites); + if (!resolvedAllowedRequisites) + return std::nullopt; + } + + auto resolvedDisallowedReferences = tryResolveRefSet(checks.disallowedReferences); + if (!resolvedDisallowedReferences) + return std::nullopt; + + auto resolvedDisallowedRequisites = tryResolveRefSet(checks.disallowedRequisites); + if (!resolvedDisallowedRequisites) + return std::nullopt; + + return DerivationOptions::OutputChecks{ + .ignoreSelfRefs = checks.ignoreSelfRefs, + .maxSize = checks.maxSize, + .maxClosureSize = checks.maxClosureSize, + .allowedReferences = resolvedAllowedReferences, + .disallowedReferences = *resolvedDisallowedReferences, + .allowedRequisites = resolvedAllowedRequisites, + .disallowedRequisites = *resolvedDisallowedRequisites, + }; + }; + + // Helper function to resolve exportReferencesGraph using functional style + auto tryResolveExportReferencesGraph = [&](const std::map> & exportGraph) + -> std::optional>> { + std::map> resolved; + for (const auto & [name, inputPaths] : exportGraph) { + std::set resolvedPaths; + for (const auto & inputPath : inputPaths) { + auto resolvedPath = tryResolvePath(inputPath); + if (!resolvedPath) + return std::nullopt; + resolvedPaths.insert(*resolvedPath); + } + resolved.emplace(name, std::move(resolvedPaths)); + } + return resolved; + }; + + // Resolve outputChecks using functional style with std::visit + auto resolvedOutputChecks = std::visit( + overloaded{ + [&](const DerivationOptions::OutputChecks & checks) + -> std::optional::OutputChecks, + std::map::OutputChecks>>> { + auto resolved = tryResolveOutputChecks(checks); + if (!resolved) + return std::nullopt; + return std::variant< + DerivationOptions::OutputChecks, + std::map::OutputChecks>>(*resolved); + }, + [&](const std::map::OutputChecks> & checksMap) + -> std::optional::OutputChecks, + std::map::OutputChecks>>> { + std::map::OutputChecks> resolvedMap; + for (const auto & [outputName, checks] : checksMap) { + auto resolved = tryResolveOutputChecks(checks); + if (!resolved) + return std::nullopt; + resolvedMap.emplace(outputName, *resolved); + } + return std::variant< + DerivationOptions::OutputChecks, + std::map::OutputChecks>>(resolvedMap); + }}, + drvOptions.outputChecks); + + if (!resolvedOutputChecks) + return std::nullopt; + + // Resolve exportReferencesGraph + auto resolvedExportGraph = tryResolveExportReferencesGraph(drvOptions.exportReferencesGraph); + if (!resolvedExportGraph) + return std::nullopt; + + // Return resolved DerivationOptions using designated initializers + return DerivationOptions{ + .outputChecks = *resolvedOutputChecks, + .unsafeDiscardReferences = drvOptions.unsafeDiscardReferences, + .passAsFile = drvOptions.passAsFile, + .exportReferencesGraph = *resolvedExportGraph, + .additionalSandboxProfile = drvOptions.additionalSandboxProfile, + .noChroot = drvOptions.noChroot, + .impureHostDeps = drvOptions.impureHostDeps, + .impureEnvVars = drvOptions.impureEnvVars, + .allowLocalNetworking = drvOptions.allowLocalNetworking, + .requiredSystemFeatures = drvOptions.requiredSystemFeatures, + .preferLocalBuild = drvOptions.preferLocalBuild, + .allowSubstitutes = drvOptions.allowSubstitutes, + }; +} + +template struct DerivationOptions; +template struct DerivationOptions; + } // namespace nix namespace nlohmann { using namespace nix; -DerivationOptions adl_serializer::from_json(const json & json_) +DerivationOptions adl_serializer>::from_json(const json & json_) { auto & json = getObject(json_); return { - .outputChecks = [&]() -> OutputChecksVariant { + .outputChecks = [&]() -> OutputChecksVariant { auto outputChecks = getObject(valueAt(json, "outputChecks")); auto forAllOutputsOpt = optionalValueAt(outputChecks, "forAllOutputs"); auto perOutputOpt = optionalValueAt(outputChecks, "perOutput"); if (forAllOutputsOpt && !perOutputOpt) { - return static_cast(*forAllOutputsOpt); + return static_cast>(*forAllOutputsOpt); } else if (perOutputOpt && !forAllOutputsOpt) { - return static_cast>(*perOutputOpt); + return static_cast>>(*perOutputOpt); } else { throw Error("Exactly one of 'perOutput' or 'forAllOutputs' is required"); } @@ -377,7 +627,7 @@ DerivationOptions adl_serializer::from_json(const json & json .unsafeDiscardReferences = valueAt(json, "unsafeDiscardReferences"), .passAsFile = getStringSet(valueAt(json, "passAsFile")), - .exportReferencesGraph = getMap(getObject(valueAt(json, "exportReferencesGraph")), getStringSet), + .exportReferencesGraph = valueAt(json, "exportReferencesGraph"), .additionalSandboxProfile = getString(valueAt(json, "additionalSandboxProfile")), .noChroot = getBoolean(valueAt(json, "noChroot")), @@ -391,16 +641,17 @@ DerivationOptions adl_serializer::from_json(const json & json }; } -void adl_serializer::to_json(json & json, const DerivationOptions & o) +void adl_serializer>::to_json( + json & json, const DerivationOptions & o) { json["outputChecks"] = std::visit( overloaded{ - [&](const OutputChecks & checks) { + [&](const OutputChecks & checks) { nlohmann::json outputChecks; outputChecks["forAllOutputs"] = checks; return outputChecks; }, - [&](const std::map & checksPerOutput) { + [&](const std::map> & checksPerOutput) { nlohmann::json outputChecks; outputChecks["perOutput"] = checksPerOutput; return outputChecks; @@ -432,7 +683,7 @@ static inline std::optional ptrToOwned(const json * ptr) return std::nullopt; } -DerivationOptions::OutputChecks adl_serializer::from_json(const json & json_) +OutputChecks adl_serializer>::from_json(const json & json_) { auto & json = getObject(json_); @@ -440,14 +691,16 @@ DerivationOptions::OutputChecks adl_serializer: .ignoreSelfRefs = getBoolean(valueAt(json, "ignoreSelfRefs")), .maxSize = ptrToOwned(getNullable(valueAt(json, "maxSize"))), .maxClosureSize = ptrToOwned(getNullable(valueAt(json, "maxClosureSize"))), - .allowedReferences = ptrToOwned(getNullable(valueAt(json, "allowedReferences"))), - .disallowedReferences = getStringSet(valueAt(json, "disallowedReferences")), - .allowedRequisites = ptrToOwned(getNullable(valueAt(json, "allowedRequisites"))), - .disallowedRequisites = getStringSet(valueAt(json, "disallowedRequisites")), + .allowedReferences = + ptrToOwned>>(getNullable(valueAt(json, "allowedReferences"))), + .disallowedReferences = valueAt(json, "disallowedReferences"), + .allowedRequisites = + ptrToOwned>>(getNullable(valueAt(json, "allowedRequisites"))), + .disallowedRequisites = valueAt(json, "disallowedRequisites"), }; } -void adl_serializer::to_json(json & json, const DerivationOptions::OutputChecks & c) +void adl_serializer>::to_json(json & json, const OutputChecks & c) { json["ignoreSelfRefs"] = c.ignoreSelfRefs; json["maxSize"] = c.maxSize; diff --git a/src/libstore/downstream-placeholder.cc b/src/libstore/downstream-placeholder.cc index 780717a62..73ed2b74a 100644 --- a/src/libstore/downstream-placeholder.cc +++ b/src/libstore/downstream-placeholder.cc @@ -1,5 +1,6 @@ #include "nix/store/downstream-placeholder.hh" #include "nix/store/derivations.hh" +#include "nix/util/json-utils.hh" namespace nix { @@ -49,3 +50,45 @@ DownstreamPlaceholder DownstreamPlaceholder::fromSingleDerivedPathBuilt( } } // namespace nix + +namespace nlohmann { + +using namespace nix; + +template +DrvRef adl_serializer>::from_json(const json & json) +{ + // OutputName case: { "drvPath": "self", "output": } + if (json.type() == nlohmann::json::value_t::object) { + auto & obj = getObject(json); + if (auto * drvPath_ = get(obj, "drvPath")) { + auto & drvPath = *drvPath_; + if (drvPath.type() == nlohmann::json::value_t::string && getString(drvPath) == "self") { + return getString(valueAt(obj, "output")); + } + } + } + + // Input case + return adl_serializer::from_json(json); +} + +template +void adl_serializer>::to_json(json & json, const DrvRef & ref) +{ + std::visit( + overloaded{ + [&](const OutputName & outputName) { + json = nlohmann::json::object(); + json["drvPath"] = "self"; + json["output"] = outputName; + }, + [&](const Item & item) { json = item; }, + }, + ref); +} + +template struct adl_serializer>; +template struct adl_serializer>; + +} // namespace nlohmann diff --git a/src/libstore/include/nix/store/build/derivation-builder.hh b/src/libstore/include/nix/store/build/derivation-builder.hh index 5eed38462..af84661e2 100644 --- a/src/libstore/include/nix/store/build/derivation-builder.hh +++ b/src/libstore/include/nix/store/build/derivation-builder.hh @@ -69,7 +69,7 @@ struct DerivationBuilderParams * * @todo this should be part of `Derivation`. */ - const DerivationOptions & drvOptions; + const DerivationOptions & drvOptions; // The remainder is state held during the build. diff --git a/src/libstore/include/nix/store/build/derivation-building-goal.hh b/src/libstore/include/nix/store/build/derivation-building-goal.hh index 547e533e2..8277d6b57 100644 --- a/src/libstore/include/nix/store/build/derivation-building-goal.hh +++ b/src/libstore/include/nix/store/build/derivation-building-goal.hh @@ -52,7 +52,7 @@ private: */ std::unique_ptr drv; - std::unique_ptr drvOptions; + std::unique_ptr> drvOptions; /** * The remainder is state held during the build. diff --git a/src/libstore/include/nix/store/build/derivation-env-desugar.hh b/src/libstore/include/nix/store/build/derivation-env-desugar.hh index 6e2efa6bb..a10ec9fa8 100644 --- a/src/libstore/include/nix/store/build/derivation-env-desugar.hh +++ b/src/libstore/include/nix/store/build/derivation-env-desugar.hh @@ -8,6 +8,7 @@ namespace nix { class Store; struct Derivation; +template struct DerivationOptions; /** @@ -77,7 +78,10 @@ struct DesugaredEnv * just part of `Derivation`. */ static DesugaredEnv create( - Store & store, const Derivation & drv, const DerivationOptions & drvOptions, const StorePathSet & inputPaths); + Store & store, + const Derivation & drv, + const DerivationOptions & drvOptions, + const StorePathSet & inputPaths); }; } // namespace nix diff --git a/src/libstore/include/nix/store/derivation-options.hh b/src/libstore/include/nix/store/derivation-options.hh index 88694f730..0b79af85d 100644 --- a/src/libstore/include/nix/store/derivation-options.hh +++ b/src/libstore/include/nix/store/derivation-options.hh @@ -8,7 +8,8 @@ #include "nix/util/types.hh" #include "nix/util/json-impls.hh" -#include "nix/store/path.hh" +#include "nix/store/store-dir-config.hh" +#include "nix/store/downstream-placeholder.hh" namespace nix { @@ -17,6 +18,9 @@ struct StoreDirConfig; struct BasicDerivation; struct StructuredAttrs; +template +struct DerivedPathMap; + /** * This represents all the special options on a `Derivation`. * @@ -34,6 +38,7 @@ struct StructuredAttrs; * separately. That would be nice to separate concerns, and not make any * environment variable names magical. */ +template struct DerivationOptions { struct OutputChecks @@ -41,13 +46,15 @@ struct DerivationOptions bool ignoreSelfRefs = false; std::optional maxSize, maxClosureSize; + using DrvRef = nix::DrvRef; + /** * env: allowedReferences * * A value of `nullopt` indicates that the check is skipped. * This means that all references are allowed. */ - std::optional allowedReferences; + std::optional> allowedReferences; /** * env: disallowedReferences @@ -55,21 +62,21 @@ struct DerivationOptions * No needed for `std::optional`, because skipping the check is * the same as disallowing the references. */ - StringSet disallowedReferences; + std::set disallowedReferences; /** * env: allowedRequisites * * See `allowedReferences` */ - std::optional allowedRequisites; + std::optional> allowedRequisites; /** * env: disallowedRequisites * * See `disallowedReferences` */ - StringSet disallowedRequisites; + std::set disallowedRequisites; bool operator==(const OutputChecks &) const = default; }; @@ -116,23 +123,7 @@ struct DerivationOptions * attributes give to the builder. The set of paths in the original JSON * is replaced with a list of `PathInfo` in JSON format. */ - std::map exportReferencesGraph; - - /** - * Once a derivations is resolved, the strings in in - * `exportReferencesGraph` should all be store paths (with possible - * suffix paths, but those are discarded). - * - * @return The parsed path set for for each key in the map. - * - * @todo Ideally, `exportReferencesGraph` would just store - * `StorePath`s for this, but we can't just do that, because for CA - * derivations they is actually in general `DerivedPath`s (via - * placeholder strings) until the derivation is resolved and exact - * inputs store paths are known. We can use better types for that - * too, but that is a longer project. - */ - std::map getParsedExportReferencesGraph(const StoreDirConfig & store) const; + std::map> exportReferencesGraph; /** * env: __sandboxProfile @@ -185,18 +176,6 @@ struct DerivationOptions bool operator==(const DerivationOptions &) const = default; - /** - * Parse this information from its legacy encoding as part of the - * environment. This should not be used with nice greenfield formats - * (e.g. JSON) but is necessary for supporting old formats (e.g. - * ATerm). - */ - static DerivationOptions - fromStructuredAttrs(const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn = true); - - static DerivationOptions - fromStructuredAttrs(const StringMap & env, const std::optional & parsed, bool shouldWarn = true); - /** * @param drv Must be the same derivation we parsed this from. In * the future we'll flip things around so a `BasicDerivation` has @@ -222,7 +201,55 @@ struct DerivationOptions bool useUidRange(const BasicDerivation & drv) const; }; +extern template struct DerivationOptions; +extern template struct DerivationOptions; + +struct DerivationOutput; + +/** + * Parse this information from its legacy encoding as part of the + * environment. This should not be used with nice greenfield formats + * (e.g. JSON) but is necessary for supporting old formats (e.g. + * ATerm). + */ +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +std::optional> tryResolve( + const DerivationOptions & drvOptions, + std::function(ref drvPath, const std::string & outputName)> + queryResolutionChain); + }; // namespace nix -JSON_IMPL(DerivationOptions); -JSON_IMPL(DerivationOptions::OutputChecks) +JSON_IMPL(nix::DerivationOptions); +JSON_IMPL(nix::DerivationOptions); +JSON_IMPL(nix::DerivationOptions::OutputChecks) +JSON_IMPL(nix::DerivationOptions::OutputChecks) diff --git a/src/libstore/include/nix/store/downstream-placeholder.hh b/src/libstore/include/nix/store/downstream-placeholder.hh index ee4d9e3c2..ba3e9faef 100644 --- a/src/libstore/include/nix/store/downstream-placeholder.hh +++ b/src/libstore/include/nix/store/downstream-placeholder.hh @@ -2,11 +2,23 @@ ///@file #include "nix/util/hash.hh" +#include "nix/util/json-impls.hh" #include "nix/store/path.hh" #include "nix/store/derived-path.hh" namespace nix { +/** + * A reference is either to a to-be-registered output (by name), + * or to an already-registered store object (by `Input`). + * + * `Ref +using DrvRef = std::variant; + /** * Downstream Placeholders are opaque and almost certainly unique values * used to allow derivations to refer to store objects which are yet to @@ -92,3 +104,17 @@ public: }; } // namespace nix + +namespace nlohmann { + +template +struct adl_serializer> +{ + static nix::DrvRef from_json(const json & json); + static void to_json(json & json, const nix::DrvRef & t); +}; + +extern template struct adl_serializer>; +extern template struct adl_serializer>; + +} // namespace nlohmann diff --git a/src/libstore/include/nix/store/parsed-derivations.hh b/src/libstore/include/nix/store/parsed-derivations.hh index 52e97b0e7..098591310 100644 --- a/src/libstore/include/nix/store/parsed-derivations.hh +++ b/src/libstore/include/nix/store/parsed-derivations.hh @@ -9,6 +9,7 @@ namespace nix { class Store; +template struct DerivationOptions; struct DerivationOutput; @@ -47,7 +48,7 @@ struct StructuredAttrs nlohmann::json::object_t prepareStructuredAttrs( Store & store, - const DerivationOptions & drvOptions, + const DerivationOptions & drvOptions, const StorePathSet & inputPaths, const DerivationOutputs & outputs) const; diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 8b2a7287e..642ac0978 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -224,11 +224,12 @@ MissingPaths Store::queryMissing(const std::vector & targets) return; auto drv = make_ref(derivationFromPath(drvPath)); - DerivationOptions drvOptions; + DerivationOptions drvOptions; try { // FIXME: this is a lot of work just to get the value // of `allowSubstitutes`. - drvOptions = DerivationOptions::fromStructuredAttrs(drv->env, drv->structuredAttrs); + drvOptions = + derivationOptionsFromStructuredAttrs(*this, drv->inputDrvs, drv->env, drv->structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", printStorePath(drvPath)); throw; diff --git a/src/libstore/parsed-derivations.cc b/src/libstore/parsed-derivations.cc index 8d147f65f..95434bd20 100644 --- a/src/libstore/parsed-derivations.cc +++ b/src/libstore/parsed-derivations.cc @@ -100,7 +100,7 @@ static nlohmann::json pathInfoToJSON(Store & store, const StorePathSet & storePa nlohmann::json::object_t StructuredAttrs::prepareStructuredAttrs( Store & store, - const DerivationOptions & drvOptions, + const DerivationOptions & drvOptions, const StorePathSet & inputPaths, const DerivationOutputs & outputs) const { @@ -114,8 +114,8 @@ nlohmann::json::object_t StructuredAttrs::prepareStructuredAttrs( json["outputs"] = std::move(outputsJson); /* Handle exportReferencesGraph. */ - for (auto & [key, storePaths] : drvOptions.getParsedExportReferencesGraph(store)) { - json[key] = pathInfoToJSON(store, store.exportReferences(storePaths, storePaths)); + for (auto & [key, storePaths] : drvOptions.exportReferencesGraph) { + json[key] = pathInfoToJSON(store, store.exportReferences(storePaths, inputPaths)); } return json; diff --git a/src/nix/nix-build/nix-build.cc b/src/nix/nix-build/nix-build.cc index 4d876c9eb..00ef32dfa 100644 --- a/src/nix/nix-build/nix-build.cc +++ b/src/nix/nix-build/nix-build.cc @@ -554,9 +554,9 @@ static void main_nix_build(int argc, char ** argv) env["NIX_STORE"] = store->storeDir; env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores ? settings.buildCores : settings.getDefaultCores()); - DerivationOptions drvOptions; + DerivationOptions drvOptions; try { - drvOptions = DerivationOptions::fromStructuredAttrs(drv.env, drv.structuredAttrs); + drvOptions = derivationOptionsFromStructuredAttrs(*store, drv.env, drv.structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", store->printStorePath(packageInfo.requireDrvPath())); throw; diff --git a/tests/functional/check-refs.sh b/tests/functional/check-refs.sh index 590c3fb53..8eb6aaf68 100755 --- a/tests/functional/check-refs.sh +++ b/tests/functional/check-refs.sh @@ -64,5 +64,5 @@ fi if isDaemonNewer "2.28pre20241225"; then # test12 should fail (syntactically invalid). expectStderr 1 nix-build -vvv -o "$RESULT" check-refs.nix -A test12 >"$TEST_ROOT/test12.stderr" - grepQuiet -F "output check for 'lib' contains an illegal reference specifier 'dev', expected store path or output name (one of [lib, out])" < "$TEST_ROOT/test12.stderr" + grepQuiet -F "output check for 'lib' contains output name 'dev', but this is not a valid output of this derivation. (Valid outputs are [lib, out].)" < "$TEST_ROOT/test12.stderr" fi diff --git a/tests/functional/derivation/advanced-attributes-structured-attrs.nix b/tests/functional/derivation/advanced-attributes-structured-attrs.nix index 46f619272..b11041303 100644 --- a/tests/functional/derivation/advanced-attributes-structured-attrs.nix +++ b/tests/functional/derivation/advanced-attributes-structured-attrs.nix @@ -66,10 +66,16 @@ derivation' { outputChecks = { out = { allowedReferences = [ foo ]; - allowedRequisites = [ foo.dev ]; + allowedRequisites = [ + foo.dev + "bin" + ]; }; bin = { - disallowedReferences = [ bar ]; + disallowedReferences = [ + bar + "dev" + ]; disallowedRequisites = [ bar.dev ]; }; dev = { diff --git a/tests/functional/derivation/advanced-attributes.nix b/tests/functional/derivation/advanced-attributes.nix index dd0c09e22..19a80f15d 100644 --- a/tests/functional/derivation/advanced-attributes.nix +++ b/tests/functional/derivation/advanced-attributes.nix @@ -58,8 +58,14 @@ derivation' { impureEnvVars = [ "UNICORN" ]; __darwinAllowLocalNetworking = true; allowedReferences = [ foo ]; - allowedRequisites = [ foo.dev ]; - disallowedReferences = [ bar ]; + allowedRequisites = [ + foo.dev + "bin" + ]; + disallowedReferences = [ + bar + "dev" + ]; disallowedRequisites = [ bar.dev ]; requiredSystemFeatures = [ "rainbow" diff --git a/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv b/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv index cd02c2f86..eeaba88e6 100644 --- a/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv +++ b/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv @@ -1 +1 @@ -Derive([("bin","","r:sha256",""),("dev","","r:sha256",""),("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"refs2\":[\"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m"),("dev","/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")]) \ No newline at end of file +Derive([("bin","","r:sha256",""),("dev","","r:sha256",""),("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"refs2\":[\"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\",\"dev\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\",\"bin\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m"),("dev","/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")]) \ No newline at end of file diff --git a/tests/functional/derivation/ca/advanced-attributes.drv b/tests/functional/derivation/ca/advanced-attributes.drv index 068cb593e..ee5968cdc 100644 --- a/tests/functional/derivation/ca/advanced-attributes.drv +++ b/tests/functional/derivation/ca/advanced-attributes.drv @@ -1 +1 @@ -Derive([("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"),("allowedRequisites","/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"),("builder","/bin/bash"),("disallowedReferences","/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"),("disallowedRequisites","/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"),("exportReferencesGraph","refs1 /164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9 refs2 /nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file +Derive([("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"),("allowedRequisites","/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z bin"),("builder","/bin/bash"),("disallowedReferences","/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g dev"),("disallowedRequisites","/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"),("exportReferencesGraph","refs1 /164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9 refs2 /nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file diff --git a/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv b/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv index 1dfcac42d..0aa82e636 100644 --- a/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv +++ b/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv @@ -1 +1 @@ -Derive([("bin","/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin","",""),("dev","/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev","",""),("out","/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"refs2\":[\"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar\"],\"disallowedRequisites\":[\"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"allowedRequisites\":[\"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin"),("dev","/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev"),("out","/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs")]) \ No newline at end of file +Derive([("bin","/nix/store/cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin","",""),("dev","/nix/store/ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev","",""),("out","/nix/store/h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"refs2\":[\"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar\",\"dev\"],\"disallowedRequisites\":[\"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"allowedRequisites\":[\"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev\",\"bin\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/nix/store/cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin"),("dev","/nix/store/ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev"),("out","/nix/store/h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs")]) \ No newline at end of file diff --git a/tests/functional/derivation/ia/advanced-attributes.drv b/tests/functional/derivation/ia/advanced-attributes.drv index c71a88886..4bc7320f5 100644 --- a/tests/functional/derivation/ia/advanced-attributes.drv +++ b/tests/functional/derivation/ia/advanced-attributes.drv @@ -1 +1 @@ -Derive([("out","/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"),("allowedRequisites","/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"),("builder","/bin/bash"),("disallowedReferences","/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"),("disallowedRequisites","/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"),("exportReferencesGraph","refs1 /nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo refs2 /nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file +Derive([("out","/nix/store/ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"),("allowedRequisites","/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev bin"),("builder","/bin/bash"),("disallowedReferences","/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar dev"),("disallowedRequisites","/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"),("exportReferencesGraph","refs1 /nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo refs2 /nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/nix/store/ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file