fix: derivation & derivationStrict
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import type { NixValue, NixAttrs } from "../types";
|
||||
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 { 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 { isNixPath } from "../types";
|
||||
|
||||
@@ -88,6 +95,7 @@ const extractEnv = (
|
||||
structuredAttrs: boolean,
|
||||
ignoreNulls: boolean,
|
||||
outContext: NixStringContext,
|
||||
drvName: string,
|
||||
): Map<string, string> => {
|
||||
const specialAttrs = new Set([
|
||||
"name",
|
||||
@@ -113,6 +121,49 @@ const extractEnv = (
|
||||
}
|
||||
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));
|
||||
} else {
|
||||
@@ -174,8 +225,16 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
|
||||
|
||||
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 env = extractEnv(attrs, structuredAttrs, ignoreNulls, collectedContext);
|
||||
const env = extractEnv(attrs, structuredAttrs, ignoreNulls, collectedContext, drvName);
|
||||
|
||||
env.set("name", drvName);
|
||||
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`);
|
||||
}
|
||||
|
||||
const result: NixAttrs = {
|
||||
type: "derivation",
|
||||
drvPath,
|
||||
name: drvName,
|
||||
builder,
|
||||
system: platform,
|
||||
};
|
||||
const result: NixAttrs = {};
|
||||
|
||||
const drvPathContext = new Set<string>();
|
||||
addDrvDeepContext(drvPathContext, drvPath);
|
||||
result.drvPath = mkStringWithContext(drvPath, drvPathContext);
|
||||
|
||||
for (const [outputName, outputInfo] of outputInfos.entries()) {
|
||||
result[outputName] = outputInfo.path;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
const outputContext = new Set<string>();
|
||||
addBuiltContext(outputContext, drvPath, outputName);
|
||||
result[outputName] = mkStringWithContext(outputInfo.path, outputContext);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
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 {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert_eq!(attrs.get("type"), Some(&Value::String("derivation".into())));
|
||||
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"),
|
||||
}
|
||||
@@ -189,7 +190,7 @@ fn derivation_escaping_in_aterm() {
|
||||
|
||||
#[test]
|
||||
fn multi_output_two_outputs() {
|
||||
let result = eval(
|
||||
let drv = eval(
|
||||
r#"derivation {
|
||||
name = "multi";
|
||||
builder = "/bin/sh";
|
||||
@@ -198,39 +199,20 @@ fn multi_output_two_outputs() {
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
match drv {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("out"));
|
||||
assert!(attrs.contains_key("dev"));
|
||||
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") {
|
||||
assert_eq!(
|
||||
drv_path,
|
||||
"/nix/store/vmyjryfipkn9ss3ya23hk8p3m58l6dsl-multi.drv"
|
||||
);
|
||||
} else {
|
||||
panic!("drvPath should be a string");
|
||||
}
|
||||
|
||||
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");
|
||||
panic!("drvPath should be a string, got: {:?}", attrs.get("drvPath"));
|
||||
}
|
||||
|
||||
if let Some(Value::String(out_path)) = attrs.get("outPath") {
|
||||
@@ -238,7 +220,8 @@ fn multi_output_two_outputs() {
|
||||
out_path,
|
||||
"/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"),
|
||||
|
||||
Reference in New Issue
Block a user