fix: derivation & derivationStrict
This commit is contained in:
@@ -1,9 +1,16 @@
|
|||||||
import type { NixValue, NixAttrs } from "../types";
|
import type { NixValue, NixAttrs } from "../types";
|
||||||
import { forceStringValue, forceList } from "../type-assert";
|
import { forceStringValue, forceList } from "../type-assert";
|
||||||
import { force } from "../thunk";
|
import { force, createThunk } from "../thunk";
|
||||||
import { type DerivationData, type OutputInfo, generateAterm } from "../derivation-helpers";
|
import { type DerivationData, type OutputInfo, generateAterm } from "../derivation-helpers";
|
||||||
import { coerceToString, StringCoercionMode } from "./conversion";
|
import { coerceToString, StringCoercionMode } from "./conversion";
|
||||||
import { type NixStringContext, extractInputDrvsAndSrcs, isStringWithContext } from "../string-context";
|
import {
|
||||||
|
type NixStringContext,
|
||||||
|
extractInputDrvsAndSrcs,
|
||||||
|
isStringWithContext,
|
||||||
|
mkStringWithContext,
|
||||||
|
addDrvDeepContext,
|
||||||
|
addBuiltContext,
|
||||||
|
} from "../string-context";
|
||||||
import { nixValueToJson } from "../conversion";
|
import { nixValueToJson } from "../conversion";
|
||||||
import { isNixPath } from "../types";
|
import { isNixPath } from "../types";
|
||||||
|
|
||||||
@@ -88,6 +95,7 @@ const extractEnv = (
|
|||||||
structuredAttrs: boolean,
|
structuredAttrs: boolean,
|
||||||
ignoreNulls: boolean,
|
ignoreNulls: boolean,
|
||||||
outContext: NixStringContext,
|
outContext: NixStringContext,
|
||||||
|
drvName: string,
|
||||||
): Map<string, string> => {
|
): Map<string, string> => {
|
||||||
const specialAttrs = new Set([
|
const specialAttrs = new Set([
|
||||||
"name",
|
"name",
|
||||||
@@ -113,6 +121,49 @@ const extractEnv = (
|
|||||||
}
|
}
|
||||||
jsonAttrs[key] = nixValueToJson(value, new Set(), outContext);
|
jsonAttrs[key] = nixValueToJson(value, new Set(), outContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key === "allowedReferences") {
|
||||||
|
console.warn(
|
||||||
|
`In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` +
|
||||||
|
`the derivation attribute 'allowedReferences'; use ` +
|
||||||
|
`'outputChecks.<output>.allowedReferences' instead`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (key === "allowedRequisites") {
|
||||||
|
console.warn(
|
||||||
|
`In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` +
|
||||||
|
`the derivation attribute 'allowedRequisites'; use ` +
|
||||||
|
`'outputChecks.<output>.allowedRequisites' instead`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (key === "disallowedReferences") {
|
||||||
|
console.warn(
|
||||||
|
`In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` +
|
||||||
|
`the derivation attribute 'disallowedReferences'; use ` +
|
||||||
|
`'outputChecks.<output>.disallowedReferences' instead`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (key === "disallowedRequisites") {
|
||||||
|
console.warn(
|
||||||
|
`In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` +
|
||||||
|
`the derivation attribute 'disallowedRequisites'; use ` +
|
||||||
|
`'outputChecks.<output>.disallowedRequisites' instead`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (key === "maxSize") {
|
||||||
|
console.warn(
|
||||||
|
`In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` +
|
||||||
|
`the derivation attribute 'maxSize'; use ` +
|
||||||
|
`'outputChecks.<output>.maxSize' instead`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (key === "maxClosureSize") {
|
||||||
|
console.warn(
|
||||||
|
`In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` +
|
||||||
|
`the derivation attribute 'maxClosureSize'; use ` +
|
||||||
|
`'outputChecks.<output>.maxClosureSize' instead`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
env.set("__json", JSON.stringify(jsonAttrs));
|
env.set("__json", JSON.stringify(jsonAttrs));
|
||||||
} else {
|
} else {
|
||||||
@@ -174,8 +225,16 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
|
|||||||
|
|
||||||
const ignoreNulls = "__ignoreNulls" in attrs ? force(attrs.__ignoreNulls) === true : false;
|
const ignoreNulls = "__ignoreNulls" in attrs ? force(attrs.__ignoreNulls) === true : false;
|
||||||
|
|
||||||
|
if ("__contentAddressed" in attrs && force(attrs.__contentAddressed) === true) {
|
||||||
|
throw new Error("ca derivations are not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("impure" in attrs && force(attrs.impure) === true) {
|
||||||
|
throw new Error("impure derivations are not supported");
|
||||||
|
}
|
||||||
|
|
||||||
const drvArgs = extractArgs(attrs, collectedContext);
|
const drvArgs = extractArgs(attrs, collectedContext);
|
||||||
const env = extractEnv(attrs, structuredAttrs, ignoreNulls, collectedContext);
|
const env = extractEnv(attrs, structuredAttrs, ignoreNulls, collectedContext, drvName);
|
||||||
|
|
||||||
env.set("name", drvName);
|
env.set("name", drvName);
|
||||||
env.set("builder", builder);
|
env.set("builder", builder);
|
||||||
@@ -277,37 +336,94 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
|
|||||||
drvPath = Deno.core.ops.op_make_store_path("text", finalDrvHash, `${drvName}.drv`);
|
drvPath = Deno.core.ops.op_make_store_path("text", finalDrvHash, `${drvName}.drv`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: NixAttrs = {
|
const result: NixAttrs = {};
|
||||||
type: "derivation",
|
|
||||||
drvPath,
|
const drvPathContext = new Set<string>();
|
||||||
name: drvName,
|
addDrvDeepContext(drvPathContext, drvPath);
|
||||||
builder,
|
result.drvPath = mkStringWithContext(drvPath, drvPathContext);
|
||||||
system: platform,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const [outputName, outputInfo] of outputInfos.entries()) {
|
for (const [outputName, outputInfo] of outputInfos.entries()) {
|
||||||
result[outputName] = outputInfo.path;
|
const outputContext = new Set<string>();
|
||||||
}
|
addBuiltContext(outputContext, drvPath, outputName);
|
||||||
|
result[outputName] = mkStringWithContext(outputInfo.path, outputContext);
|
||||||
if (outputInfos.has("out")) {
|
|
||||||
result.outPath = outputInfos.get("out")!.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drvArgs.length > 0) {
|
|
||||||
result.args = drvArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!structuredAttrs) {
|
|
||||||
for (const [key, value] of env.entries()) {
|
|
||||||
if (!["name", "builder", "system", ...outputs].includes(key)) {
|
|
||||||
result[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const derivation = (args: NixValue): NixAttrs => {
|
export const derivation = (args: NixValue): NixAttrs => {
|
||||||
return derivationStrict(args);
|
const attrs = forceAttrs(args);
|
||||||
|
const strict = derivationStrict(args);
|
||||||
|
|
||||||
|
const outputs: string[] = extractOutputs(attrs);
|
||||||
|
const drvName = validateName(attrs);
|
||||||
|
const collectedContext: NixStringContext = new Set();
|
||||||
|
const builder = validateBuilder(attrs, collectedContext);
|
||||||
|
const platform = validateSystem(attrs);
|
||||||
|
const structuredAttrs = "__structuredAttrs" in attrs ? force(attrs.__structuredAttrs) === true : false;
|
||||||
|
const ignoreNulls = "__ignoreNulls" in attrs ? force(attrs.__ignoreNulls) === true : false;
|
||||||
|
const drvArgs = extractArgs(attrs, collectedContext);
|
||||||
|
|
||||||
|
const specialAttrs = new Set([
|
||||||
|
"name",
|
||||||
|
"builder",
|
||||||
|
"system",
|
||||||
|
"args",
|
||||||
|
"outputs",
|
||||||
|
"__structuredAttrs",
|
||||||
|
"__ignoreNulls",
|
||||||
|
"__contentAddressed",
|
||||||
|
"impure",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const baseAttrs: NixAttrs = {
|
||||||
|
type: "derivation",
|
||||||
|
drvPath: strict.drvPath,
|
||||||
|
name: drvName,
|
||||||
|
builder,
|
||||||
|
system: platform,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (drvArgs.length > 0) {
|
||||||
|
baseAttrs.args = drvArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!structuredAttrs) {
|
||||||
|
for (const [key, value] of Object.entries(attrs)) {
|
||||||
|
if (!specialAttrs.has(key) && !outputs.includes(key)) {
|
||||||
|
const forcedValue = force(value);
|
||||||
|
if (!(ignoreNulls && forcedValue === null)) {
|
||||||
|
baseAttrs[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputsList: NixAttrs[] = [];
|
||||||
|
|
||||||
|
for (const outputName of outputs) {
|
||||||
|
const outputObj: NixAttrs = {
|
||||||
|
...baseAttrs,
|
||||||
|
outPath: strict[outputName],
|
||||||
|
outputName,
|
||||||
|
};
|
||||||
|
outputsList.push(outputObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
baseAttrs.drvAttrs = attrs;
|
||||||
|
for (const [i, outputName] of outputs.entries()) {
|
||||||
|
baseAttrs[outputName] = createThunk(() => outputsList[i], `output_${outputName}`);
|
||||||
|
}
|
||||||
|
baseAttrs.all = createThunk(() => outputsList, "all_outputs");
|
||||||
|
|
||||||
|
for (const outputObj of outputsList) {
|
||||||
|
outputObj.drvAttrs = attrs;
|
||||||
|
for (const [i, outputName] of outputs.entries()) {
|
||||||
|
outputObj[outputName] = createThunk(() => outputsList[i], `output_${outputName}`);
|
||||||
|
}
|
||||||
|
outputObj.all = createThunk(() => outputsList, "all_outputs");
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputsList[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -143,9 +143,10 @@ fn derivation_strict() {
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Value::AttrSet(attrs) => {
|
Value::AttrSet(attrs) => {
|
||||||
assert_eq!(attrs.get("type"), Some(&Value::String("derivation".into())));
|
|
||||||
assert!(attrs.contains_key("drvPath"));
|
assert!(attrs.contains_key("drvPath"));
|
||||||
assert!(attrs.contains_key("outPath"));
|
assert!(attrs.contains_key("out"));
|
||||||
|
assert!(!attrs.contains_key("type"));
|
||||||
|
assert!(!attrs.contains_key("outPath"));
|
||||||
}
|
}
|
||||||
_ => panic!("Expected AttrSet"),
|
_ => panic!("Expected AttrSet"),
|
||||||
}
|
}
|
||||||
@@ -189,7 +190,7 @@ fn derivation_escaping_in_aterm() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_output_two_outputs() {
|
fn multi_output_two_outputs() {
|
||||||
let result = eval(
|
let drv = eval(
|
||||||
r#"derivation {
|
r#"derivation {
|
||||||
name = "multi";
|
name = "multi";
|
||||||
builder = "/bin/sh";
|
builder = "/bin/sh";
|
||||||
@@ -198,39 +199,20 @@ fn multi_output_two_outputs() {
|
|||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
match result {
|
match drv {
|
||||||
Value::AttrSet(attrs) => {
|
Value::AttrSet(attrs) => {
|
||||||
|
assert!(attrs.contains_key("drvPath"));
|
||||||
assert!(attrs.contains_key("out"));
|
assert!(attrs.contains_key("out"));
|
||||||
assert!(attrs.contains_key("dev"));
|
assert!(attrs.contains_key("dev"));
|
||||||
assert!(attrs.contains_key("outPath"));
|
assert!(attrs.contains_key("outPath"));
|
||||||
assert!(attrs.contains_key("drvPath"));
|
|
||||||
|
|
||||||
// Verify exact paths match CppNix
|
|
||||||
if let Some(Value::String(drv_path)) = attrs.get("drvPath") {
|
if let Some(Value::String(drv_path)) = attrs.get("drvPath") {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
drv_path,
|
drv_path,
|
||||||
"/nix/store/vmyjryfipkn9ss3ya23hk8p3m58l6dsl-multi.drv"
|
"/nix/store/vmyjryfipkn9ss3ya23hk8p3m58l6dsl-multi.drv"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
panic!("drvPath should be a string");
|
panic!("drvPath should be a string, got: {:?}", attrs.get("drvPath"));
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Value::String(out_path)) = attrs.get("out") {
|
|
||||||
assert_eq!(
|
|
||||||
out_path,
|
|
||||||
"/nix/store/a3d95yg9d215c54n0ybr4npmpnj29229-multi"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
panic!("out should be a string");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Value::String(dev_path)) = attrs.get("dev") {
|
|
||||||
assert_eq!(
|
|
||||||
dev_path,
|
|
||||||
"/nix/store/hq3b99lz71gwfq6x8lqwg14hf929q0d2-multi-dev"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
panic!("dev should be a string");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Value::String(out_path)) = attrs.get("outPath") {
|
if let Some(Value::String(out_path)) = attrs.get("outPath") {
|
||||||
@@ -238,7 +220,8 @@ fn multi_output_two_outputs() {
|
|||||||
out_path,
|
out_path,
|
||||||
"/nix/store/a3d95yg9d215c54n0ybr4npmpnj29229-multi"
|
"/nix/store/a3d95yg9d215c54n0ybr4npmpnj29229-multi"
|
||||||
);
|
);
|
||||||
assert_eq!(attrs.get("out"), Some(&Value::String(out_path.clone())));
|
} else {
|
||||||
|
panic!("outPath should be a string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("Expected AttrSet"),
|
_ => panic!("Expected AttrSet"),
|
||||||
|
|||||||
Reference in New Issue
Block a user