difftreelog
build enable gc debugging
in: trunk
9 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -126,17 +126,6 @@
]
[[package]]
-name = "alejandra"
-version = "4.0.0"
-source = "git+https://github.com/kamadorueda/alejandra#c68bef57c1db3add865493d9cb741a14618bdc28"
-dependencies = [
- "mimalloc",
- "rnix",
- "rowan",
- "serde",
-]
-
-[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -673,12 +662,6 @@
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
-[[package]]
-name = "countme"
-version = "3.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
[[package]]
name = "cpufeatures"
@@ -1352,12 +1335,6 @@
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
-[[package]]
-name = "hashbrown"
-version = "0.14.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
@@ -1793,16 +1770,6 @@
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
-
-[[package]]
-name = "libmimalloc-sys"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870"
-dependencies = [
- "cc",
- "libc",
-]
[[package]]
name = "link-cplusplus"
@@ -1873,24 +1840,6 @@
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
-
-[[package]]
-name = "memoffset"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "mimalloc"
-version = "0.1.48"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8"
-dependencies = [
- "libmimalloc-sys",
-]
[[package]]
name = "mime"
@@ -1969,7 +1918,6 @@
name = "nixlike"
version = "0.1.0"
dependencies = [
- "alejandra",
"linked-hash-map",
"peg",
"ron",
@@ -2569,15 +2517,6 @@
"byteorder",
"rmp",
"serde",
-]
-
-[[package]]
-name = "rnix"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f15e00b0ab43abd70d50b6f8cd021290028f9b7fdd7cdfa6c35997173bc1ba9"
-dependencies = [
- "rowan",
]
[[package]]
@@ -2591,19 +2530,6 @@
"serde",
"serde_derive",
"unicode-ident",
-]
-
-[[package]]
-name = "rowan"
-version = "0.15.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4f1e4a001f863f41ea8d0e6a0c34b356d5b733db50dadab3efef640bafb779b"
-dependencies = [
- "countme",
- "hashbrown 0.14.5",
- "memoffset",
- "rustc-hash 1.1.0",
- "text-size",
]
[[package]]
@@ -3155,12 +3081,6 @@
dependencies = [
"unicode-width 0.2.1",
]
-
-[[package]]
-name = "text-size"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
[[package]]
name = "tf-provider"
cmds/fleet/src/main.rsdiffbeforeafterboth--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -27,7 +27,7 @@
use tracing::{Instrument, error, info, info_span};
#[cfg(feature = "indicatif")]
use tracing_indicatif::IndicatifLayer;
-use tracing_subscriber::{EnvFilter, prelude::*};
+use tracing_subscriber::{fmt::format::Format, prelude::*, EnvFilter};
#[derive(Parser)]
struct Prefetch {}
crates/fleet-base/src/opts.rsdiffbeforeafterboth--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -9,7 +9,7 @@
use anyhow::{Context, Result, bail};
use nix_eval::{
FetchSettings, FlakeLockFlags, FlakeReference, FlakeReferenceParseFlags, FlakeSettings, Value,
- nix_go, util::assert_warn,
+ gc_now, nix_go, util::assert_warn,
};
use nom::{
Parser,
@@ -260,6 +260,10 @@
system: self.local_system.clone(),
}));
+ if cfg!(debug_assertions) {
+ gc_now();
+ }
+
Ok(Config(Arc::new(FleetConfigInternals {
directory,
data,
crates/nix-eval/src/lib.rsdiffbeforeafterboth--- a/crates/nix-eval/src/lib.rs
+++ b/crates/nix-eval/src/lib.rs
@@ -1,29 +1,42 @@
+use std::alloc::{GlobalAlloc, Layout};
use std::borrow::Cow;
use std::cell::RefCell;
use std::ffi::{CStr, CString, c_char, c_int, c_uint, c_void};
-use std::fmt;
+use std::mem::forget;
use std::ptr::null_mut;
use std::sync::LazyLock;
use std::{collections::HashMap, path::PathBuf};
+use std::{fmt, slice};
use anyhow::{Context, anyhow, bail};
use serde::Serialize;
use serde::de::DeserializeOwned;
pub use anyhow::Result;
-use tracing::instrument;
+use tracing::{info, instrument};
use self::logging::nix_logging_cxx;
use self::nix_cxx::set_fetcher_setting;
use self::nix_raw::{
- alloc_value, c_context, c_context_create, err_code, err_info_msg, eval_state_build,
- eval_state_builder_new, expr_eval_from_string, fetchers_settings, fetchers_settings_free,
- fetchers_settings_new, flake_lock, flake_lock_flags, flake_lock_flags_free,
- flake_lock_flags_new, flake_reference_parse_flags, flake_reference_parse_flags_free,
- flake_reference_parse_flags_new, flake_reference_parse_flags_set_base_directory,
- flake_settings, flake_settings_free, flake_settings_new, get_string, init_bool, init_int,
- init_string, locked_flake_free, locked_flake_get_output_attrs, set_err_msg, setting_set,
- state_free, value_decref, value_incref,
+ BindingsBuilder as c_bindings_builder, EvalState as c_eval_state, GC_SUCCESS,
+ GC_allow_register_threads, GC_free, GC_get_stack_base, GC_init, GC_malloc, GC_realloc,
+ GC_register_my_thread, GC_stack_base, GC_thread_is_registered, GC_unregister_my_thread,
+ Store as c_store, alloc_value, bindings_builder_free, bindings_builder_insert, c_context,
+ c_context_create, c_context_free, clear_err, err_code, err_info_msg, err_msg, eval_state_build,
+ eval_state_builder_load, eval_state_builder_new, eval_state_builder_set_eval_setting,
+ expr_eval_from_string, fetchers_settings, fetchers_settings_free, fetchers_settings_new,
+ flake_lock, flake_lock_flags, flake_lock_flags_free, flake_lock_flags_new, flake_reference,
+ flake_reference_and_fragment_from_string, flake_reference_parse_flags,
+ flake_reference_parse_flags_free, flake_reference_parse_flags_new,
+ flake_reference_parse_flags_set_base_directory, flake_settings, flake_settings_free,
+ flake_settings_new, get_attr_byname, get_attr_name_byidx, get_attrs_size, get_list_byidx,
+ get_list_size, get_string, get_type, has_attr_byname, init_bool, init_int, init_string,
+ libexpr_init, libstore_init, libutil_init, locked_flake, locked_flake_free,
+ locked_flake_get_output_attrs, make_attrs, make_bindings_builder, realised_string,
+ realised_string_free, realised_string_get_buffer_size, realised_string_get_buffer_start,
+ realised_string_get_store_path, realised_string_get_store_path_count, set_err_msg, setting_set,
+ state_free, store_open, store_path_name, string_realise, value, value_call, value_decref,
+ value_incref,
};
// Contains macros helpers
@@ -117,22 +130,26 @@
}
}
+pub fn gc_now() {
+ unsafe { nix_raw::gc_now() };
+}
+
pub fn gc_register_my_thread() {
- assert_eq!(unsafe { nix_raw::GC_thread_is_registered() }, 0);
+ assert_eq!(unsafe { GC_thread_is_registered() }, 0);
- let mut sb = nix_raw::GC_stack_base {
+ let mut sb = GC_stack_base {
mem_base: null_mut(),
};
- let r = unsafe { nix_raw::GC_get_stack_base(&mut sb) };
- if r as u32 != nix_raw::GC_SUCCESS {
+ let r = unsafe { GC_get_stack_base(&mut sb) };
+ if r as u32 != GC_SUCCESS {
panic!("failed to get thread stack base");
}
- unsafe { nix_raw::GC_register_my_thread(&sb) };
+ unsafe { GC_register_my_thread(&sb) };
}
pub fn gc_unregister_my_thread() {
- assert_eq!(unsafe { nix_raw::GC_thread_is_registered() }, 1);
+ assert_eq!(unsafe { GC_thread_is_registered() }, 1);
- unsafe { nix_raw::GC_unregister_my_thread() };
+ unsafe { GC_unregister_my_thread() };
}
pub struct ThreadRegisterGuard {}
@@ -178,12 +195,12 @@
// TODO: Can throw error (resulting in panic) if unable to retrieve error. Should be able to resolve by passing context as a first argument,
// but it looks ugly
- let str = unsafe { nix_raw::err_msg(null_mut(), self.0, null_mut()) };
+ let str = unsafe { err_msg(null_mut(), self.0, null_mut()) };
Some(unsafe { CStr::from_ptr(str) }.to_string_lossy())
}
fn clean_err(&mut self) {
unsafe {
- nix_raw::clear_err(self.0);
+ clear_err(self.0);
}
}
@@ -211,7 +228,7 @@
impl Drop for NixContext {
fn drop(&mut self) {
unsafe {
- nix_raw::c_context_free(self.0);
+ c_context_free(self.0);
}
}
}
@@ -225,35 +242,26 @@
fn new() -> Result<Self> {
let mut ctx = NixContext::new();
let store = ctx
- .run_in_context(|c| unsafe { nix_raw::store_open(c, c"auto".as_ptr(), null_mut()) })
+ .run_in_context(|c| unsafe { store_open(c, c"auto".as_ptr(), null_mut()) })
.map(Store)?;
let builder = ctx.run_in_context(|c| unsafe { eval_state_builder_new(c, store.0) })?;
- ctx.run_in_context(|c| {
- unsafe { nix_raw::eval_state_builder_load(c, builder) }
- // eval_s
- })?;
- ctx.run_in_context(|c| {
- unsafe {
- nix_raw::eval_state_builder_set_eval_setting(
- c,
- builder,
- c"lazy-trees".as_ptr(),
- c"true".as_ptr(),
- )
- }
- // eval_s
+ ctx.run_in_context(|c| unsafe { eval_state_builder_load(c, builder) })?;
+ ctx.run_in_context(|c| unsafe {
+ eval_state_builder_set_eval_setting(
+ c,
+ builder,
+ c"lazy-trees".as_ptr(),
+ c"true".as_ptr(),
+ )
})?;
- ctx.run_in_context(|c| {
- unsafe {
- nix_raw::eval_state_builder_set_eval_setting(
- c,
- builder,
- c"lazy-locks".as_ptr(),
- c"true".as_ptr(),
- )
- }
- // eval_s
+ ctx.run_in_context(|c| unsafe {
+ eval_state_builder_set_eval_setting(
+ c,
+ builder,
+ c"lazy-locks".as_ptr(),
+ c"true".as_ptr(),
+ )
})?;
let state = ctx
.run_in_context(|c| unsafe { eval_state_build(c, builder) })
@@ -280,9 +288,7 @@
thread_local! {
static THREAD_STATE: RefCell<ThreadState> = RefCell::new(ThreadState::new().expect("thread state init shouldn't fail"));
}
-fn with_default_context<T>(
- f: impl FnOnce(*mut c_context, *mut nix_raw::EvalState) -> T,
-) -> Result<T> {
+fn with_default_context<T>(f: impl FnOnce(*mut c_context, *mut c_eval_state) -> T) -> Result<T> {
let global = &GLOBAL_STATE.state;
let (ctx, state) = THREAD_STATE.with_borrow_mut(|w| (w.ctx.0, global.0));
let mut ctx = NixContext(ctx);
@@ -385,16 +391,16 @@
}
unsafe extern "C" fn copy_nix_str(start: *const c_char, n: c_uint, user_data: *mut c_void) {
- let s = unsafe { std::slice::from_raw_parts(start.cast::<u8>(), n as usize) };
+ let s = unsafe { slice::from_raw_parts(start.cast::<u8>(), n as usize) };
let s = std::str::from_utf8(s).expect("c string has invalid utf-8");
unsafe { *user_data.cast::<String>() = s.to_owned() };
}
-struct Store(*mut nix_raw::Store);
+struct Store(*mut c_store);
unsafe impl Send for Store {}
unsafe impl Sync for Store {}
-struct EvalState(*mut nix_raw::EvalState);
+struct EvalState(*mut c_eval_state);
unsafe impl Send for EvalState {}
unsafe impl Sync for EvalState {}
@@ -406,7 +412,7 @@
}
}
-pub struct FlakeReference(*mut nix_raw::flake_reference);
+pub struct FlakeReference(*mut flake_reference);
impl FlakeReference {
#[instrument(name = "new-flake-reference", skip(flake, parse, fetch))]
pub fn new(
@@ -419,7 +425,7 @@
let mut fragment = String::new();
// let fetch_settings = fetcher_settings;
with_default_context(|c, _| unsafe {
- nix_raw::flake_reference_and_fragment_from_string(
+ flake_reference_and_fragment_from_string(
c,
fetch.0,
flake.0,
@@ -449,7 +455,7 @@
unsafe impl Send for FlakeReference {}
unsafe impl Sync for FlakeReference {}
-pub struct LockedFlake(*mut nix_raw::locked_flake);
+pub struct LockedFlake(*mut locked_flake);
impl LockedFlake {
pub fn get_attrs(&self, settings: &mut FlakeSettings) -> Result<Value> {
with_default_context(|c, es| unsafe {
@@ -480,7 +486,7 @@
f
}
-pub struct RealisedString(*mut nix_raw::realised_string);
+pub struct RealisedString(*mut realised_string);
impl fmt::Debug for RealisedString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
@@ -489,19 +495,19 @@
impl RealisedString {
pub fn as_str(&self) -> &str {
- let len = unsafe { nix_raw::realised_string_get_buffer_size(self.0) };
- let data: *const u8 = unsafe { nix_raw::realised_string_get_buffer_start(self.0) }.cast();
- let data = unsafe { std::slice::from_raw_parts(data, len) };
+ let len = unsafe { realised_string_get_buffer_size(self.0) };
+ let data: *const u8 = unsafe { realised_string_get_buffer_start(self.0) }.cast();
+ let data = unsafe { slice::from_raw_parts(data, len) };
std::str::from_utf8(data).expect("non-utf8 strings not supported")
}
pub fn path_count(&self) -> usize {
- unsafe { nix_raw::realised_string_get_store_path_count(self.0) }
+ unsafe { realised_string_get_store_path_count(self.0) }
}
pub fn path(&self, i: usize) -> String {
assert!(i < self.path_count());
- let path = unsafe { nix_raw::realised_string_get_store_path(self.0, i) };
+ let path = unsafe { realised_string_get_store_path(self.0, i) };
let mut err_out = String::new();
- unsafe { nix_raw::store_path_name(path, Some(copy_nix_str), (&raw mut err_out).cast()) };
+ unsafe { store_path_name(path, Some(copy_nix_str), (&raw mut err_out).cast()) };
err_out
}
}
@@ -509,11 +515,11 @@
unsafe impl Send for RealisedString {}
impl Drop for RealisedString {
fn drop(&mut self) {
- unsafe { nix_raw::realised_string_free(self.0) }
+ unsafe { realised_string_free(self.0) }
}
}
-pub struct Value(*mut nix_raw::value);
+pub struct Value(*mut value);
unsafe impl Send for Value {}
unsafe impl Sync for Value {}
@@ -544,17 +550,18 @@
}
}
-struct AttrsBuilder(*mut nix_raw::BindingsBuilder);
+struct AttrsBuilder(*mut c_bindings_builder);
impl AttrsBuilder {
fn new(capacity: usize) -> Self {
- with_default_context(|c, es| unsafe { nix_raw::make_bindings_builder(c, es, capacity) })
+ with_default_context(|c, es| unsafe { make_bindings_builder(c, es, capacity) })
.map(Self)
.expect("alloc should not fail")
}
fn insert(&mut self, k: &impl AsFieldName, v: Value) {
k.as_field_name(|name| {
with_default_context(|c, _| unsafe {
- nix_raw::bindings_builder_insert(c, self.0, name.as_ptr().cast(), v.0)
+ bindings_builder_insert(c, self.0, name.as_ptr().cast(), v.0);
+ // bindings_builder_insert doesn't do incref
})
})
.expect("builder insert shouldn't fail");
@@ -562,7 +569,7 @@
}
impl Drop for AttrsBuilder {
fn drop(&mut self) {
- unsafe { nix_raw::bindings_builder_free(self.0) };
+ unsafe { bindings_builder_free(self.0) };
}
}
@@ -573,8 +580,9 @@
for (k, v) in v {
b.insert(&k, v);
}
- with_default_context(|c, _| unsafe { nix_raw::make_attrs(c, out.0, b.0) })
+ with_default_context(|c, _| unsafe { make_attrs(c, out.0, b.0) })
.expect("attrs initialization should not fail");
+
out
}
fn new_list<T: Into<Self>>(v: Vec<T>) -> Self {
@@ -611,7 +619,7 @@
// Ok(())
// }
pub fn type_of(&self) -> NixType {
- let ty = with_default_context(|c, _| unsafe { nix_raw::get_type(c, self.0) })
+ let ty = with_default_context(|c, _| unsafe { get_type(c, self.0) })
.expect("get_type should not fail");
NixType::from_int(ty)
}
@@ -628,7 +636,7 @@
Ok(str_out)
}
pub fn to_realised_string(&self) -> Result<RealisedString> {
- with_default_context(|c, es| unsafe { nix_raw::string_realise(c, es, self.0, false) })
+ with_default_context(|c, es| unsafe { string_realise(c, es, self.0, false) })
.map(RealisedString)
// let store_paths = unsafe { nix_raw::realised_string_get_store_path_count(str) };
@@ -642,9 +650,7 @@
pub fn has_field(&self, field: &str) -> Result<bool> {
let f = init_field_name(field);
- with_default_context(|c, es| unsafe {
- nix_raw::has_attr_byname(c, self.0, es, f.as_ptr().cast())
- })
+ with_default_context(|c, es| unsafe { has_attr_byname(c, self.0, es, f.as_ptr().cast()) })
}
// pub fn derivation_path(&self) {
// nix_raw::real
@@ -654,13 +660,12 @@
bail!("invalid type: expected attrs");
}
- let len = with_default_context(|c, _| unsafe { nix_raw::get_attrs_size(c, self.0) })?;
+ let len = with_default_context(|c, _| unsafe { get_attrs_size(c, self.0) })?;
let mut out = Vec::with_capacity(len as usize);
for i in 0..len {
- let name = with_default_context(|c, es| unsafe {
- nix_raw::get_attr_name_byidx(c, self.0, es, i)
- })?;
+ let name =
+ with_default_context(|c, es| unsafe { get_attr_name_byidx(c, self.0, es, i) })?;
let c = unsafe { CStr::from_ptr(name) };
out.push(c.to_str().expect("nix field names are utf-8").to_owned());
}
@@ -670,14 +675,12 @@
if !matches!(self.type_of(), NixType::List) {
bail!("invalid type: expected list");
}
- let len =
- with_default_context(|c, _| unsafe { nix_raw::get_list_size(c, self.0) })? as usize;
+ let len = with_default_context(|c, _| unsafe { get_list_size(c, self.0) })? as usize;
if v >= len {
bail!("oob list get: {v} >= {len}");
}
- with_default_context(|c, es| unsafe { nix_raw::get_list_byidx(c, self.0, es, v as u32) })
- .map(Self)
+ with_default_context(|c, es| unsafe { get_list_byidx(c, self.0, es, v as u32) }).map(Self)
}
pub fn attrs_update(self, other: Value) -> Result<Self> {
let a_fields = self.list_fields()?;
@@ -710,7 +713,7 @@
name.as_field_name(|name| {
with_default_context(|c, es| unsafe {
- nix_raw::get_attr_byname(c, self.0, es, name.as_ptr().cast())
+ get_attr_byname(c, self.0, es, name.as_ptr().cast())
})
.map(Self)
})
@@ -735,9 +738,7 @@
};
let out = Value::new_uninit();
- with_default_context(|c, es| unsafe {
- nix_raw::value_call(c, es, function.0, v.0, out.0)
- })?;
+ with_default_context(|c, es| unsafe { value_call(c, es, function.0, v.0, out.0) })?;
Ok(out)
}
@@ -745,7 +746,7 @@
let s = CString::new(v).expect("expression shouldn't have internal NULs");
let out = Self::new_uninit();
with_default_context(|c, es| unsafe {
- expr_eval_from_string(c, es, s.as_ptr(), c"/homeless-shelter".as_ptr(), out.0)
+ expr_eval_from_string(c, es, s.as_ptr(), c"/root".as_ptr(), out.0)
})?;
Ok(out)
}
@@ -764,11 +765,10 @@
self.clone()
};
// to_string here blocks until the path is built
- let drv_path =
- tokio::task::spawn_blocking(move || v.builtin_to_string()?.to_realised_string())
- .await
- .expect("spawn should not fail")?;
- Ok(PathBuf::from(drv_path.as_str()))
+ let s = v.builtin_to_string()?;
+ let rs = s.to_realised_string()?;
+ let drv_path = rs.as_str().to_owned();
+ Ok(PathBuf::from(drv_path))
}
pub fn as_json<T: DeserializeOwned>(&self) -> Result<T> {
let to_json = Self::eval("builtins.toJSON")?;
@@ -848,17 +848,14 @@
}
pub fn init_libraries() {
- unsafe { nix_raw::GC_allow_register_threads() };
- unsafe {
- nix_raw::GC_init();
- };
+ unsafe { GC_allow_register_threads() };
let mut ctx = NixContext::new();
- ctx.run_in_context(|c| unsafe { nix_raw::libutil_init(c) })
+ ctx.run_in_context(|c| unsafe { libutil_init(c) })
.expect("util init should not fail");
- ctx.run_in_context(|c| unsafe { nix_raw::libstore_init(c) })
+ ctx.run_in_context(|c| unsafe { libstore_init(c) })
.expect("store init should not fail");
- ctx.run_in_context(|c| unsafe { nix_raw::libexpr_init(c) })
+ ctx.run_in_context(|c| unsafe { libexpr_init(c) })
.expect("expr init should not fail");
nix_logging_cxx::apply_tracing_logger();
@@ -872,8 +869,11 @@
fetch_settings.set(c"warn-dirty", c"false");
let manifest = format!("{}/../../", env!("CARGO_MANIFEST_DIR"));
- let (mut r, _) = FlakeReference::new(&manifest, &fetch_settings)?;
- let locked = r.lock(&fetch_settings)?;
+ let flake = FlakeSettings::new()?;
+ let parse = FlakeReferenceParseFlags::new(&flake)?;
+ let (mut r, _) = FlakeReference::new(&manifest, &flake, &parse, &fetch_settings)?;
+ let lock = FlakeLockFlags::new(&flake)?;
+ let locked = r.lock(&fetch_settings, &flake, &lock)?;
let attrs = locked.get_attrs(&mut FlakeSettings::new()?)?;
let builtins = Value::eval("builtins")?;
@@ -887,3 +887,22 @@
Ok(())
}
+
+// pub struct GcAlloc;
+// unsafe impl GlobalAlloc for GcAlloc {
+// unsafe fn alloc(&self, l: Layout) -> *mut u8 {
+// let ptr = unsafe { GC_malloc(l.size()) };
+// ptr.cast()
+// }
+// unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {
+// // unsafe { GC_free(ptr.cast()) };
+// }
+//
+// unsafe fn realloc(&self, ptr: *mut u8, _: Layout, new_size: usize) -> *mut u8 {
+// let ptr = unsafe { GC_realloc(ptr.cast(), new_size) };
+// ptr.cast()
+// }
+// }
+//
+// #[global_allocator]
+// static GC: GcAlloc = GcAlloc;
crates/nix-eval/src/logging.rsdiffbeforeafterboth1use std::collections::HashMap;2use std::fmt::Arguments;3use std::sync::{LazyLock, Mutex};45use tracing::{6 Level, Span, debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn,7 warn_span,8};9#[cfg(feature = "indicatif")]10use tracing_indicatif::span_ext::IndicatifSpanExt as _;11use vte::Parser;1213#[derive(Debug)]14enum ActivityType {15 Unknown = 0,16 CopyPath = 100,17 FileTransfer = 101,18 Realise = 102,19 CopyPaths = 103,20 Builds = 104,21 Build = 105,22 OptimiseStore = 106,23 VerifyPaths = 107,24 Substitute = 108,25 QueryPathInfo = 109,26 PostBuildHook = 110,27 BuildWaiting = 111,28 FetchTree = 112,29}3031fn strip_prefix_suffix<'s, 'p>(a: &'s str, pref: &'p str, suff: &'p str) -> Option<&'s str> {32 a.strip_prefix(pref)?.strip_suffix(suff)33}3435fn parse_path(path: &str) -> &str {36 strip_prefix_suffix(path, "\x1b[35;1m", "\x1b[0m").unwrap_or(path)37}3839fn parse_drv(drv: &str) -> &str {40 let drv = parse_path(drv);41 if let Some(pkg) = drv.strip_prefix("/nix/store/") {42 let mut it = pkg.splitn(2, '-');43 it.next();44 if let Some(pkg) = it.next() {45 return pkg;46 }47 }48 drv49}50fn parse_host(host: &str) -> &str {51 if host.is_empty() || host == "local" {52 return "local";53 }54 // https/ssh is the default55 host.strip_prefix("https://").unwrap_or(host)56}5758impl ActivityType {59 fn name(&self) -> &'static str {60 match self {61 ActivityType::Unknown => "nix",62 ActivityType::CopyPath => "nix::copy-path",63 ActivityType::FileTransfer => "nix::file-transfer",64 ActivityType::Realise => "nix::realise",65 ActivityType::CopyPaths => "nix::copy-paths",66 ActivityType::Builds => "nix::builds",67 ActivityType::Build => "nix::build",68 ActivityType::OptimiseStore => "nix::optimise-store",69 ActivityType::VerifyPaths => "nix::verify-paths",70 ActivityType::Substitute => "nix::substitute",71 ActivityType::QueryPathInfo => "nix::query-path-info",72 ActivityType::PostBuildHook => "nix::post-build-hook",73 ActivityType::BuildWaiting => "nix::build-waiting",74 ActivityType::FetchTree => "nix::fetch-tree",75 }76 }77 fn format(78 &self,79 values: &[FieldValue],80 s: &str,81 into: impl FnOnce(Arguments<'_>) -> Span,82 ) -> Span {83 use FieldValue::*;84 match (self, values) {85 (ActivityType::QueryPathInfo, [Str(drv), Str(host)]) => {86 let drv = parse_drv(drv);87 let host = parse_host(host);88 debug_span!(target: "nix::query-path-info", "querying", drv, host)89 }90 (ActivityType::Substitute, [Str(drv), Str(host)]) => {91 let drv = parse_drv(drv);92 let host = parse_host(host);93 debug_span!(target: "nix::substitute", "substituting", drv, host)94 }95 (ActivityType::CopyPath, [Str(drv), Str(from), Str(to)]) => {96 let drv = parse_drv(drv);97 let from = parse_host(from);98 let to = parse_host(to);99 debug_span!(target: "nix::copy-path", "copying", drv, from, to)100 }101 (ActivityType::Build, [Str(drv), Str(host), Int(_), Int(_)]) => {102 let drv = parse_drv(drv);103 let host = parse_host(host);104 info_span!(target: "nix::build", "building", drv, host)105 }106 (ActivityType::FileTransfer, [Str(file)]) => {107 info_span!(target: "nix::file-transfer", "downloading", file)108 }109 (ActivityType::Realise, []) => {110 debug_span!(target: "nix::realise", "realising")111 }112 (ActivityType::CopyPaths, []) => {113 debug_span!(target: "nix::copy-paths", "copying paths")114 }115 (ActivityType::Unknown, [])116 if s.starts_with("copying \"") && s.ends_with("\" to the store") =>117 {118 let tree = s119 .trim_start_matches("copying \"")120 .trim_end_matches("\" to the store");121 debug_span!(target: "nix::trees", "copying", tree)122 }123 (ActivityType::Unknown, [])124 if s.starts_with("copying '") && s.ends_with("' to the store") =>125 {126 let tree = s127 .trim_start_matches("copying '")128 .trim_end_matches("' to the store");129 debug_span!(target: "nix::trees", "copying", tree)130 }131 (ActivityType::Unknown, []) if s.starts_with("hashing '") && s.ends_with("'") => {132 let tree = s.trim_start_matches("hashing '").trim_end_matches("'");133 debug_span!(target: "nix::trees", "hashing", tree)134 }135 (ActivityType::Unknown, []) if s.starts_with("connecting to '") && s.ends_with("'") => {136 let host = s137 .trim_start_matches("connecting to '")138 .trim_end_matches("'");139 debug_span!(target: "nix::remote", "connecting", host)140 }141 (ActivityType::Unknown, [])142 if s.starts_with("copying outputs from '") && s.ends_with("'") =>143 {144 let host = s145 .trim_start_matches("copying outputs from '")146 .trim_end_matches("'");147 debug_span!(target: "nix::remote", "copying outputs", host)148 }149 (ActivityType::Unknown, [])150 if s.starts_with("copying dependencies to '") && s.ends_with("'") =>151 {152 let host = s153 .trim_start_matches("copying dependencies to '")154 .trim_end_matches("'");155 debug_span!(target: "nix::remote", "copying dependencies", host)156 }157 (ActivityType::Unknown, [])158 if s.starts_with("waiting for the upload lock to '") && s.ends_with("'") =>159 {160 let host = s161 .trim_start_matches("waiting for the upload lock to '")162 .trim_end_matches("'");163 debug_span!(target: "nix::remote", "waiting for upload lock", host)164 }165 (ActivityType::BuildWaiting, [])166 if s.starts_with("waiting for a machine to build '") && s.ends_with("'") =>167 {168 let drv = parse_drv(169 s.trim_start_matches("waiting for a machine to build '")170 .trim_end_matches("'"),171 );172 debug_span!(target: "nix::build-waiting", "waiting for available builder", drv)173 }174 (ActivityType::Unknown, []) if s == "querying info about missing paths" => {175 debug_span!(target: "nix::remote", "querying")176 }177 _ => into(format_args!("{}({values:?})", self.name())),178 }179 }180 fn from_int(v: u32) -> Self {181 match v {182 0 => Self::Unknown,183 100 => Self::CopyPath,184 101 => Self::FileTransfer,185 102 => Self::Realise,186 103 => Self::CopyPaths,187 104 => Self::Builds,188 105 => Self::Build,189 106 => Self::OptimiseStore,190 107 => Self::VerifyPaths,191 108 => Self::Substitute,192 109 => Self::QueryPathInfo,193 110 => Self::PostBuildHook,194 111 => Self::BuildWaiting,195 112 => Self::FetchTree,196 _ => {197 warn!("unknown nix action: {v}");198 Self::Unknown199 }200 }201 }202}203204#[derive(Debug)]205enum ResultType {206 FileLinked = 100,207 BuildLogLine = 101,208 UntrustedPath = 102,209 CorruptedPath = 103,210 SetPhase = 104,211 Progress = 105,212 SetExpected = 106,213 PostBuildLogLine = 107,214 FetchStatus = 108,215216 Unknown = 999,217}218impl ResultType {219 fn from_int(v: u32) -> Self {220 match v {221 100 => Self::FileLinked,222 101 => Self::BuildLogLine,223 102 => Self::UntrustedPath,224 103 => Self::CorruptedPath,225 104 => Self::SetPhase,226 105 => Self::Progress,227 106 => Self::SetExpected,228 107 => Self::PostBuildLogLine,229 108 => Self::FetchStatus,230231 _ => {232 warn!("unknown nix result: {v}");233 Self::Unknown234 }235 }236 }237}238#[derive(Clone, Copy)]239enum Verbosity {240 Error,241 Warn,242 Notice,243 Info,244 Talkative,245 Chatty,246 Debug,247 Vomit,248}249impl From<Verbosity> for tracing::Level {250 fn from(val: Verbosity) -> Self {251 match val {252 Verbosity::Error => Level::ERROR,253 Verbosity::Warn => Level::WARN,254 Verbosity::Notice => Level::WARN,255 Verbosity::Info => Level::INFO,256 Verbosity::Talkative => Level::DEBUG,257 Verbosity::Chatty => Level::DEBUG,258 Verbosity::Debug => Level::DEBUG,259 Verbosity::Vomit => Level::TRACE,260 }261 }262}263impl Verbosity {264 fn from_int(u: u32) -> Self {265 [266 Self::Error,267 Self::Warn,268 Self::Notice,269 Self::Info,270 Self::Talkative,271 Self::Chatty,272 Self::Debug,273 Self::Vomit,274 ]275 .get(u as usize)276 .cloned()277 .unwrap_or_else(|| {278 warn!("unknown log level: {u}");279 Verbosity::Vomit280 })281 }282}283284static NIX_SPAN_MAPPING: LazyLock<Mutex<HashMap<u64, Span>>> =285 LazyLock::new(|| Mutex::new(HashMap::new()));286287#[derive(Debug)]288enum FieldValue {289 Int(i32),290 Str(String),291}292293struct StartActivityBuilder {294 activity_id: u64,295 verbosity: Verbosity,296 typ: ActivityType,297 fields: Vec<FieldValue>,298}299impl StartActivityBuilder {300 fn add_int_field(&mut self, i: i32) {301 self.fields.push(FieldValue::Int(i));302 }303 fn add_string_field(&mut self, v: &str) {304 self.fields.push(FieldValue::Str(v.to_owned()));305 }306 fn emit(&mut self, parent: u64, s: &str) {307 let mut mapping = NIX_SPAN_MAPPING.lock().expect("not poisoned");308309 let parent = mapping.get(&parent);310311 // let meta = spans.alloc_metadata(312 // self.typ.name(),313 // self.verbosity.into(),314 // MetadataKind::Span,315 // "nix activity start",316 // None,317 // None,318 // None,319 // self.typ.fields(),320 // );321 //322 // let mut fields = meta.fields().iter();323 // let span = if let Some(parent) = parent {324 // let s = Span::new(325 // meta,326 // &match meta.fields().len() {327 // 1 => meta.fields().value_set(328 // &<[_; 1]>::try_from([(329 // &fields.next().expect("has field"),330 // Some(&format_args!("Test") as &dyn tracing::Value),331 // )])332 // .expect("valid size"),333 // ),334 // _ => unreachable!(),335 // },336 // );337 // s.follows_from(parent);338 // s339 // } else {340 // Span::new_root(341 // meta,342 // &match meta.fields().len() {343 // 1 => meta.fields().value_set(344 // &<[_; 1]>::try_from([(345 // &fields.next().expect("has field"),346 // Some(&format_args!("Test") as &dyn tracing::Value),347 // )])348 // .expect("valid size"),349 // ),350 // _ => unreachable!(),351 // },352 // )353 // };354 //355 // let id = span.id().expect("id created");356357 let span = {358 let _in_parent = parent.map(|p| p.enter());359 let level: Level = self.verbosity.into();360 if level == Level::ERROR {361 self.typ362 .format(&self.fields, s, |v| error_span!("action", v))363 } else if level == Level::WARN {364 self.typ365 .format(&self.fields, s, |v| warn_span!("action", v))366 } else if level == Level::INFO {367 self.typ368 .format(&self.fields, s, |v| info_span!("action", v))369 } else if level == Level::DEBUG {370 self.typ371 .format(&self.fields, s, |v| debug_span!("action", v))372 } else {373 self.typ374 .format(&self.fields, s, |v| trace_span!("action", v))375 }376 };377 if !s.trim().is_empty() {378 let s = ansi_filter(s);379 #[cfg(feature = "indicatif")]380 {381 span.pb_set_message(s);382 }383 let _e = span.enter();384 let level: Level = self.verbosity.into();385 if level == Level::ERROR {386 error!(target: "nix", "{}", s)387 } else if level == Level::WARN {388 warn!(target: "nix", "{}", s)389 } else if level == Level::INFO {390 info!(target: "nix", "{}", s)391 } else if level == Level::DEBUG {392 debug!(target: "nix", "{}", s)393 } else {394 trace!(target: "nix", "{}", s)395 }396 } else {397 #[cfg(feature = "indicatif")]398 {399 span.pb_start();400 }401 }402 mapping.insert(self.activity_id, span);403 }404 fn emit_result(&mut self, ty: u32) {405 let mapping = NIX_SPAN_MAPPING.lock().expect("not poisoned");406407 let Some(parent) = mapping.get(&self.activity_id) else {408 panic!("unexpected result for dead parent");409 };410411 let _in_parent = parent.enter();412 let res = ResultType::from_int(ty);413414 use FieldValue::*;415 match (&res, self.fields.as_slice()) {416 // ResultType::FileLinked => todo!(),417 (ResultType::BuildLogLine, [Str(s)]) => {418 let s = ansi_filter(s);419 info!("{s}");420 }421 // ResultType::UntrustedPath => todo!(),422 // ResultType::CorruptedPath => todo!(),423 // ResultType::SetPhase => todo!(),424 (ResultType::SetExpected, [Int(act_ty), Int(_expected)]) => {425 let _act_ty = ActivityType::from_int(*act_ty as u32);426 }427 (ResultType::SetPhase, [Str(phase)]) => {428 // parent.pb_set_message(phase);429 debug!(target: "nix::phase", phase)430 }431 (ResultType::Progress, [Int(_done), Int(_expected), Int(_), Int(_)]) => {432 #[cfg(feature = "indicatif")]433 {434 parent.pb_set_length(*_expected as u64);435 parent.pb_set_position(*_done as u64);436 }437 }438 _ => warn!("unknown progress report: {:?}({:?})", &res, &self.fields),439 }440 }441}442fn new_start_activity(activity_id: u64, lvl: u32, typ: u32) -> Box<StartActivityBuilder> {443 Box::new(StartActivityBuilder {444 activity_id,445 verbosity: Verbosity::from_int(lvl),446 typ: ActivityType::from_int(typ),447 fields: vec![],448 })449}450451fn emit_warn(v: &str) {452 warn!(target: "nix::eval", "{v}")453}454fn emit_stop(v: u64) {455 let mut mapping = NIX_SPAN_MAPPING.lock().expect("not poisoned");456 mapping.remove(&v);457}458fn emit_log(lvl: u32, v: &str) {459 let verbosity = Verbosity::from_int(lvl);460 let level: Level = verbosity.into();461 if level == Level::ERROR {462 error!(target: "nix", "{v}")463 } else if level == Level::WARN {464 warn!(target: "nix", "{v}")465 } else if level == Level::INFO {466 info!(target: "nix", "{v}")467 } else if level == Level::DEBUG {468 debug!(target: "nix", "{v}")469 } else {470 trace!(target: "nix", "{v}")471 }472}473474struct AnsiFiltered {475 output: String,476}477impl vte::Perform for AnsiFiltered {478 fn print(&mut self, c: char) {479 self.output.push(c);480 }481482 fn execute(&mut self, byte: u8) {483 // We don't want \r, bells, etc484 if byte == b'\n' {485 self.output.push('\n');486 } else if byte == b'\t' {487 // TODO: align output to the correct multiplier?488 self.output.push('\t');489 }490 }491492 fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {}493 fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {}494495 fn csi_dispatch(496 &mut self,497 params: &vte::Params,498 _intermediates: &[u8],499 _ignore: bool,500 action: char,501 ) {502 use std::fmt::Write;503 if action != 'm' {504 // Only plain colors are enabled, everything other might corrupt the output505 return;506 }507 self.output.push_str("IDK\x1b[");508 for (i, par) in params.iter().enumerate() {509 if i != 0 {510 let _ = write!(self.output, ";");511 }512 for (i, sub) in par.iter().enumerate() {513 if i != 0 {514 let _ = write!(self.output, ":");515 }516 let _ = write!(self.output, "{sub}");517 }518 }519 self.output.push(action);520 }521}522fn ansi_filter(i: &str) -> String {523 let mut out = AnsiFiltered {524 output: String::new(),525 };526 let mut parser = Parser::new();527528 // For some reason it gets stuck with longer inputs529 for chunk in i.as_bytes().chunks(50) {530 parser.advance(&mut out, chunk);531 }532533 out.output534}535536#[cxx::bridge]537pub mod nix_logging_cxx {538 extern "Rust" {539 type StartActivityBuilder;540 fn new_start_activity(activity_id: u64, lvl: u32, typ: u32) -> Box<StartActivityBuilder>;541 fn add_int_field(&mut self, i: i32);542 fn add_string_field(&mut self, v: &str);543 fn emit(&mut self, parent: u64, s: &str);544 fn emit_result(&mut self, ty: u32);545546 fn emit_warn(v: &str);547 fn emit_stop(id: u64);548 fn emit_log(lvl: u32, v: &str);549 }550 unsafe extern "C++" {551 include!("nix-eval/src/logging.hh");552553 fn apply_tracing_logger();554 }555}1use std::collections::HashMap;2use std::fmt::Arguments;3use std::sync::{LazyLock, Mutex};45use tracing::{6 Level, Span, debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn,7 warn_span,8};9#[cfg(feature = "indicatif")]10use tracing_indicatif::span_ext::IndicatifSpanExt as _;11use vte::Parser;1213#[derive(Debug)]14enum ActivityType {15 Unknown = 0,16 CopyPath = 100,17 FileTransfer = 101,18 Realise = 102,19 CopyPaths = 103,20 Builds = 104,21 Build = 105,22 OptimiseStore = 106,23 VerifyPaths = 107,24 Substitute = 108,25 QueryPathInfo = 109,26 PostBuildHook = 110,27 BuildWaiting = 111,28 FetchTree = 112,29}3031fn strip_prefix_suffix<'s, 'p>(a: &'s str, pref: &'p str, suff: &'p str) -> Option<&'s str> {32 a.strip_prefix(pref)?.strip_suffix(suff)33}3435fn parse_path(path: &str) -> &str {36 strip_prefix_suffix(path, "\x1b[35;1m", "\x1b[0m").unwrap_or(path)37}3839fn parse_drv(drv: &str) -> &str {40 let drv = parse_path(drv);41 if let Some(pkg) = drv.strip_prefix("/nix/store/") {42 let mut it = pkg.splitn(2, '-');43 it.next();44 if let Some(pkg) = it.next() {45 return pkg;46 }47 }48 drv49}50fn parse_host(host: &str) -> &str {51 if host.is_empty() || host == "local" {52 return "local";53 }54 // https/ssh is the default55 host.strip_prefix("https://").unwrap_or(host)56}5758impl ActivityType {59 fn name(&self) -> &'static str {60 match self {61 ActivityType::Unknown => "nix",62 ActivityType::CopyPath => "nix::copy-path",63 ActivityType::FileTransfer => "nix::file-transfer",64 ActivityType::Realise => "nix::realise",65 ActivityType::CopyPaths => "nix::copy-paths",66 ActivityType::Builds => "nix::builds",67 ActivityType::Build => "nix::build",68 ActivityType::OptimiseStore => "nix::optimise-store",69 ActivityType::VerifyPaths => "nix::verify-paths",70 ActivityType::Substitute => "nix::substitute",71 ActivityType::QueryPathInfo => "nix::query-path-info",72 ActivityType::PostBuildHook => "nix::post-build-hook",73 ActivityType::BuildWaiting => "nix::build-waiting",74 ActivityType::FetchTree => "nix::fetch-tree",75 }76 }77 fn format(78 &self,79 values: &[FieldValue],80 s: &str,81 into: impl FnOnce(Arguments<'_>) -> Span,82 ) -> Span {83 use FieldValue::*;84 match (self, values) {85 (ActivityType::QueryPathInfo, [Str(drv), Str(host)]) => {86 let drv = parse_drv(drv);87 let host = parse_host(host);88 debug_span!(target: "nix::query-path-info", "querying", drv, host)89 }90 (ActivityType::Substitute, [Str(drv), Str(host)]) => {91 let drv = parse_drv(drv);92 let host = parse_host(host);93 debug_span!(target: "nix::substitute", "substituting", drv, host)94 }95 (ActivityType::CopyPath, [Str(drv), Str(from), Str(to)]) => {96 let drv = parse_drv(drv);97 let from = parse_host(from);98 let to = parse_host(to);99 debug_span!(target: "nix::copy-path", "copying", drv, from, to)100 }101 (ActivityType::Build, [Str(drv), Str(host), Int(_), Int(_)]) => {102 let drv = parse_drv(drv);103 let host = parse_host(host);104 info_span!(target: "nix::build", "building", drv, host)105 }106 (ActivityType::FileTransfer, [Str(file)]) => {107 info_span!(target: "nix::file-transfer", "downloading", file)108 }109 (ActivityType::Realise, []) => {110 debug_span!(target: "nix::realise", "realising")111 }112 (ActivityType::CopyPaths, []) => {113 debug_span!(target: "nix::copy-paths", "copying paths")114 }115 (ActivityType::Unknown, [])116 if s.starts_with("copying \"") && s.ends_with("\" to the store") =>117 {118 let tree = s119 .trim_start_matches("copying \"")120 .trim_end_matches("\" to the store");121 debug_span!(target: "nix::trees", "copying", tree)122 }123 (ActivityType::Unknown, [])124 if s.starts_with("copying '") && s.ends_with("' to the store") =>125 {126 let tree = s127 .trim_start_matches("copying '")128 .trim_end_matches("' to the store");129 debug_span!(target: "nix::trees", "copying", tree)130 }131 (ActivityType::Unknown, []) if s.starts_with("hashing '") && s.ends_with("'") => {132 let tree = s.trim_start_matches("hashing '").trim_end_matches("'");133 debug_span!(target: "nix::trees", "hashing", tree)134 }135 (ActivityType::Unknown, []) if s.starts_with("connecting to '") && s.ends_with("'") => {136 let host = s137 .trim_start_matches("connecting to '")138 .trim_end_matches("'");139 debug_span!(target: "nix::remote", "connecting", host)140 }141 (ActivityType::Unknown, [])142 if s.starts_with("copying outputs from '") && s.ends_with("'") =>143 {144 let host = s145 .trim_start_matches("copying outputs from '")146 .trim_end_matches("'");147 debug_span!(target: "nix::remote", "copying outputs", host)148 }149 (ActivityType::Unknown, [])150 if s.starts_with("copying dependencies to '") && s.ends_with("'") =>151 {152 let host = s153 .trim_start_matches("copying dependencies to '")154 .trim_end_matches("'");155 debug_span!(target: "nix::remote", "copying dependencies", host)156 }157 (ActivityType::Unknown, [])158 if s.starts_with("waiting for the upload lock to '") && s.ends_with("'") =>159 {160 let host = s161 .trim_start_matches("waiting for the upload lock to '")162 .trim_end_matches("'");163 debug_span!(target: "nix::remote", "waiting for upload lock", host)164 }165 (ActivityType::BuildWaiting, [])166 if s.starts_with("waiting for a machine to build '") && s.ends_with("'") =>167 {168 let drv = parse_drv(169 s.trim_start_matches("waiting for a machine to build '")170 .trim_end_matches("'"),171 );172 debug_span!(target: "nix::build-waiting", "waiting for available builder", drv)173 }174 (ActivityType::Unknown, []) if s == "querying info about missing paths" => {175 debug_span!(target: "nix::remote", "querying")176 }177 _ => into(format_args!("{}({values:?})", self.name())),178 }179 }180 fn from_int(v: u32) -> Self {181 match v {182 0 => Self::Unknown,183 100 => Self::CopyPath,184 101 => Self::FileTransfer,185 102 => Self::Realise,186 103 => Self::CopyPaths,187 104 => Self::Builds,188 105 => Self::Build,189 106 => Self::OptimiseStore,190 107 => Self::VerifyPaths,191 108 => Self::Substitute,192 109 => Self::QueryPathInfo,193 110 => Self::PostBuildHook,194 111 => Self::BuildWaiting,195 112 => Self::FetchTree,196 _ => {197 warn!("unknown nix action: {v}");198 Self::Unknown199 }200 }201 }202}203204#[derive(Debug)]205enum ResultType {206 FileLinked = 100,207 BuildLogLine = 101,208 UntrustedPath = 102,209 CorruptedPath = 103,210 SetPhase = 104,211 Progress = 105,212 SetExpected = 106,213 PostBuildLogLine = 107,214 FetchStatus = 108,215216 Unknown = 999,217}218impl ResultType {219 fn from_int(v: u32) -> Self {220 match v {221 100 => Self::FileLinked,222 101 => Self::BuildLogLine,223 102 => Self::UntrustedPath,224 103 => Self::CorruptedPath,225 104 => Self::SetPhase,226 105 => Self::Progress,227 106 => Self::SetExpected,228 107 => Self::PostBuildLogLine,229 108 => Self::FetchStatus,230231 _ => {232 warn!("unknown nix result: {v}");233 Self::Unknown234 }235 }236 }237}238#[derive(Clone, Copy)]239enum Verbosity {240 Error,241 Warn,242 Notice,243 Info,244 Talkative,245 Chatty,246 Debug,247 Vomit,248}249impl From<Verbosity> for tracing::Level {250 fn from(val: Verbosity) -> Self {251 match val {252 Verbosity::Error => Level::ERROR,253 Verbosity::Warn => Level::WARN,254 Verbosity::Notice => Level::WARN,255 Verbosity::Info => Level::INFO,256 Verbosity::Talkative => Level::DEBUG,257 Verbosity::Chatty => Level::DEBUG,258 Verbosity::Debug => Level::DEBUG,259 Verbosity::Vomit => Level::TRACE,260 }261 }262}263impl Verbosity {264 fn from_int(u: u32) -> Self {265 [266 Self::Error,267 Self::Warn,268 Self::Notice,269 Self::Info,270 Self::Talkative,271 Self::Chatty,272 Self::Debug,273 Self::Vomit,274 ]275 .get(u as usize)276 .cloned()277 .unwrap_or_else(|| {278 warn!("unknown log level: {u}");279 Verbosity::Vomit280 })281 }282}283284static NIX_SPAN_MAPPING: LazyLock<Mutex<HashMap<u64, Span>>> =285 LazyLock::new(|| Mutex::new(HashMap::new()));286287#[derive(Debug)]288enum FieldValue {289 Int(i32),290 Str(String),291}292293struct StartActivityBuilder {294 activity_id: u64,295 verbosity: Verbosity,296 typ: ActivityType,297 fields: Vec<FieldValue>,298}299impl StartActivityBuilder {300 fn add_int_field(&mut self, i: i32) {301 self.fields.push(FieldValue::Int(i));302 }303 fn add_string_field(&mut self, v: &str) {304 self.fields.push(FieldValue::Str(v.to_owned()));305 }306 fn emit(&mut self, parent: u64, s: &str) {307 let mut mapping = NIX_SPAN_MAPPING.lock().expect("not poisoned");308309 let parent = mapping.get(&parent);310311 // let meta = spans.alloc_metadata(312 // self.typ.name(),313 // self.verbosity.into(),314 // MetadataKind::Span,315 // "nix activity start",316 // None,317 // None,318 // None,319 // self.typ.fields(),320 // );321 //322 // let mut fields = meta.fields().iter();323 // let span = if let Some(parent) = parent {324 // let s = Span::new(325 // meta,326 // &match meta.fields().len() {327 // 1 => meta.fields().value_set(328 // &<[_; 1]>::try_from([(329 // &fields.next().expect("has field"),330 // Some(&format_args!("Test") as &dyn tracing::Value),331 // )])332 // .expect("valid size"),333 // ),334 // _ => unreachable!(),335 // },336 // );337 // s.follows_from(parent);338 // s339 // } else {340 // Span::new_root(341 // meta,342 // &match meta.fields().len() {343 // 1 => meta.fields().value_set(344 // &<[_; 1]>::try_from([(345 // &fields.next().expect("has field"),346 // Some(&format_args!("Test") as &dyn tracing::Value),347 // )])348 // .expect("valid size"),349 // ),350 // _ => unreachable!(),351 // },352 // )353 // };354 //355 // let id = span.id().expect("id created");356357 let span = {358 let _in_parent = parent.map(|p| p.enter());359 let level: Level = self.verbosity.into();360 if level == Level::ERROR {361 self.typ362 .format(&self.fields, s, |v| error_span!("action", v))363 } else if level == Level::WARN {364 self.typ365 .format(&self.fields, s, |v| warn_span!("action", v))366 } else if level == Level::INFO {367 self.typ368 .format(&self.fields, s, |v| info_span!("action", v))369 } else if level == Level::DEBUG {370 self.typ371 .format(&self.fields, s, |v| debug_span!("action", v))372 } else {373 self.typ374 .format(&self.fields, s, |v| trace_span!("action", v))375 }376 };377 if !s.trim().is_empty() {378 let s = ansi_filter(s);379 #[cfg(feature = "indicatif")]380 {381 span.pb_set_message(s);382 }383 let _e = span.enter();384 let level: Level = self.verbosity.into();385 if level == Level::ERROR {386 error!(target: "nix", "{}", s)387 } else if level == Level::WARN {388 warn!(target: "nix", "{}", s)389 } else if level == Level::INFO {390 info!(target: "nix", "{}", s)391 } else if level == Level::DEBUG {392 debug!(target: "nix", "{}", s)393 } else {394 trace!(target: "nix", "{}", s)395 }396 } else {397 #[cfg(feature = "indicatif")]398 {399 span.pb_start();400 }401 }402 mapping.insert(self.activity_id, span);403 }404 fn emit_result(&mut self, ty: u32) {405 let mapping = NIX_SPAN_MAPPING.lock().expect("not poisoned");406407 let Some(parent) = mapping.get(&self.activity_id) else {408 panic!("unexpected result for dead parent");409 };410411 let _in_parent = parent.enter();412 let res = ResultType::from_int(ty);413414 use FieldValue::*;415 match (&res, self.fields.as_slice()) {416 // ResultType::FileLinked => todo!(),417 (ResultType::BuildLogLine, [Str(s)]) => {418 let s = ansi_filter(s);419 info!("{s}");420 }421 // ResultType::UntrustedPath => todo!(),422 // ResultType::CorruptedPath => todo!(),423 // ResultType::SetPhase => todo!(),424 (ResultType::SetExpected, [Int(act_ty), Int(_expected)]) => {425 let _act_ty = ActivityType::from_int(*act_ty as u32);426 }427 (ResultType::SetPhase, [Str(phase)]) => {428 // parent.pb_set_message(phase);429 debug!(target: "nix::phase", phase)430 }431 (ResultType::Progress, [Int(_done), Int(_expected), Int(_), Int(_)]) => {432 #[cfg(feature = "indicatif")]433 {434 parent.pb_set_length(*_expected as u64);435 parent.pb_set_position(*_done as u64);436 }437 }438 _ => warn!("unknown progress report: {:?}({:?})", &res, &self.fields),439 }440 }441}442fn new_start_activity(activity_id: u64, lvl: u32, typ: u32) -> Box<StartActivityBuilder> {443 Box::new(StartActivityBuilder {444 activity_id,445 verbosity: Verbosity::from_int(lvl),446 typ: ActivityType::from_int(typ),447 fields: vec![],448 })449}450451fn emit_warn(v: &str) {452 warn!(target: "nix::eval", "{v}")453}454fn emit_stop(v: u64) {455 let mut mapping = NIX_SPAN_MAPPING.lock().expect("not poisoned");456 mapping.remove(&v);457}458fn emit_log(lvl: u32, v: &str) {459 let verbosity = Verbosity::from_int(lvl);460 let level: Level = verbosity.into();461 if level == Level::ERROR {462 error!(target: "nix", "{v}")463 } else if level == Level::WARN {464 warn!(target: "nix", "{v}")465 } else if level == Level::INFO {466 info!(target: "nix", "{v}")467 } else if level == Level::DEBUG {468 debug!(target: "nix", "{v}")469 } else {470 trace!(target: "nix", "{v}")471 }472}473474struct AnsiFiltered {475 output: String,476}477impl vte::Perform for AnsiFiltered {478 fn print(&mut self, c: char) {479 self.output.push(c);480 }481482 fn execute(&mut self, byte: u8) {483 // We don't want \r, bells, etc484 if byte == b'\n' {485 self.output.push('\n');486 } else if byte == b'\t' {487 // TODO: align output to the correct multiplier?488 self.output.push('\t');489 }490 }491492 fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {}493 fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {}494495 fn csi_dispatch(496 &mut self,497 params: &vte::Params,498 _intermediates: &[u8],499 _ignore: bool,500 action: char,501 ) {502 use std::fmt::Write;503 if action != 'm' {504 // Only plain colors are enabled, everything other might corrupt the output505 return;506 }507 self.output.push_str("\x1b[");508 for (i, par) in params.iter().enumerate() {509 if i != 0 {510 let _ = write!(self.output, ";");511 }512 for (i, sub) in par.iter().enumerate() {513 if i != 0 {514 let _ = write!(self.output, ":");515 }516 let _ = write!(self.output, "{sub}");517 }518 }519 self.output.push(action);520 }521}522fn ansi_filter(i: &str) -> String {523 let mut out = AnsiFiltered {524 output: String::new(),525 };526 let mut parser = Parser::new();527528 // For some reason it gets stuck with longer inputs529 for chunk in i.as_bytes().chunks(50) {530 parser.advance(&mut out, chunk);531 }532533 out.output534}535536#[cxx::bridge]537pub mod nix_logging_cxx {538 extern "Rust" {539 type StartActivityBuilder;540 fn new_start_activity(activity_id: u64, lvl: u32, typ: u32) -> Box<StartActivityBuilder>;541 fn add_int_field(&mut self, i: i32);542 fn add_string_field(&mut self, v: &str);543 fn emit(&mut self, parent: u64, s: &str);544 fn emit_result(&mut self, ty: u32);545546 fn emit_warn(v: &str);547 fn emit_stop(id: u64);548 fn emit_log(lvl: u32, v: &str);549 }550 unsafe extern "C++" {551 include!("nix-eval/src/logging.hh");552553 fn apply_tracing_logger();554 }555}crates/nixlike/Cargo.tomldiffbeforeafterboth--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -7,7 +7,6 @@
[dependencies]
thiserror.workspace = true
-alejandra = { git = "https://github.com/kamadorueda/alejandra" }
linked-hash-map = "0.5.6"
peg = "0.8.5"
ron = "0.11.0"
crates/nixlike/src/lib.rsdiffbeforeafterboth--- a/crates/nixlike/src/lib.rs
+++ b/crates/nixlike/src/lib.rs
@@ -5,7 +5,6 @@
//! expressions and expect it to work, only basic primitives are supported, and there is no
//! variables/recursive records, interpolation, e.t.c.
-use alejandra::config::Indentation;
use linked_hash_map::LinkedHashMap;
use peg::str::LineCol;
use se_impl::MySerialize;
@@ -197,14 +196,8 @@
assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"\n");
}
pub fn format_nix(value: &String) -> String {
- let (_, out) = alejandra::format::in_memory(
- "".to_owned(),
- value.to_owned(),
- alejandra::config::Config {
- indentation: Indentation::TwoSpaces,
- },
- );
- out
+ // TODO
+ value.to_owned()
}
#[test]
crates/nixlike/src/to_string.rsdiffbeforeafterboth--- a/crates/nixlike/src/to_string.rs
+++ b/crates/nixlike/src/to_string.rs
@@ -1,5 +1,3 @@
-use alejandra::config::Indentation;
-
use crate::Value;
pub fn write_identifier(k: &str, out: &mut String) {
@@ -100,12 +98,5 @@
pub fn write_nix(value: &Value) -> String {
let mut out = String::new();
write_nix_buf(value, &mut out);
- let (_, out) = alejandra::format::in_memory(
- "".to_owned(),
- out,
- alejandra::config::Config {
- indentation: Indentation::TwoSpaces,
- },
- );
out
}
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -114,7 +114,13 @@
{
_module.args.pkgs = import inputs.nixpkgs {
inherit system;
- overlays = [ (inputs.rust-overlay.overlays.default) ];
+ overlays = [ (inputs.rust-overlay.overlays.default) (final: prev: {
+ boehmgc = prev.boehmgc.overrideAttrs (prevAttrs: {
+ configureFlags = prevAttrs.configureFlags ++ [
+ "--enable-gc-assertions"
+ ];
+ });
+ }) ];
};
# Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.
packages = lib.mkIf deployerSystem (
@@ -157,7 +163,6 @@
factory = craneLib.devShell;
packages = with pkgs; [
rust
- alejandra
cargo-edit
cargo-udeps
cargo-fuzz