optimize: avoid using #[serde] in ops

This commit is contained in:
2026-02-18 20:57:21 +08:00
parent 42031edac1
commit b424f60f9f
7 changed files with 194 additions and 173 deletions

View File

@@ -377,16 +377,16 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
const rustResult: { const rustResult: {
drvPath: string; drvPath: string;
outputs: [string, string][]; outputs: [string, string][];
} = Deno.core.ops.op_finalize_derivation({ } = Deno.core.ops.op_finalize_derivation(
name: drvName, drvName,
builder, builder,
platform, platform,
outputs, outputs,
args: drvArgs, drvArgs,
env: envEntries, envEntries,
context: contextArray, contextArray,
fixedOutput: fixedOutputInfo, fixedOutputInfo,
}); );
const result: NixAttrs = new Map(); const result: NixAttrs = new Map();

View File

@@ -30,9 +30,5 @@ export const convertHash = (args: NixValue): string => {
const toHashFormat = forceStringNoCtx(select(attrs, ["toHashFormat"])); const toHashFormat = forceStringNoCtx(select(attrs, ["toHashFormat"]));
return Deno.core.ops.op_convert_hash({ return Deno.core.ops.op_convert_hash(hash, hashAlgo, toHashFormat);
hash,
hashAlgo,
toHashFormat,
});
}; };

View File

@@ -49,8 +49,7 @@ export const importFunc = (path: NixValue): NixValue => {
return cached; return cached;
} }
const code = Deno.core.ops.op_import(pathStr); const result = Deno.core.ops.op_import(pathStr);
const result = Function(`return (${code})`)();
importCache.set(pathStr, result); importCache.set(pathStr, result);
return result; return result;
@@ -85,24 +84,24 @@ export const fetchClosure = (_args: NixValue): never => {
}; };
export interface FetchUrlResult { export interface FetchUrlResult {
store_path: string; storePath: string;
hash: string; hash: string;
} }
export interface FetchTarballResult { export interface FetchTarballResult {
store_path: string; storePath: string;
nar_hash: string; narHash: string;
} }
export interface FetchGitResult { export interface FetchGitResult {
out_path: string; outPath: string;
rev: string; rev: string;
short_rev: string; shortRev: string;
rev_count: number; revCount: number;
last_modified: number; lastModified: number;
last_modified_date: string; lastModifiedDate: string;
submodules: boolean; submodules: boolean;
nar_hash: string | null; narHash: string | null;
} }
const normalizeUrlInput = ( const normalizeUrlInput = (
@@ -154,16 +153,16 @@ export const fetchurl = (args: NixValue): NixString => {
executable ?? false, executable ?? false,
); );
const context: NixStringContext = new Set(); const context: NixStringContext = new Set();
addOpaqueContext(context, result.store_path); addOpaqueContext(context, result.storePath);
return mkStringWithContext(result.store_path, context); return mkStringWithContext(result.storePath, context);
}; };
export const fetchTarball = (args: NixValue): NixString => { export const fetchTarball = (args: NixValue): NixString => {
const { url, name, sha256 } = normalizeTarballInput(args); const { url, name, sha256 } = normalizeTarballInput(args);
const result: FetchTarballResult = Deno.core.ops.op_fetch_tarball(url, name ?? null, sha256 ?? null); const result: FetchTarballResult = Deno.core.ops.op_fetch_tarball(url, name ?? null, sha256 ?? null);
const context: NixStringContext = new Set(); const context: NixStringContext = new Set();
addOpaqueContext(context, result.store_path); addOpaqueContext(context, result.storePath);
return mkStringWithContext(result.store_path, context); return mkStringWithContext(result.storePath, context);
}; };
export const fetchGit = (args: NixValue): NixAttrs => { export const fetchGit = (args: NixValue): NixAttrs => {
@@ -173,16 +172,16 @@ export const fetchGit = (args: NixValue): NixAttrs => {
const url = coerceToString(forced, StringCoercionMode.Base, false, disposedContext); const url = coerceToString(forced, StringCoercionMode.Base, false, disposedContext);
const result = Deno.core.ops.op_fetch_git(url, null, null, false, false, false, null); 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.outPath);
return new Map<string, NixValue>([ return new Map<string, NixValue>([
["outPath", mkStringWithContext(result.out_path, outContext)], ["outPath", mkStringWithContext(result.outPath, outContext)],
["rev", result.rev], ["rev", result.rev],
["shortRev", result.short_rev], ["shortRev", result.shortRev],
["revCount", BigInt(result.rev_count)], ["revCount", BigInt(result.revCount)],
["lastModified", BigInt(result.last_modified)], ["lastModified", BigInt(result.lastModified)],
["lastModifiedDate", result.last_modified_date], ["lastModifiedDate", result.lastModifiedDate],
["submodules", result.submodules], ["submodules", result.submodules],
["narHash", result.nar_hash], ["narHash", result.narHash],
]); ]);
} }
const attrs = forceAttrs(args); const attrs = forceAttrs(args);
@@ -205,16 +204,16 @@ export const fetchGit = (args: NixValue): NixAttrs => {
); );
const outContext: NixStringContext = new Set(); const outContext: NixStringContext = new Set();
addOpaqueContext(outContext, result.out_path); addOpaqueContext(outContext, result.outPath);
return new Map<string, NixValue>([ return new Map<string, NixValue>([
["outPath", mkStringWithContext(result.out_path, outContext)], ["outPath", mkStringWithContext(result.outPath, outContext)],
["rev", result.rev], ["rev", result.rev],
["shortRev", result.short_rev], ["shortRev", result.shortRev],
["revCount", BigInt(result.rev_count)], ["revCount", BigInt(result.revCount)],
["lastModified", BigInt(result.last_modified)], ["lastModified", BigInt(result.lastModified)],
["lastModifiedDate", result.last_modified_date], ["lastModifiedDate", result.lastModifiedDate],
["submodules", result.submodules], ["submodules", result.submodules],
["narHash", result.nar_hash], ["narHash", result.narHash],
]); ]);
}; };
@@ -307,12 +306,7 @@ const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => {
export const readDir = (path: NixValue): NixAttrs => { export const readDir = (path: NixValue): NixAttrs => {
const pathStr = realisePath(path); const pathStr = realisePath(path);
const entries: Record<string, string> = Deno.core.ops.op_read_dir(pathStr); return Deno.core.ops.op_read_dir(pathStr);
const result: NixAttrs = new Map();
for (const [name, type] of Object.entries(entries)) {
result.set(name, type);
}
return result;
}; };
export const readFile = (path: NixValue): string => { export const readFile = (path: NixValue): string => {

View File

@@ -305,7 +305,7 @@ export const assert = (assertion: NixValue, expr: NixValue, assertionRaw: string
}; };
export const mkPos = (span: number): NixAttrs => { export const mkPos = (span: number): NixAttrs => {
return new Map(Object.entries(Deno.core.ops.op_decode_span(span))); return Deno.core.ops.op_decode_span(span);
}; };
interface WithScope { interface WithScope {

View File

@@ -15,7 +15,7 @@ import type {
import type { op } from "../operators"; import type { op } from "../operators";
import type { createThunk, force } from "../thunk"; import type { createThunk, force } from "../thunk";
import type { forceBool } from "../type-assert"; import type { forceBool } from "../type-assert";
import type { mkAttrs, mkFunction } from "../types"; import type { mkAttrs, mkFunction, NixAttrs } from "../types";
declare global { declare global {
var Nix: NixRuntime; var Nix: NixRuntime;
@@ -55,7 +55,7 @@ declare global {
function op_read_file(path: string): string; function op_read_file(path: string): string;
function op_read_file_type(path: string): string; function op_read_file_type(path: string): string;
function op_read_dir(path: string): Record<string, string>; function op_read_dir(path: string): Map<string, string>;
function op_path_exists(path: string): boolean; function op_path_exists(path: string): boolean;
function op_walk_dir(path: string): [string, string][]; function op_walk_dir(path: string): [string, string][];
@@ -81,11 +81,7 @@ declare global {
includePaths: string[], includePaths: string[],
): string; ): string;
function op_decode_span(span: number): { function op_decode_span(span: number): NixAttrs;
file: string | null;
line: number | null;
column: number | null;
};
function op_to_file(name: string, contents: string, references: string[]): string; function op_to_file(name: string, contents: string, references: string[]): string;
@@ -100,16 +96,16 @@ declare global {
function op_from_toml(toml: string): unknown; function op_from_toml(toml: string): unknown;
function op_to_xml(e: NixValue): [string, string[]]; function op_to_xml(e: NixValue): [string, string[]];
function op_finalize_derivation(input: { function op_finalize_derivation(
name: string; name: string,
builder: string; builder: string,
platform: string; platform: string,
outputs: string[]; outputs: string[],
args: string[]; args: string[],
env: [string, string][]; env: [string, string][],
context: string[]; context: string[],
fixedOutput: { hashAlgo: string; hash: string; hashMode: string } | null; fixedOutput: { hashAlgo: string; hash: string; hashMode: string } | null,
}): { drvPath: string; outputs: [string, string][] }; ): { drvPath: string; outputs: [string, string][] };
function op_fetch_url( function op_fetch_url(
url: string, url: string,

View File

@@ -1,8 +1,8 @@
use deno_core::OpState; use deno_core::OpState;
use deno_core::ToV8;
use deno_core::op2; use deno_core::op2;
use nix_compat::nixhash::HashAlgo; use nix_compat::nixhash::HashAlgo;
use nix_compat::nixhash::NixHash; use nix_compat::nixhash::NixHash;
use serde::Serialize;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use crate::runtime::OpStateExt; use crate::runtime::OpStateExt;
@@ -22,19 +22,19 @@ pub use metadata_cache::MetadataCache;
use crate::nar; use crate::nar;
use crate::runtime::NixRuntimeError; use crate::runtime::NixRuntimeError;
#[derive(Serialize)] #[derive(ToV8)]
pub struct FetchUrlResult { pub struct FetchUrlResult {
pub store_path: String, pub store_path: String,
pub hash: String, pub hash: String,
} }
#[derive(Serialize)] #[derive(ToV8)]
pub struct FetchTarballResult { pub struct FetchTarballResult {
pub store_path: String, pub store_path: String,
pub nar_hash: String, pub nar_hash: String,
} }
#[derive(Serialize)] #[derive(ToV8)]
pub struct FetchGitResult { pub struct FetchGitResult {
pub out_path: String, pub out_path: String,
pub rev: String, pub rev: String,
@@ -47,7 +47,6 @@ pub struct FetchGitResult {
} }
#[op2] #[op2]
#[serde]
pub fn op_fetch_url<Ctx: RuntimeContext>( pub fn op_fetch_url<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[string] url: String, #[string] url: String,
@@ -152,7 +151,6 @@ pub fn op_fetch_url<Ctx: RuntimeContext>(
} }
#[op2] #[op2]
#[serde]
pub fn op_fetch_tarball<Ctx: RuntimeContext>( pub fn op_fetch_tarball<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[string] url: String, #[string] url: String,
@@ -266,7 +264,6 @@ pub fn op_fetch_tarball<Ctx: RuntimeContext>(
} }
#[op2] #[op2]
#[serde]
pub fn op_fetch_git<Ctx: RuntimeContext>( pub fn op_fetch_git<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[string] url: String, #[string] url: String,

View File

@@ -1,9 +1,11 @@
use std::collections::BTreeMap;
use std::convert::Infallible;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use hashbrown::hash_map::{Entry, HashMap}; use hashbrown::{HashMap, HashSet, hash_map::Entry};
use deno_core::{FromV8, OpState, v8}; use deno_core::{FromV8, OpState, ToV8, v8};
use regex::Regex; use regex::Regex;
use rust_embed::Embed; use rust_embed::Embed;
@@ -36,6 +38,26 @@ impl RegexCache {
} }
} }
pub(super) struct Map<K, V>(HashMap<K, V>);
impl<'a, K, V> ToV8<'a> for Map<K, V>
where
K: ToV8<'a>,
K::Error: ToString,
V: ToV8<'a>,
V::Error: ToString,
{
type Error = NixRuntimeError;
fn to_v8<'i>(self, scope: &mut v8::PinScope<'a, 'i>) -> Result<v8::Local<'a, v8::Value>> {
let map = v8::Map::new(scope);
for (k, v) in self.0 {
let k = k.to_v8(scope).map_err(|err| err.to_string())?;
let v = v.to_v8(scope).map_err(|err| err.to_string())?;
map.set(scope, k, v).ok_or("Failed to set V8 Map KV")?;
}
Ok(map.into())
}
}
#[derive(Embed)] #[derive(Embed)]
#[folder = "src/runtime/corepkgs"] #[folder = "src/runtime/corepkgs"]
pub(crate) struct CorePkgs; pub(crate) struct CorePkgs;
@@ -93,7 +115,7 @@ pub(super) fn op_import<Ctx: RuntimeContext>(
pub(super) fn op_scoped_import<Ctx: RuntimeContext>( pub(super) fn op_scoped_import<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
#[serde] scope: Vec<String>, #[scoped] scope: Vec<String>,
) -> Result<String> { ) -> Result<String> {
let _span = tracing::info_span!("op_scoped_import", path = %path).entered(); let _span = tracing::info_span!("op_scoped_import", path = %path).entered();
let ctx: &mut Ctx = state.get_ctx_mut(); let ctx: &mut Ctx = state.get_ctx_mut();
@@ -161,10 +183,7 @@ pub(super) fn op_read_file_type(#[string] path: String) -> Result<String> {
} }
#[deno_core::op2] #[deno_core::op2]
#[serde] pub(super) fn op_read_dir(#[string] path: String) -> Result<Map<String, &'static str>> {
pub(super) fn op_read_dir(
#[string] path: String,
) -> Result<std::collections::HashMap<String, String>> {
let path = Path::new(&path); let path = Path::new(&path);
if !path.is_dir() { if !path.is_dir() {
@@ -174,7 +193,7 @@ pub(super) fn op_read_dir(
let entries = std::fs::read_dir(path) let entries = std::fs::read_dir(path)
.map_err(|e| format!("Failed to read directory {}: {}", path.display(), e))?; .map_err(|e| format!("Failed to read directory {}: {}", path.display(), e))?;
let mut result = std::collections::HashMap::new(); let mut result = HashMap::new();
for entry in entries { for entry in entries {
let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?; let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?;
@@ -198,10 +217,10 @@ pub(super) fn op_read_dir(
"unknown" "unknown"
}; };
result.insert(file_name, type_str.to_string()); result.insert(file_name, type_str);
} }
Ok(result) Ok(Map(result))
} }
#[deno_core::op2] #[deno_core::op2]
@@ -255,12 +274,28 @@ pub(super) fn op_make_placeholder(#[string] output: String) -> String {
format!("/{}", encoded) format!("/{}", encoded)
} }
enum StringOrU32 {
String(String),
U32(u32),
}
impl<'a> ToV8<'a> for StringOrU32 {
type Error = Infallible;
fn to_v8<'i>(
self,
scope: &mut v8::PinScope<'a, 'i>,
) -> std::result::Result<v8::Local<'a, v8::Value>, Self::Error> {
match self {
Self::String(x) => x.to_v8(scope),
Self::U32(x) => x.to_v8(scope),
}
}
}
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_decode_span<Ctx: RuntimeContext>( pub(super) fn op_decode_span<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[smi] span_id: u32, #[smi] span_id: u32,
) -> Result<serde_json::Value> { ) -> Map<&'static str, StringOrU32> {
let ctx: &Ctx = state.get_ctx(); let ctx: &Ctx = state.get_ctx();
let (source_id, range) = ctx.get_span(span_id as usize); let (source_id, range) = ctx.get_span(span_id as usize);
let source = ctx.get_source(source_id); let source = ctx.get_source(source_id);
@@ -268,11 +303,11 @@ pub(super) fn op_decode_span<Ctx: RuntimeContext>(
let (line, column) = byte_offset_to_line_col(&source.src, start as usize); let (line, column) = byte_offset_to_line_col(&source.src, start as usize);
Ok(serde_json::json!({ Map(HashMap::from([
"file": source.get_name(), ("file", StringOrU32::String(source.get_name())),
"line": line, ("line", StringOrU32::U32(line)),
"column": column ("column", StringOrU32::U32(column)),
})) ]))
} }
fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) { fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) {
@@ -294,14 +329,18 @@ fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) {
(line, col) (line, col)
} }
#[derive(serde::Serialize)] mod private {
use deno_core::ToV8;
#[derive(ToV8)]
pub(super) struct ParsedHash { pub(super) struct ParsedHash {
hex: String, pub(super) hex: String,
algo: String, pub(super) algo: String,
} }
}
use private::*;
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_parse_hash( pub(super) fn op_parse_hash(
#[string] hash_str: String, #[string] hash_str: String,
#[string] algo: Option<String>, #[string] algo: Option<String>,
@@ -433,7 +472,7 @@ pub(super) fn op_to_file<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[string] name: String, #[string] name: String,
#[string] contents: String, #[string] contents: String,
#[serde] references: Vec<String>, #[scoped] references: Vec<String>,
) -> Result<String> { ) -> Result<String> {
let ctx: &Ctx = state.get_ctx(); let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store(); let store = ctx.get_store();
@@ -487,7 +526,6 @@ pub(super) fn op_get_env(#[string] key: String) -> Result<String> {
} }
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_walk_dir(#[string] path: String) -> Result<Vec<(String, String)>> { pub(super) fn op_walk_dir(#[string] path: String) -> Result<Vec<(String, String)>> {
fn walk_recursive( fn walk_recursive(
base: &Path, base: &Path,
@@ -549,7 +587,7 @@ pub(super) fn op_add_filtered_path<Ctx: RuntimeContext>(
#[string] name: Option<String>, #[string] name: Option<String>,
recursive: bool, recursive: bool,
#[string] sha256: Option<String>, #[string] sha256: Option<String>,
#[serde] include_paths: Vec<String>, #[scoped] include_paths: Vec<String>,
) -> Result<String> { ) -> Result<String> {
use nix_compat::nixhash::{HashAlgo, NixHash}; use nix_compat::nixhash::{HashAlgo, NixHash};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
@@ -648,7 +686,6 @@ pub(super) fn op_add_filtered_path<Ctx: RuntimeContext>(
} }
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_match( pub(super) fn op_match(
state: &mut OpState, state: &mut OpState,
#[string] regex: String, #[string] regex: String,
@@ -673,7 +710,6 @@ pub(super) fn op_match(
} }
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_split( pub(super) fn op_split(
state: &mut OpState, state: &mut OpState,
#[string] regex: String, #[string] regex: String,
@@ -709,13 +745,30 @@ pub(super) fn op_split(
Ok(ret) Ok(ret)
} }
#[derive(serde::Serialize)]
#[serde(untagged)]
pub(super) enum SplitResult { pub(super) enum SplitResult {
Text(String), Text(String),
Captures(Vec<Option<String>>), Captures(Vec<Option<String>>),
} }
impl<'a> ToV8<'a> for SplitResult {
type Error = Infallible;
fn to_v8<'i>(
self,
scope: &mut v8::PinScope<'a, 'i>,
) -> std::result::Result<v8::Local<'a, v8::Value>, Self::Error> {
Ok(match self {
Self::Text(text) => {
let Ok(value) = text.to_v8(scope);
value
}
Self::Captures(captures) => {
let Ok(value) = captures.to_v8(scope);
value
}
})
}
}
pub(super) enum NixJsonValue { pub(super) enum NixJsonValue {
Null, Null,
Bool(bool), Bool(bool),
@@ -836,34 +889,24 @@ pub(super) fn op_from_toml(#[string] toml_str: String) -> Result<NixJsonValue> {
toml_to_nix(parsed) toml_to_nix(parsed)
} }
#[derive(serde::Deserialize)] mod scope {
use deno_core::{FromV8, ToV8};
#[derive(FromV8)]
pub(super) struct FixedOutputInput { pub(super) struct FixedOutputInput {
#[serde(rename = "hashAlgo")] pub(super) hash_algo: String,
hash_algo: String, pub(super) hash: String,
hash: String, pub(super) hash_mode: String,
#[serde(rename = "hashMode")]
hash_mode: String,
} }
#[derive(serde::Deserialize)] #[derive(ToV8)]
pub(super) struct FinalizeDerivationInput {
name: String,
builder: String,
platform: String,
outputs: Vec<String>,
args: Vec<String>,
env: Vec<(String, String)>,
context: Vec<String>,
#[serde(rename = "fixedOutput")]
fixed_output: Option<FixedOutputInput>,
}
#[derive(serde::Serialize)]
pub(super) struct FinalizeDerivationOutput { pub(super) struct FinalizeDerivationOutput {
#[serde(rename = "drvPath")] // renamed to `drvPath` automatically
drv_path: String, pub(super) drv_path: String,
outputs: Vec<(String, String)>, pub(super) outputs: Vec<(String, String)>,
} }
}
use scope::*;
fn output_path_name(drv_name: &str, output: &str) -> String { fn output_path_name(drv_name: &str, output: &str) -> String {
if output == "out" { if output == "out" {
@@ -874,10 +917,16 @@ fn output_path_name(drv_name: &str, output: &str) -> String {
} }
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>( pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
state: &mut OpState, state: &mut OpState,
#[serde] input: FinalizeDerivationInput, #[string] name: String,
#[string] builder: String,
#[string] platform: String,
#[scoped] outputs: Vec<String>,
#[scoped] args: Vec<String>,
#[scoped] env: Vec<(String, String)>,
#[scoped] context: Vec<String>,
#[scoped] fixed_output: Option<FixedOutputInput>,
) -> Result<FinalizeDerivationOutput> { ) -> Result<FinalizeDerivationOutput> {
use crate::derivation::{DerivationData, OutputInfo}; use crate::derivation::{DerivationData, OutputInfo};
use crate::string_context::extract_input_drvs_and_srcs; use crate::string_context::extract_input_drvs_and_srcs;
@@ -887,15 +936,15 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
let store_dir = store.get_store_dir().to_string(); let store_dir = store.get_store_dir().to_string();
let (input_drvs, input_srcs) = let (input_drvs, input_srcs) =
extract_input_drvs_and_srcs(&input.context).map_err(NixRuntimeError::from)?; extract_input_drvs_and_srcs(&context).map_err(NixRuntimeError::from)?;
let env: std::collections::BTreeMap<String, String> = input.env.into_iter().collect(); let env: BTreeMap<String, String> = env.into_iter().collect();
let drv_path; let drv_path;
let output_paths: Vec<(String, String)>; let output_paths: Vec<(String, String)>;
if let Some(fixed) = &input.fixed_output { if let Some(fixed) = &fixed_output {
let path_name = output_path_name(&input.name, "out"); let path_name = output_path_name(&name, "out");
let out_path = crate::runtime::ops::op_make_fixed_output_path_impl( let out_path = crate::runtime::ops::op_make_fixed_output_path_impl(
&store_dir, &store_dir,
&fixed.hash_algo, &fixed.hash_algo,
@@ -910,7 +959,7 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
"" ""
}; };
let mut final_outputs = std::collections::BTreeMap::new(); let mut final_outputs = BTreeMap::new();
final_outputs.insert( final_outputs.insert(
"out".to_string(), "out".to_string(),
OutputInfo { OutputInfo {
@@ -924,13 +973,13 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
final_env.insert("out".to_string(), out_path.clone()); final_env.insert("out".to_string(), out_path.clone());
let drv = DerivationData { let drv = DerivationData {
name: input.name.clone(), name: name.clone(),
outputs: final_outputs, outputs: final_outputs,
input_drvs: input_drvs.clone(), input_drvs: input_drvs.clone(),
input_srcs: input_srcs.clone(), input_srcs: input_srcs.clone(),
platform: input.platform, platform,
builder: input.builder, builder,
args: input.args, args,
env: final_env, env: final_env,
}; };
@@ -938,7 +987,7 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
let references = drv.collect_references(); let references = drv.collect_references();
drv_path = store drv_path = store
.add_text_to_store(&format!("{}.drv", input.name), &final_aterm, references) .add_text_to_store(&format!("{}.drv", name), &final_aterm, references)
.map_err(|e| NixRuntimeError::from(format!("failed to write derivation: {}", e)))?; .map_err(|e| NixRuntimeError::from(format!("failed to write derivation: {}", e)))?;
let fixed_hash_fingerprint = format!( let fixed_hash_fingerprint = format!(
@@ -952,8 +1001,7 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
output_paths = vec![("out".to_string(), out_path)]; output_paths = vec![("out".to_string(), out_path)];
} else { } else {
let masked_outputs: std::collections::BTreeMap<String, OutputInfo> = input let masked_outputs: std::collections::BTreeMap<String, OutputInfo> = outputs
.outputs
.iter() .iter()
.map(|o| { .map(|o| {
( (
@@ -968,18 +1016,18 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
.collect(); .collect();
let mut masked_env = env.clone(); let mut masked_env = env.clone();
for output in &input.outputs { for output in &outputs {
masked_env.insert(output.clone(), String::new()); masked_env.insert(output.clone(), String::new());
} }
let masked_drv = DerivationData { let masked_drv = DerivationData {
name: input.name.clone(), name: name.clone(),
outputs: masked_outputs, outputs: masked_outputs,
input_drvs: input_drvs.clone(), input_drvs: input_drvs.clone(),
input_srcs: input_srcs.clone(), input_srcs: input_srcs.clone(),
platform: input.platform.clone(), platform: platform.clone(),
builder: input.builder.clone(), builder: builder.clone(),
args: input.args.clone(), args: args.clone(),
env: masked_env, env: masked_env,
}; };
@@ -1007,8 +1055,8 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
let mut final_env = env; let mut final_env = env;
let mut result_output_paths = Vec::new(); let mut result_output_paths = Vec::new();
for output_name in &input.outputs { for output_name in &outputs {
let path_name = output_path_name(&input.name, output_name); let path_name = output_path_name(&name, output_name);
let out_path = crate::nix_utils::make_store_path( let out_path = crate::nix_utils::make_store_path(
&store_dir, &store_dir,
&format!("output:{}", output_name), &format!("output:{}", output_name),
@@ -1028,13 +1076,13 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
} }
let final_drv = DerivationData { let final_drv = DerivationData {
name: input.name, name,
outputs: final_outputs, outputs: final_outputs,
input_drvs, input_drvs,
input_srcs, input_srcs,
platform: input.platform, platform,
builder: input.builder, builder,
args: input.args, args,
env: final_env, env: final_env,
}; };
@@ -1161,21 +1209,21 @@ pub(super) fn op_hash_file(#[string] algo: String, #[string] path: String) -> Re
#[deno_core::op2] #[deno_core::op2]
#[string] #[string]
pub(super) fn op_convert_hash(#[serde] input: ConvertHashInput) -> Result<String> { pub(super) fn op_convert_hash(
#[string] hash: &str,
#[string] algo: Option<String>,
#[string] format: &str,
) -> Result<String> {
use nix_compat::nixhash::{HashAlgo, NixHash}; use nix_compat::nixhash::{HashAlgo, NixHash};
let hash_algo = input let hash_algo = algo.as_deref().and_then(|a| HashAlgo::from_str(a).ok());
.hash_algo
.as_deref()
.and_then(|a| HashAlgo::from_str(a).ok());
let hash = NixHash::from_str(&input.hash, hash_algo).map_err(|e| { let hash = NixHash::from_str(hash, hash_algo)
NixRuntimeError::from(format!("cannot convert hash '{}': {}", input.hash, e)) .map_err(|e| NixRuntimeError::from(format!("cannot convert hash '{}': {}", hash, e)))?;
})?;
let bytes = hash.digest_as_bytes(); let bytes = hash.digest_as_bytes();
match input.to_format.as_str() { match format {
"base16" => Ok(hex::encode(bytes)), "base16" => Ok(hex::encode(bytes)),
"nix32" | "base32" => Ok(nix_compat::nixbase32::encode(bytes)), "nix32" | "base32" => Ok(nix_compat::nixbase32::encode(bytes)),
"base64" => { "base64" => {
@@ -1188,20 +1236,11 @@ pub(super) fn op_convert_hash(#[serde] input: ConvertHashInput) -> Result<String
})), })),
_ => Err(NixRuntimeError::from(format!( _ => Err(NixRuntimeError::from(format!(
"unknown hash format '{}'", "unknown hash format '{}'",
input.to_format format
))), ))),
} }
} }
#[derive(serde::Deserialize)]
pub(super) struct ConvertHashInput {
hash: String,
#[serde(rename = "hashAlgo")]
hash_algo: Option<String>,
#[serde(rename = "toHashFormat")]
to_format: String,
}
struct XmlCtx<'s> { struct XmlCtx<'s> {
force_fn: v8::Local<'s, v8::Function>, force_fn: v8::Local<'s, v8::Function>,
is_thunk: v8::Local<'s, v8::Symbol>, is_thunk: v8::Local<'s, v8::Symbol>,
@@ -1243,7 +1282,7 @@ impl<'s> XmlCtx<'s> {
struct XmlWriter { struct XmlWriter {
buf: String, buf: String,
context: Vec<String>, context: Vec<String>,
drvs_seen: hashbrown::HashSet<String>, drvs_seen: HashSet<String>,
} }
impl XmlWriter { impl XmlWriter {
@@ -1251,7 +1290,7 @@ impl XmlWriter {
Self { Self {
buf: String::with_capacity(4096), buf: String::with_capacity(4096),
context: Vec::new(), context: Vec::new(),
drvs_seen: hashbrown::HashSet::new(), drvs_seen: HashSet::new(),
} }
} }
@@ -1742,7 +1781,6 @@ impl<'a> FromV8<'a> for ToXmlResult {
} }
#[deno_core::op2] #[deno_core::op2]
#[serde]
pub(super) fn op_to_xml(#[scoped] value: ToXmlResult) -> (String, Vec<String>) { pub(super) fn op_to_xml(#[scoped] value: ToXmlResult) -> (String, Vec<String>) {
(value.xml, value.context) (value.xml, value.context)
} }