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