refactor: RuntimeContext

This commit is contained in:
2026-01-24 15:21:54 +08:00
parent f46ee9d48f
commit 10430e2006
8 changed files with 246 additions and 239 deletions

View File

@@ -316,8 +316,8 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Select {
.attrpath
.iter()
.map(|attr| match attr {
Attr::Str(sym) => ctx.get_sym(*sym).escape_quote(),
Attr::Dynamic(expr_id) => ctx.get_ir(*expr_id).compile(ctx),
Attr::Str(sym, _) => ctx.get_sym(*sym).escape_quote(),
Attr::Dynamic(expr_id, _) => ctx.get_ir(*expr_id).compile(ctx),
})
.join(",");
let span_str = encode_span(self.span, ctx);
@@ -431,8 +431,8 @@ impl<Ctx: CodegenContext> Compile<Ctx> for HasAttr {
.rhs
.iter()
.map(|attr| match attr {
Attr::Str(sym) => ctx.get_sym(*sym).escape_quote(),
Attr::Dynamic(expr_id) => ctx.get_ir(*expr_id).compile(ctx),
Attr::Str(sym, _) => ctx.get_sym(*sym).escape_quote(),
Attr::Dynamic(expr_id, _) => ctx.get_ir(*expr_id).compile(ctx),
})
.join(",");
format!("Nix.hasAttr({lhs},[{attrpath}])")

View File

@@ -14,45 +14,8 @@ use crate::ir::{
Thunk, ToIr as _, synthetic_span,
};
use crate::runtime::{Runtime, RuntimeContext};
use crate::store::{StoreBackend, StoreConfig};
use crate::store::{Store, StoreBackend, StoreConfig};
use crate::value::Value;
use std::sync::Arc;
mod private {
use super::*;
use std::ptr::NonNull;
pub struct CtxPtr(NonNull<Ctx>);
impl CtxPtr {
pub fn new(ctx: &mut Ctx) -> Self {
unsafe { CtxPtr(NonNull::new_unchecked(ctx)) }
}
fn as_ref(&self) -> &Ctx {
// SAFETY: This is safe since inner `NonNull<Ctx>` is obtained from `&mut Ctx`
unsafe { self.0.as_ref() }
}
fn as_mut(&mut self) -> &mut Ctx {
// SAFETY: This is safe since inner `NonNull<Ctx>` is obtained from `&mut Ctx`
unsafe { self.0.as_mut() }
}
}
impl RuntimeContext for CtxPtr {
fn get_current_dir(&self) -> &Path {
self.as_ref().get_current_dir()
}
fn add_source(&mut self, source: Source) {
self.as_mut().sources.push(source);
}
fn compile_code(&mut self, source: Source) -> Result<String> {
self.as_mut().compile_code(source)
}
fn get_source(&self, id: usize) -> Source {
self.as_ref().get_source(id)
}
}
}
use private::CtxPtr;
#[derive(Debug)]
pub(crate) struct SccInfo {
@@ -62,7 +25,7 @@ pub(crate) struct SccInfo {
pub struct Context {
ctx: Ctx,
runtime: Runtime<CtxPtr>,
runtime: Runtime<Ctx>,
}
impl Context {
@@ -79,14 +42,9 @@ impl Context {
tracing::debug!("Compiling code");
let code = self.compile_code(source)?;
self.runtime
.op_state()
.borrow_mut()
.put(self.ctx.store.clone());
tracing::debug!("Executing JavaScript");
self.runtime
.eval(format!("Nix.force({code})"), CtxPtr::new(&mut self.ctx))
.eval(format!("Nix.force({code})"), &mut self.ctx)
}
pub fn compile_code(&mut self, source: Source) -> Result<String> {
@@ -95,7 +53,7 @@ impl Context {
#[allow(dead_code)]
pub(crate) fn eval_js(&mut self, code: String) -> Result<Value> {
self.runtime.eval(code, CtxPtr::new(&mut self.ctx))
self.runtime.eval(code, &mut self.ctx)
}
pub fn get_store_dir(&self) -> &str {
@@ -108,7 +66,7 @@ pub(crate) struct Ctx {
symbols: DefaultStringInterner,
global: NonNull<HashMap<SymId, ExprId>>,
sources: Vec<Source>,
store: Arc<StoreBackend>,
store: StoreBackend,
}
impl Ctx {
@@ -197,7 +155,7 @@ impl Ctx {
}
let config = StoreConfig::from_env();
let store = Arc::new(StoreBackend::new(config)?);
let store = StoreBackend::new(config)?;
Ok(Self {
symbols,
@@ -207,9 +165,7 @@ impl Ctx {
store,
})
}
}
impl Ctx {
pub(crate) fn downgrade_ctx<'a>(&'a mut self) -> DowngradeCtx<'a> {
let global_ref = unsafe { self.global.as_ref() };
DowngradeCtx::new(self, global_ref)
@@ -279,6 +235,24 @@ impl CodegenContext for Ctx {
}
}
impl RuntimeContext for Ctx {
fn get_current_dir(&self) -> &Path {
self.get_current_dir()
}
fn add_source(&mut self, source: Source) {
self.sources.push(source);
}
fn compile_code(&mut self, source: Source) -> Result<String> {
self.compile_code(source)
}
fn get_source(&self, id: usize) -> Source {
self.get_source(id)
}
fn get_store(&self) -> &dyn Store {
self.store.as_store()
}
}
struct DependencyTracker {
graph: DiGraphMap<ExprId, ()>,
current_binding: Option<ExprId>,
@@ -460,16 +434,18 @@ impl DowngradeContext for DowngradeCtx<'_> {
use crate::ir::{Attr, Select};
let select = Select {
expr: namespace,
attrpath: vec![Attr::Str(sym)],
attrpath: vec![Attr::Str(sym, synthetic_span())],
default: result, // Link to outer With or None
span,
};
result = Some(self.new_expr(select.to_ir()));
}
result.ok_or_else(|| {
Error::downgrade_error(format!("'{}' not found", self.get_sym(sym)))
.with_span(span)
.with_source(self.get_current_source())
Error::downgrade_error(
format!("'{}' not found", self.get_sym(sym)),
self.get_current_source(),
span,
)
})
}

View File

@@ -134,10 +134,10 @@ impl Error {
.into()
}
pub fn downgrade_error(msg: String) -> Box<Self> {
pub fn downgrade_error(msg: String, src: Source, span: rnix::TextRange) -> Box<Self> {
Error::DowngradeError {
src: None,
span: None,
src: Some(src.into()),
span: Some(text_range_to_source_span(span)),
message: msg,
}
.into()

View File

@@ -3,6 +3,9 @@ use deno_core::op2;
use serde::Serialize;
use tracing::{debug, info, warn};
use crate::runtime::OpStateExt;
use crate::runtime::RuntimeContext;
mod archive;
pub(crate) mod cache;
mod download;
@@ -53,16 +56,13 @@ pub struct FetchHgResult {
#[op2]
#[serde]
pub fn op_fetch_url(
pub fn op_fetch_url<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] url: String,
#[string] expected_hash: Option<String>,
#[string] name: Option<String>,
executable: bool,
) -> Result<FetchUrlResult, NixError> {
use crate::store::StoreBackend;
use std::sync::Arc;
let _span = tracing::info_span!("op_fetch_url", url = %url).entered();
info!("fetchurl started");
@@ -128,9 +128,9 @@ pub fn op_fetch_url(
}
}
let store = state.borrow::<Arc<StoreBackend>>();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_path = store
.as_store()
.add_to_store(&file_name, &data, false, vec![])
.map_err(|e| NixError::from(e.to_string()))?;
@@ -160,16 +160,13 @@ pub fn op_fetch_url(
#[op2]
#[serde]
pub fn op_fetch_tarball(
pub fn op_fetch_tarball<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] url: String,
#[string] expected_hash: Option<String>,
#[string] expected_nar_hash: Option<String>,
#[string] name: Option<String>,
) -> Result<FetchTarballResult, NixError> {
use crate::store::StoreBackend;
use std::sync::Arc;
let _span = tracing::info_span!("op_fetch_tarball", url = %url).entered();
info!("fetchTarball started");
@@ -264,9 +261,9 @@ pub fn op_fetch_tarball(
}
info!("Adding to store");
let store = state.borrow::<Arc<StoreBackend>>();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_path = store
.as_store()
.add_to_store_from_path(&dir_name, &extracted_path, vec![])
.map_err(|e| NixError::from(e.to_string()))?;
@@ -292,7 +289,7 @@ pub fn op_fetch_tarball(
#[op2]
#[serde]
pub fn op_fetch_git(
pub fn op_fetch_git<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] url: String,
#[string] git_ref: Option<String>,
@@ -302,19 +299,17 @@ pub fn op_fetch_git(
all_refs: bool,
#[string] name: Option<String>,
) -> Result<FetchGitResult, NixError> {
use crate::store::StoreBackend;
use std::sync::Arc;
let _span = tracing::info_span!("op_fetch_git", url = %url).entered();
info!("fetchGit started");
let cache = FetcherCache::new().map_err(|e| NixError::from(e.to_string()))?;
let dir_name = name.unwrap_or_else(|| "source".to_string());
let store = state.borrow::<Arc<StoreBackend>>();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
git::fetch_git(
&cache,
store.as_store(),
store,
&url,
git_ref.as_deref(),
rev.as_deref(),
@@ -377,11 +372,11 @@ fn base64_decode(input: &str) -> Result<Vec<u8>, String> {
Ok(output)
}
pub fn register_ops() -> Vec<deno_core::OpDecl> {
pub fn register_ops<Ctx: RuntimeContext>() -> Vec<deno_core::OpDecl> {
vec![
op_fetch_url(),
op_fetch_tarball(),
op_fetch_git(),
op_fetch_url::<Ctx>(),
op_fetch_tarball::<Ctx>(),
op_fetch_git::<Ctx>(),
op_fetch_hg(),
]
}

View File

@@ -120,7 +120,7 @@ impl AttrSet {
if let Some(attr) = path.next() {
// If the path is not yet exhausted, we need to recurse deeper.
match attr {
Attr::Str(ident) => {
Attr::Str(ident, span) => {
// If the next attribute is a static string.
if let Some(&id) = self.stcs.get(&ident) {
// If a sub-attrset already exists, recurse into it.
@@ -132,8 +132,11 @@ impl AttrSet {
// This path segment exists but is not an attrset, which is an error.
Error::downgrade_error(format!(
"attribute '{}' already defined but is not an attribute set",
format_symbol(ctx.get_sym(ident))
))
format_symbol(ctx.get_sym(ident)),
),
ctx.get_current_source(),
span
)
})
.and_then(|attrs| attrs._insert(path, name, value, ctx));
ctx.replace_expr(id, ir);
@@ -144,7 +147,7 @@ impl AttrSet {
let mut attrs = AttrSet {
stcs: Default::default(),
dyns: Default::default(),
span: synthetic_span(),
span,
};
attrs._insert(path, name, value, ctx)?;
let attrs = ctx.new_expr(attrs.to_ir());
@@ -152,14 +155,14 @@ impl AttrSet {
}
Ok(())
}
Attr::Dynamic(dynamic) => {
Attr::Dynamic(dynamic, span) => {
// If the next attribute is a dynamic expression, we must create a new sub-attrset.
// We cannot merge with existing dynamic attributes at this stage.
// FIXME: span
let mut attrs = AttrSet {
stcs: Default::default(),
dyns: Default::default(),
span: synthetic_span(),
span,
};
attrs._insert(path, name, value, ctx)?;
self.dyns.push((dynamic, ctx.new_expr(attrs.to_ir())));
@@ -169,15 +172,19 @@ impl AttrSet {
} else {
// This is the final attribute in the path, so insert the value here.
match name {
Attr::Str(ident) => {
Attr::Str(ident, span) => {
if self.stcs.insert(ident, value).is_some() {
return Err(Error::downgrade_error(format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(ident))
)));
return Err(Error::downgrade_error(
format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(ident)),
),
ctx.get_current_source(),
span,
));
}
}
Attr::Dynamic(dynamic) => {
Attr::Dynamic(dynamic, _) => {
self.dyns.push((dynamic, value));
}
}
@@ -215,10 +222,10 @@ pub struct ArgId(pub usize);
pub enum Attr {
/// A dynamic attribute key, which is an expression that must evaluate to a string.
/// Example: `attrs.${key}`
Dynamic(ExprId),
Dynamic(ExprId, TextRange),
/// A static attribute key.
/// Example: `attrs.key`
Str(SymId),
Str(SymId, TextRange),
}
/// The kinds of binary operations supported in Nix.

View File

@@ -19,9 +19,11 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for Expr {
Assert(assert) => assert.downgrade(ctx),
Error(error) => {
let span = error.syntax().text_range();
Err(self::Error::downgrade_error(error.to_string())
.with_span(span)
.with_source(ctx.get_current_source()))
Err(self::Error::downgrade_error(
error.to_string(),
ctx.get_current_source(),
span,
))
}
IfElse(ifelse) => ifelse.downgrade(ctx),
Select(select) => select.downgrade(ctx),
@@ -320,7 +322,8 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::LegacyLet {
let body_sym = ctx.new_sym("body".to_string());
let select = Select {
expr: attrset_expr,
attrpath: vec![Attr::Str(body_sym)],
// FIXME: span
attrpath: vec![Attr::Str(body_sym, synthetic_span())],
default: None,
span,
};
@@ -397,13 +400,9 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Lambda {
scc_info,
required,
optional,
} = downgrade_pattern_bindings(
pat_entries,
alias,
arg,
ctx,
|ctx, _| self.body().unwrap().downgrade(ctx),
)?;
} = downgrade_pattern_bindings(pat_entries, alias, arg, ctx, |ctx, _| {
self.body().unwrap().downgrade(ctx)
})?;
param = Some(Param {
required,

View File

@@ -79,21 +79,21 @@ pub fn downgrade_inherit(
for attr in inherit.attrs() {
let span = attr.syntax().text_range();
let ident = match downgrade_attr(attr, ctx)? {
Attr::Str(ident) => ident,
Attr::Str(ident, _) => ident,
_ => {
// `inherit` does not allow dynamic attributes.
return Err(Error::downgrade_error(
"dynamic attributes not allowed in inherit".to_string(),
)
.with_span(span)
.with_source(ctx.get_current_source()));
ctx.get_current_source(),
span,
));
}
};
let expr = if let Some(expr) = from {
let select_expr = ctx.new_expr(
Select {
expr,
attrpath: vec![Attr::Str(ident)],
attrpath: vec![Attr::Str(ident, span)],
default: None,
span,
}
@@ -111,10 +111,14 @@ pub fn downgrade_inherit(
};
match stcs.entry(ident) {
Entry::Occupied(occupied) => {
return Err(Error::downgrade_error(format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(*occupied.key()))
))
return Err(Error::downgrade_error(
format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(*occupied.key()))
),
ctx.get_current_source(),
span,
)
.with_span(span)
.with_source(ctx.get_current_source()));
}
@@ -129,20 +133,24 @@ pub fn downgrade_inherit(
pub fn downgrade_attr(attr: ast::Attr, ctx: &mut impl DowngradeContext) -> Result<Attr> {
use ast::Attr::*;
use ast::InterpolPart::*;
let span = attr.syntax().text_range();
match attr {
Ident(ident) => Ok(Attr::Str(ctx.new_sym(ident.to_string()))),
Ident(ident) => Ok(Attr::Str(
ctx.new_sym(ident.to_string()),
ident.syntax().text_range(),
)),
Str(string) => {
let parts = string.normalized_parts();
let span = string.syntax().text_range();
if parts.is_empty() {
Ok(Attr::Str(ctx.new_sym("".to_string())))
Ok(Attr::Str(ctx.new_sym("".to_string()), span))
} else if parts.len() == 1 {
// If the string has only one part, it's either a literal or a single interpolation.
match parts.into_iter().next().unwrap() {
Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident))),
Interpolation(interpol) => {
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?))
}
Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident), span)),
Interpolation(interpol) => Ok(Attr::Dynamic(
interpol.expr().unwrap().downgrade(ctx)?,
span,
)),
}
} else {
// If the string has multiple parts, it's an interpolated string that must be concatenated.
@@ -155,10 +163,14 @@ pub fn downgrade_attr(attr: ast::Attr, ctx: &mut impl DowngradeContext) -> Resul
.collect::<Result<Vec<_>>>()?;
Ok(Attr::Dynamic(
ctx.new_expr(ConcatStrings { parts, span }.to_ir()),
span,
))
}
}
Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(ctx)?)),
Dynamic(dynamic) => Ok(Attr::Dynamic(
dynamic.expr().unwrap().downgrade(ctx)?,
dynamic.syntax().text_range(),
)),
}
}
@@ -194,12 +206,14 @@ pub fn downgrade_static_attrpathvalue(
) -> Result<()> {
let attrpath_node = value.attrpath().unwrap();
let path = downgrade_attrpath(attrpath_node.clone(), ctx)?;
if path.iter().any(|attr| matches!(attr, Attr::Dynamic(_))) {
if let Some(&Attr::Dynamic(_, span)) =
path.iter().find(|attr| matches!(attr, Attr::Dynamic(..)))
{
return Err(Error::downgrade_error(
"dynamic attributes not allowed in let bindings".to_string(),
)
.with_span(attrpath_node.syntax().text_range())
.with_source(ctx.get_current_source()));
ctx.get_current_source(),
span,
));
}
let value = value.value().unwrap().downgrade(ctx)?;
attrs.insert(path, value, ctx)
@@ -231,47 +245,54 @@ pub fn downgrade_pattern_bindings<Ctx>(
where
Ctx: DowngradeContext,
{
let mut param_syms = Vec::new();
let mut param_defaults = Vec::new();
let mut param_spans = Vec::new();
let mut seen_params = HashSet::new();
for entry in pat_entries {
let sym = ctx.new_sym(entry.ident().unwrap().to_string());
let span = entry.ident().unwrap().syntax().text_range();
if !seen_params.insert(sym) {
return Err(Error::downgrade_error(format!(
"duplicate parameter '{}'",
format_symbol(ctx.get_sym(sym))
))
.with_span(span)
.with_source(ctx.get_current_source()));
}
let default_ast = entry.default();
param_syms.push(sym);
param_defaults.push(default_ast);
param_spans.push(span);
struct Param {
sym: SymId,
sym_span: TextRange,
default: Option<ast::Expr>,
span: TextRange,
}
let mut seen_params = HashSet::new();
let (params, mut binding_keys) = pat_entries
.into_iter()
.map(|entry| {
let ident = entry.ident().unwrap();
let sym_span = ident.syntax().text_range();
let sym = ctx.new_sym(ident.syntax().text().to_string());
let default = entry.default();
let span = entry.syntax().text_range();
if !seen_params.insert(sym) {
return Err(Error::downgrade_error(
format!("duplicate parameter '{}'", format_symbol(ctx.get_sym(sym))),
ctx.get_current_source(),
span,
));
}
Ok((
Param {
sym,
sym_span,
default,
span,
},
sym,
))
})
.collect::<Result<(Vec<_>, Vec<_>)>>()?;
let mut binding_keys: Vec<SymId> = param_syms.clone();
if let Some(alias_sym) = alias {
binding_keys.push(alias_sym);
}
let (required, optional) =
param_syms
.iter()
.zip(param_defaults.iter())
.partition_map(|(&sym, default)| {
use itertools::Either::*;
if default.is_none() {
Left(sym)
} else {
Right(sym)
}
});
let (required, optional) = params.iter().partition_map(|Param { sym, default, .. }| {
use itertools::Either::*;
if default.is_none() {
Left(sym)
} else {
Right(sym)
}
});
// Get the owner from outer tracker's current_binding
let owner = ctx.get_current_binding();
@@ -282,16 +303,18 @@ where
|ctx, sym_to_slot| {
let mut bindings = HashMap::new();
for ((sym, default_ast), span) in param_syms
.iter()
.zip(param_defaults.iter())
.zip(param_spans.iter())
for Param {
sym,
sym_span,
default,
span,
} in params
{
let slot = *sym_to_slot.get(sym).unwrap();
let slot = *sym_to_slot.get(&sym).unwrap();
ctx.set_current_binding(Some(slot));
let default = if let Some(default_expr) = default_ast {
Some(default_expr.clone().downgrade(ctx)?)
let default = if let Some(default) = default {
Some(default.clone().downgrade(ctx)?)
} else {
None
};
@@ -299,13 +322,13 @@ where
let select_expr = ctx.new_expr(
Select {
expr: arg,
attrpath: vec![Attr::Str(*sym)],
attrpath: vec![Attr::Str(sym, sym_span)],
default,
span: *span,
span,
}
.to_ir(),
);
bindings.insert(*sym, select_expr);
bindings.insert(sym, select_expr);
ctx.set_current_binding(None);
}
@@ -393,12 +416,11 @@ where
.to_ir(),
);
} else {
return Err(Error::downgrade_error(format!(
"binding '{}' not found",
format_symbol(ctx.get_sym(sym))
))
.with_span(synthetic_span())
.with_source(ctx.get_current_source()));
return Err(Error::downgrade_error(
format!("binding '{}' not found", format_symbol(ctx.get_sym(sym))),
ctx.get_current_source(),
synthetic_span(),
));
}
}
@@ -433,12 +455,14 @@ where
if let ast::Attr::Ident(ident) = attr {
let sym = ctx.new_sym(ident.to_string());
if !binding_syms.insert(sym) {
return Err(Error::downgrade_error(format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(sym))
))
.with_span(ident.syntax().text_range())
.with_source(ctx.get_current_source()));
return Err(Error::downgrade_error(
format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(sym))
),
ctx.get_current_source(),
ident.syntax().text_range(),
));
}
}
}
@@ -453,12 +477,14 @@ where
if let Some(ast::Attr::Ident(ident)) = attrs_vec.first() {
let sym = ctx.new_sym(ident.to_string());
if !binding_syms.insert(sym) {
return Err(Error::downgrade_error(format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(sym))
))
.with_span(ident.syntax().text_range())
.with_source(ctx.get_current_source()));
return Err(Error::downgrade_error(
format!(
"attribute '{}' already defined",
format_symbol(ctx.get_sym(sym))
),
ctx.get_current_source(),
ident.syntax().text_range(),
));
}
}
} else if attrs_vec.len() > 1 {

View File

@@ -8,6 +8,7 @@ use deno_error::JsErrorClass;
use itertools::Itertools as _;
use crate::error::{Error, Result, Source};
use crate::store::Store;
use crate::value::{AttrSet, List, Symbol, Value};
type ScopeRef<'p, 's> = v8::PinnedRef<'p, v8::HandleScope<'s>>;
@@ -19,6 +20,23 @@ pub(crate) trait RuntimeContext: 'static {
fn add_source(&mut self, path: Source);
fn compile_code(&mut self, source: Source) -> Result<String>;
fn get_source(&self, id: usize) -> Source;
fn get_store(&self) -> &dyn Store;
}
pub(crate) trait OpStateExt<Ctx: RuntimeContext> {
fn get_ctx(&self) -> &Ctx;
fn get_ctx_mut(&mut self) -> &mut Ctx;
}
impl<Ctx: RuntimeContext> OpStateExt<Ctx> for OpState {
fn get_ctx(&self) -> &Ctx {
self.try_borrow::<&'static mut Ctx>()
.expect("RuntimeContext not set")
}
fn get_ctx_mut(&mut self) -> &mut Ctx {
self.try_borrow_mut::<&'static mut Ctx>()
.expect("RuntimeContext not set")
}
}
fn runtime_extension<Ctx: RuntimeContext>() -> Extension {
@@ -30,16 +48,16 @@ fn runtime_extension<Ctx: RuntimeContext>() -> Extension {
op_path_exists(),
op_resolve_path(),
op_sha256_hex(),
op_make_store_path(),
op_make_store_path::<Ctx>(),
op_output_path_name(),
op_make_fixed_output_path(),
op_add_path(),
op_store_path(),
op_to_file(),
op_copy_path_to_store(),
op_make_fixed_output_path::<Ctx>(),
op_add_path::<Ctx>(),
op_store_path::<Ctx>(),
op_to_file::<Ctx>(),
op_copy_path_to_store::<Ctx>(),
op_get_env(),
];
ops.extend(crate::fetcher::register_ops());
ops.extend(crate::fetcher::register_ops::<Ctx>());
Extension {
name: "nix_runtime",
@@ -85,7 +103,7 @@ fn op_import<Ctx: RuntimeContext>(
#[string] path: String,
) -> std::result::Result<String, NixError> {
let _span = tracing::info_span!("op_import", path = %path).entered();
let ctx = state.borrow_mut::<Ctx>();
let ctx: &mut Ctx = state.get_ctx_mut();
let current_dir = ctx.get_current_dir();
let mut absolute_path = current_dir
@@ -169,17 +187,15 @@ fn op_sha256_hex(#[string] data: String) -> String {
#[deno_core::op2]
#[string]
fn op_make_store_path(
fn op_make_store_path<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] ty: String,
#[string] hash_hex: String,
#[string] name: String,
) -> String {
use crate::store::StoreBackend;
use std::sync::Arc;
let store = state.borrow::<Arc<StoreBackend>>();
let store_dir = store.as_store().get_store_dir();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_dir = store.get_store_dir();
crate::nix_hash::make_store_path(store_dir, &ty, &hash_hex, &name)
}
@@ -191,19 +207,18 @@ fn op_output_path_name(#[string] drv_name: String, #[string] output_name: String
#[deno_core::op2]
#[string]
fn op_make_fixed_output_path(
fn op_make_fixed_output_path<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] hash_algo: String,
#[string] hash: String,
#[string] hash_mode: String,
#[string] name: String,
) -> String {
use crate::store::StoreBackend;
use sha2::{Digest, Sha256};
use std::sync::Arc;
let store = state.borrow::<Arc<StoreBackend>>();
let store_dir = store.as_store().get_store_dir();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_dir = store.get_store_dir();
if hash_algo == "sha256" && hash_mode == "recursive" {
crate::nix_hash::make_store_path(store_dir, "source", &hash, &name)
@@ -220,18 +235,16 @@ fn op_make_fixed_output_path(
#[deno_core::op2]
#[string]
fn op_add_path(
fn op_add_path<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] path: String,
#[string] name: Option<String>,
recursive: bool,
#[string] sha256: Option<String>,
) -> std::result::Result<String, NixError> {
use crate::store::StoreBackend;
use sha2::{Digest, Sha256};
use std::fs;
use std::path::Path;
use std::sync::Arc;
let path_obj = Path::new(&path);
@@ -272,10 +285,10 @@ fn op_add_path(
)));
}
let store = state.borrow::<Arc<StoreBackend>>();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_path = store
.as_store()
.add_to_store_from_path(&computed_name, path_obj, vec![])
.map_err(|e| NixError::from(format!("failed to add path to store: {}", e)))?;
@@ -319,20 +332,19 @@ fn compute_nar_hash(path: &std::path::Path) -> std::result::Result<String, NixEr
#[deno_core::op2]
#[string]
fn op_store_path(
fn op_store_path<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] path: String,
) -> std::result::Result<String, NixError> {
use crate::store::{StoreBackend, validate_store_path};
use std::sync::Arc;
use crate::store::validate_store_path;
let store = state.borrow::<Arc<StoreBackend>>();
let store_dir = store.as_store().get_store_dir();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_dir = store.get_store_dir();
validate_store_path(store_dir, &path).map_err(|e| NixError::from(e.to_string()))?;
store
.as_store()
.ensure_path(&path)
.map_err(|e| NixError::from(e.to_string()))?;
@@ -341,18 +353,15 @@ fn op_store_path(
#[deno_core::op2]
#[string]
fn op_to_file(
fn op_to_file<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] name: String,
#[string] contents: String,
#[serde] references: Vec<String>,
) -> std::result::Result<String, NixError> {
use crate::store::StoreBackend;
use std::sync::Arc;
let store = state.borrow::<Arc<StoreBackend>>();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_path = store
.as_store()
.add_text_to_store(&name, &contents, references)
.map_err(|e| NixError::from(format!("builtins.toFile failed: {}", e)))?;
@@ -361,13 +370,11 @@ fn op_to_file(
#[deno_core::op2]
#[string]
fn op_copy_path_to_store(
fn op_copy_path_to_store<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] path: String,
) -> std::result::Result<String, NixError> {
use crate::store::StoreBackend;
use std::path::Path;
use std::sync::Arc;
let path_obj = Path::new(&path);
@@ -381,9 +388,9 @@ fn op_copy_path_to_store(
.unwrap_or("source")
.to_string();
let store = state.borrow::<Arc<StoreBackend>>();
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
let store_path = store
.as_store()
.add_to_store_from_path(&name, path_obj, vec![])
.map_err(|e| NixError::from(format!("failed to copy path to store: {}", e)))?;
@@ -436,11 +443,8 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
})
}
pub(crate) fn op_state(&mut self) -> std::rc::Rc<std::cell::RefCell<OpState>> {
self.js_runtime.op_state()
}
pub(crate) fn eval(&mut self, script: String, ctx: Ctx) -> Result<Value> {
pub(crate) fn eval(&mut self, script: String, ctx: &mut Ctx) -> Result<Value> {
let ctx: &'static mut Ctx = unsafe { &mut *(ctx as *mut Ctx) };
self.js_runtime.op_state().borrow_mut().put(ctx);
let global_value = self
@@ -450,7 +454,7 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
// Get current source from Context
let op_state = self.js_runtime.op_state();
let op_state_borrow = op_state.borrow();
let ctx = op_state_borrow.borrow::<Ctx>();
let ctx: &Ctx = op_state_borrow.get_ctx();
let msg = e.get_message().to_string();
let mut span = None;