feat: implement realisePath
This commit is contained in:
@@ -86,7 +86,7 @@ export const coerceToString = (
|
||||
value: NixValue,
|
||||
mode: StringCoercionMode,
|
||||
copyToStore: boolean = false,
|
||||
outContext?: NixStringContext,
|
||||
outContext: NixStringContext,
|
||||
): string => {
|
||||
const v = force(value);
|
||||
|
||||
@@ -96,10 +96,8 @@ export const coerceToString = (
|
||||
}
|
||||
|
||||
if (isStringWithContext(v)) {
|
||||
if (outContext) {
|
||||
for (const elem of v.context) {
|
||||
outContext.add(elem);
|
||||
}
|
||||
for (const elem of v.context) {
|
||||
outContext.add(elem);
|
||||
}
|
||||
return v.value;
|
||||
}
|
||||
@@ -109,9 +107,7 @@ export const coerceToString = (
|
||||
if (copyToStore) {
|
||||
const pathStr = v.value;
|
||||
const storePath = Deno.core.ops.op_copy_path_to_store(pathStr);
|
||||
if (outContext) {
|
||||
outContext.add(storePath);
|
||||
}
|
||||
outContext.add(storePath);
|
||||
return storePath;
|
||||
}
|
||||
return v.value;
|
||||
@@ -253,7 +249,7 @@ export const coerceToStringWithContext = (
|
||||
* - Returns the path string (not a NixPath object)
|
||||
* - Preserves string context if present
|
||||
*/
|
||||
export const coerceToPath = (value: NixValue, outContext?: NixStringContext): string => {
|
||||
export const coerceToPath = (value: NixValue, outContext: NixStringContext): string => {
|
||||
const forced = force(value);
|
||||
|
||||
if (isPath(forced)) {
|
||||
@@ -347,10 +343,8 @@ export const nixValueToJson = (
|
||||
return result;
|
||||
}
|
||||
if (isStringWithContext(result)) {
|
||||
if (outContext) {
|
||||
for (const elem of result.context) {
|
||||
outContext.add(elem);
|
||||
}
|
||||
for (const elem of result.context) {
|
||||
outContext.add(elem);
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export const abort = (s: NixValue): never => {
|
||||
};
|
||||
|
||||
export const throwFunc = (s: NixValue): never => {
|
||||
throw new CatchableError(coerceToString(s, StringCoercionMode.Base));
|
||||
throw new CatchableError(coerceToString(s, StringCoercionMode.Base, false, new Set()));
|
||||
};
|
||||
|
||||
export const trace =
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { forceStringNoCtx } from "../type-assert";
|
||||
import type { NixValue } from "../types";
|
||||
import { realisePath } from "./io";
|
||||
|
||||
export const hashFile =
|
||||
(type: NixValue) =>
|
||||
(_p: NixValue): never => {
|
||||
(p: NixValue): string => {
|
||||
const _ty = forceStringNoCtx(type);
|
||||
const _pathStr = realisePath(p);
|
||||
throw new Error("Not implemented: hashFile");
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getPathValue } from "../path";
|
||||
import type { NixStringContext, StringWithContext } from "../string-context";
|
||||
import { addOpaqueContext, mkStringWithContext } from "../string-context";
|
||||
import { addOpaqueContext, decodeContextElem, mkStringWithContext } from "../string-context";
|
||||
import { force } from "../thunk";
|
||||
import {
|
||||
forceAttrs,
|
||||
@@ -14,32 +14,40 @@ import type { NixAttrs, NixPath, NixString, NixValue } from "../types";
|
||||
import { CatchableError, IS_PATH, isNixPath } from "../types";
|
||||
import { coerceToPath, coerceToString, StringCoercionMode } from "./conversion";
|
||||
import { baseNameOf } from "./path";
|
||||
import { isAttrs, isPath } from "./type-check";
|
||||
import { isAttrs, isPath, isString } from "./type-check";
|
||||
|
||||
const importCache = new Map<string, NixValue>();
|
||||
|
||||
export const importFunc = (path: NixValue): NixValue => {
|
||||
const context: NixStringContext = new Set();
|
||||
const pathStr = coerceToPath(path, context);
|
||||
|
||||
// FIXME: Context collected but not yet propagated to build system
|
||||
// This means derivation dependencies from imported paths are not
|
||||
// currently tracked. This will cause issues when:
|
||||
// 1. Importing from derivation outputs: import "${drv}/file.nix"
|
||||
// 2. Building packages that depend on imported configurations
|
||||
if (context.size > 0) {
|
||||
console.warn(
|
||||
`[WARN] import: Path has string context which is not yet fully tracked.
|
||||
Dependency tracking for imported derivations may be incomplete.`,
|
||||
);
|
||||
const realiseContext = (context: NixStringContext): void => {
|
||||
for (const encoded of context) {
|
||||
const elem = decodeContextElem(encoded);
|
||||
if (elem.type === "built") {
|
||||
throw new Error(
|
||||
`cannot build derivation '${elem.drvPath}' during evaluation because import-from-derivation is not supported`,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const realisePath = (value: NixValue): string => {
|
||||
const context: NixStringContext = new Set();
|
||||
const pathStr = coerceToPath(value, context);
|
||||
|
||||
if (context.size > 0) {
|
||||
realiseContext(context);
|
||||
}
|
||||
|
||||
return pathStr;
|
||||
};
|
||||
|
||||
export const importFunc = (path: NixValue): NixValue => {
|
||||
const pathStr = realisePath(path);
|
||||
|
||||
const cached = importCache.get(pathStr);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// Call Rust op - returns JS code string
|
||||
const code = Deno.core.ops.op_import(pathStr);
|
||||
const result = Function(`return (${code})`)();
|
||||
|
||||
@@ -53,15 +61,7 @@ export const scopedImport =
|
||||
const scopeAttrs = forceAttrs(scope);
|
||||
const scopeKeys = Object.keys(scopeAttrs);
|
||||
|
||||
const context: NixStringContext = new Set();
|
||||
const pathStr = coerceToPath(path, context);
|
||||
|
||||
if (context.size > 0) {
|
||||
console.warn(
|
||||
`[WARN] scopedImport: Path has string context which is not yet fully tracked.
|
||||
Dependency tracking for imported derivations may be incomplete.`,
|
||||
);
|
||||
}
|
||||
const pathStr = realisePath(path);
|
||||
|
||||
const code = Deno.core.ops.op_scoped_import(pathStr, scopeKeys);
|
||||
|
||||
@@ -169,9 +169,10 @@ export const fetchTarball = (args: NixValue): NixString => {
|
||||
|
||||
export const fetchGit = (args: NixValue): NixAttrs => {
|
||||
const forced = force(args);
|
||||
if (typeof forced === "string" || isPath(forced)) {
|
||||
const path = coerceToPath(forced);
|
||||
const result: FetchGitResult = Deno.core.ops.op_fetch_git(path, null, null, false, false, false, null);
|
||||
const disposedContext: NixStringContext = new Set();
|
||||
if (isString(forced) || isPath(forced)) {
|
||||
const url = coerceToString(forced, StringCoercionMode.Base, false, disposedContext);
|
||||
const result = Deno.core.ops.op_fetch_git(url, null, null, false, false, false, null);
|
||||
const outContext: NixStringContext = new Set();
|
||||
addOpaqueContext(outContext, result.out_path);
|
||||
return {
|
||||
@@ -303,7 +304,7 @@ const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => {
|
||||
};
|
||||
|
||||
export const readDir = (path: NixValue): NixAttrs => {
|
||||
const pathStr = coerceToPath(path);
|
||||
const pathStr = realisePath(path);
|
||||
const entries: Record<string, string> = Deno.core.ops.op_read_dir(pathStr);
|
||||
const result: NixAttrs = {};
|
||||
for (const [name, type] of Object.entries(entries)) {
|
||||
@@ -313,18 +314,22 @@ export const readDir = (path: NixValue): NixAttrs => {
|
||||
};
|
||||
|
||||
export const readFile = (path: NixValue): string => {
|
||||
const pathStr = coerceToPath(path);
|
||||
const pathStr = realisePath(path);
|
||||
return Deno.core.ops.op_read_file(pathStr);
|
||||
};
|
||||
|
||||
export const readFileType = (path: NixValue): string => {
|
||||
const pathStr = coerceToPath(path);
|
||||
const pathStr = realisePath(path);
|
||||
return Deno.core.ops.op_read_file_type(pathStr);
|
||||
};
|
||||
|
||||
export const pathExists = (path: NixValue): boolean => {
|
||||
const pathStr = coerceToPath(path);
|
||||
return Deno.core.ops.op_path_exists(pathStr);
|
||||
try {
|
||||
const pathStr = realisePath(path);
|
||||
return Deno.core.ops.op_path_exists(pathStr);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@ import { mkPath } from "../path";
|
||||
import { mkStringWithContext, type NixStringContext } from "../string-context";
|
||||
import { force } from "../thunk";
|
||||
import type { NixPath, NixString, NixValue } from "../types";
|
||||
import { isNixPath, isStringWithContext } from "../types";
|
||||
import { isNixPath } from "../types";
|
||||
import { coerceToPath, coerceToString, StringCoercionMode } from "./conversion";
|
||||
|
||||
/**
|
||||
@@ -86,21 +86,8 @@ export const dirOf = (s: NixValue): NixPath | NixString => {
|
||||
}
|
||||
|
||||
// String input → string output
|
||||
const strValue: NixString = coerceToString(s, StringCoercionMode.Base, false) as NixString;
|
||||
|
||||
let pathStr: string;
|
||||
let hasContext = false;
|
||||
let originalContext: Set<string> | undefined;
|
||||
|
||||
if (typeof strValue === "string") {
|
||||
pathStr = strValue;
|
||||
} else if (isStringWithContext(strValue)) {
|
||||
pathStr = strValue.value;
|
||||
hasContext = strValue.context.size > 0;
|
||||
originalContext = strValue.context;
|
||||
} else {
|
||||
pathStr = strValue as string;
|
||||
}
|
||||
const outContext: NixStringContext = new Set();
|
||||
const pathStr = coerceToString(s, StringCoercionMode.Base, false, outContext);
|
||||
|
||||
const lastSlash = pathStr.lastIndexOf("/");
|
||||
|
||||
@@ -113,9 +100,8 @@ export const dirOf = (s: NixValue): NixPath | NixString => {
|
||||
|
||||
const result = pathStr.slice(0, lastSlash);
|
||||
|
||||
// Preserve string context if present
|
||||
if (hasContext && originalContext) {
|
||||
return mkStringWithContext(result, originalContext);
|
||||
if (outContext.size > 0) {
|
||||
return mkStringWithContext(result, outContext);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user