use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use anyhow::Context as _;
use serde::{Deserialize, Serialize};
use tracing::debug;
mod eval;
mod master;
mod worker;
pub const WORKER_ENV: &str = "EVIX_WORKER";
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Input {
Flake(String),
Expr(String),
File(PathBuf),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AutoArg {
Expr(String),
Str(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub input: Input,
pub auto_args: Vec<(String, AutoArg)>,
pub force_recurse: bool,
pub gc_roots_dir: Option<PathBuf>,
pub workers: usize,
pub max_memory_size: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Derivation {
pub attr: String,
pub attr_path: Vec<String>,
pub name: String,
pub system: String,
pub drv_path: String,
pub outputs: BTreeMap<String, Option<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gc_root_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvalError {
pub attr: String,
pub attr_path: Vec<String>,
pub error: String,
pub fatal: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Event {
Derivation(Derivation),
AttrSet {
attr: String,
attr_path: Vec<String>,
attrs: Vec<String>,
},
Error(EvalError),
}
impl Event {
pub fn attr(&self) -> &str {
match self {
Event::Derivation(d) => &d.attr,
Event::AttrSet { attr, .. } => attr,
Event::Error(e) => &e.attr,
}
}
pub fn attr_path(&self) -> &[String] {
match self {
Event::Derivation(d) => &d.attr_path,
Event::AttrSet { attr_path, .. } => attr_path,
Event::Error(e) => &e.attr_path,
}
}
}
pub fn evaluate<F>(config: &Config, sink: F) -> anyhow::Result<()>
where
F: FnMut(&Event) -> anyhow::Result<()> + Send + 'static,
{
debug!("evaluating input, {} workers", config.workers);
if let Some(dir) = &config.gc_roots_dir {
std::fs::create_dir_all(dir).with_context(|| format!("creating gc-roots dir {dir:?}"))?;
debug!("ensured gc-roots directory exists");
}
let sink = Arc::new(Mutex::new(sink));
master::run(config, sink)
}
pub fn run_worker() -> anyhow::Result<()> {
worker::run()
}