fix: derivation (WIP)

This commit is contained in:
2026-02-11 23:55:24 +08:00
parent 249eaf3c11
commit a8f1c81b60
12 changed files with 89 additions and 49 deletions

View File

@@ -127,12 +127,7 @@ const structuredAttrsExcludedKeys = new Set([
]);
const specialAttrs = new Set([
"name",
"builder",
"system",
"args",
"outputs",
"__structuredAttrs",
"__ignoreNulls",
"__contentAddressed",
"__impure",
@@ -300,14 +295,6 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
const drvArgs = extractArgs(attrs, collectedContext);
const env = extractEnv(attrs, structuredAttrs, ignoreNulls, collectedContext, drvName);
if (!structuredAttrs) {
env.set("name", drvName);
env.set("builder", builder);
env.set("system", platform);
if (outputs.length > 1 || outputs[0] !== "out") {
env.set("outputs", outputs.join(" "));
}
}
const { inputDrvs, inputSrcs } = extractInputDrvsAndSrcs(collectedContext);

View File

@@ -193,7 +193,7 @@ export const builtins: any = {
warn: mkPrimop(functional.warn, "warn", 2),
break: mkPrimop(functional.breakFunc, "break", 1),
derivation: mkPrimop(derivation.derivation, "derivation", 1),
derivation: undefined as any,
derivationStrict: mkPrimop(derivation.derivationStrict, "derivationStrict", 1),
import: mkPrimop(io.importFunc, "import", 1),

View File

@@ -6,7 +6,7 @@
import type { NixValue, NixThunkInterface, NixStrictValue } from "./types";
import { HAS_CONTEXT } from "./string-context";
import { IS_PATH } from "./types";
import { isAttrs } from "./builtins/type-check";
import { isAttrs, isList } from "./builtins/type-check";
/**
* Symbol used to mark objects as thunks
@@ -165,7 +165,9 @@ export const forceDeep = (value: NixValue, seen: WeakSet<object> = new WeakSet()
}
return CYCLE_MARKER;
}
seen.add(forced);
if (isAttrs(forced) || isList(forced)) {
seen.add(forced);
}
if (HAS_CONTEXT in forced || IS_PATH in forced) {
return forced;

View File

@@ -41,7 +41,22 @@ impl Context {
let ctx = Ctx::new()?;
let runtime = Runtime::new()?;
Ok(Self { ctx, runtime })
let mut context = Self { ctx, runtime };
context.init_derivation()?;
Ok(context)
}
fn init_derivation(&mut self) -> Result<()> {
const DERIVATION_NIX: &str = include_str!("runtime/corepkgs/derivation.nix");
let source = Source::new_virtual(
"<nix/derivation-internal.nix>".into(),
DERIVATION_NIX.to_string(),
);
let code = self.ctx.compile(source, None)?;
self.runtime
.eval(format!("Nix.builtins.derivation = {}", code), &mut self.ctx)?;
Ok(())
}
eval!(eval, "Nix.force({})");

View File

@@ -21,6 +21,8 @@ pub enum SourceType {
Repl(Arc<PathBuf>),
/// file
File(Arc<PathBuf>),
/// virtual (name, no path)
Virtual(Arc<str>),
}
#[derive(Clone, Debug)]
@@ -71,6 +73,13 @@ impl Source {
})
}
pub fn new_virtual(name: Arc<str>, src: String) -> Self {
Self {
ty: SourceType::Virtual(name),
src: src.into(),
}
}
pub fn get_dir(&self) -> &Path {
use SourceType::*;
match &self.ty {
@@ -79,6 +88,7 @@ impl Source {
.as_path()
.parent()
.expect("source file must have a parent dir"),
Virtual(_) => Path::new("/"),
}
}
@@ -87,6 +97,7 @@ impl Source {
SourceType::Eval(_) => "«eval»".into(),
SourceType::Repl(_) => "«repl»".into(),
SourceType::File(path) => path.as_os_str().to_string_lossy().to_string(),
SourceType::Virtual(name) => name.to_string(),
}
}
}

View File

@@ -264,14 +264,15 @@ pub fn op_fetch_tarball<Ctx: RuntimeContext>(
);
if let Some(ref expected) = expected_sha256
&& nar_hash != *expected {
return Err(NixRuntimeError::from(format!(
"NAR hash mismatch for '{}': expected {}, got {}",
url,
expected_hex.expect("must be Some"),
nar_hash_hex
)));
}
&& nar_hash != *expected
{
return Err(NixRuntimeError::from(format!(
"NAR hash mismatch for '{}': expected {}, got {}",
url,
expected_hex.expect("must be Some"),
nar_hash_hex
)));
}
info!("Adding to store");
let ctx: &Ctx = state.get_ctx();

View File

@@ -31,8 +31,10 @@ pub fn fetch_git(
let temp_dir = tempfile::tempdir()?;
let checkout_dir = checkout_rev_to_temp(&bare_repo, &target_rev, submodules, temp_dir.path())?;
let nar_hash = hex::encode(crate::nar::compute_nar_hash(&checkout_dir)
.map_err(|e| GitError::NarHashError(e.to_string()))?);
let nar_hash = hex::encode(
crate::nar::compute_nar_hash(&checkout_dir)
.map_err(|e| GitError::NarHashError(e.to_string()))?,
);
let store_path = store
.add_to_store_from_path(name, &checkout_dir, vec![])

View File

@@ -10,9 +10,9 @@ mod downgrade;
mod fetcher;
mod ir;
mod nar;
mod nix_utils;
mod runtime;
mod store;
mod nix_utils;
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

View File

@@ -0,0 +1,31 @@
drvAttrs@{
outputs ? [ "out" ],
...
}:
let
strict = derivationStrict drvAttrs;
commonAttrs =
drvAttrs
// (builtins.listToAttrs outputsList)
// {
all = map (x: x.value) outputsList;
inherit drvAttrs;
};
outputToAttrListElement = outputName: {
name = outputName;
value = commonAttrs // {
outPath = builtins.getAttr outputName strict;
drvPath = strict.drvPath;
type = "derivation";
inherit outputName;
};
};
outputsList = map outputToAttrListElement outputs;
in
(builtins.head outputsList).value

View File

@@ -1,6 +1,5 @@
use std::path::{Component, Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
use hashbrown::hash_map::{Entry, HashMap};
@@ -53,12 +52,12 @@ pub(super) fn op_import<Ctx: RuntimeContext>(
let corepkg_name = &path[5..path.len() - 1];
if let Some(file) = CorePkgs::get(corepkg_name) {
tracing::info!("Importing corepkg: {}", corepkg_name);
let source = Source {
ty: crate::error::SourceType::Eval(Arc::new(ctx.get_current_dir().to_path_buf())),
src: str::from_utf8(&file.data)
let source = Source::new_virtual(
path.into(),
str::from_utf8(&file.data)
.expect("corrupted corepkgs file")
.into(),
};
);
ctx.add_source(source.clone());
return Ok(ctx.compile(source).map_err(|err| err.to_string())?);
} else {
@@ -445,9 +444,8 @@ pub(super) fn op_add_path<Ctx: RuntimeContext>(
};
if let Some(ref expected_hash) = sha256 {
let expected_hex =
NixHash::from_str(expected_hash, Some(HashAlgo::Sha256))
.map_err(|err| err.to_string())?;
let expected_hex = NixHash::from_str(expected_hash, Some(HashAlgo::Sha256))
.map_err(|err| err.to_string())?;
if computed_hash != expected_hex.digest_as_bytes() {
return Err(NixRuntimeError::from(format!(
"hash mismatch for path '{}': expected {}, got {}",
@@ -960,9 +958,8 @@ pub(super) fn op_add_filtered_path<Ctx: RuntimeContext>(
};
if let Some(ref expected_hash) = sha256 {
let expected_hex =
NixHash::from_str(expected_hash, Some(HashAlgo::Sha256))
.map_err(|err| err.to_string())?;
let expected_hex = NixHash::from_str(expected_hash, Some(HashAlgo::Sha256))
.map_err(|err| err.to_string())?;
if computed_hash != expected_hex.digest_as_bytes() {
return Err(NixRuntimeError::from(format!(
"hash mismatch for path '{}': expected {}, got {}",

View File

@@ -11,9 +11,7 @@ impl StoreConfig {
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("/nix/var/nix/daemon-socket/socket"));
Self {
daemon_socket,
}
Self { daemon_socket }
}
}

View File

@@ -8,13 +8,13 @@ use nix_compat::wire::ProtocolVersion;
use nix_compat::wire::de::{NixRead, NixReader};
use nix_compat::wire::ser::{NixSerialize, NixWrite, NixWriter, NixWriterBuilder};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use thiserror::Error;
use tokio::io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf, split};
use tokio::net::UnixStream;
use tokio::sync::Mutex;
use thiserror::Error;
use crate::error::{Error, Result};
use super::Store;
use crate::error::{Error, Result};
pub struct DaemonStore {
runtime: tokio::runtime::Runtime,
@@ -569,11 +569,7 @@ impl NixDaemonClient {
traces.push(trace_hint);
}
Ok(NixDaemonError {
level,
msg,
traces,
})
Ok(NixDaemonError { level, msg, traces })
}
/// Check if a path is valid in the store