git.delta.rocks / jrsonnet / refs/heads / trunk

difftreelog

source

crates/nix-eval/src/drv.rs3.5 KiBsourcehistory
1use std::collections::{HashMap, HashSet, VecDeque};2use std::ffi::CString;34use anyhow::{Result, bail};5use serde::Deserialize;67use crate::nix_raw::{derivation_free, derivation_to_json, store_drv_from_store_path};8use crate::{copy_nix_str, with_store_context};910fn store_dir() -> Result<String> {11	let mut out = String::new();12	with_store_context(|c, store, _| unsafe {13		crate::nix_raw::store_get_storedir(c, store, Some(copy_nix_str), (&raw mut out).cast())14	})?;15	Ok(out)16}1718fn to_absolute_store_path(store_dir: &str, path: &str) -> String {19	if path.starts_with('/') {20		path.to_owned()21	} else {22		format!("{store_dir}/{path}")23	}24}2526pub struct Derivation(*mut crate::nix_raw::derivation);27unsafe impl Send for Derivation {}2829impl Derivation {30	pub fn from_path(drv_path: &str) -> Result<Self> {31		let path_c = CString::new(drv_path)?;32		let store_path = with_store_context(|c, store, _| unsafe {33			crate::nix_raw::store_parse_path(c, store, path_c.as_ptr())34		})?;35		let drv = with_store_context(|c, store, _| unsafe {36			store_drv_from_store_path(c, store, store_path)37		});38		unsafe { crate::nix_raw::store_path_free(store_path) };39		let drv = drv?;40		if drv.is_null() {41			bail!("failed to read derivation from {drv_path}");42		}43		Ok(Self(drv))44	}4546	pub fn to_json_string(&self) -> Result<String> {47		let mut out = String::new();48		with_store_context(|c, _, _| unsafe {49			derivation_to_json(c, self.0, Some(copy_nix_str), (&raw mut out).cast())50		})?;51		Ok(out)52	}5354	pub fn parsed(&self) -> Result<DrvParsed> {55		let s = self.to_json_string()?;56		Ok(serde_json::from_str(&s)?)57	}58}5960impl Drop for Derivation {61	fn drop(&mut self) {62		unsafe { derivation_free(self.0) };63	}64}6566#[derive(Debug, Deserialize)]67pub struct DrvParsed {68	pub inputs: DrvInputs,69	pub outputs: HashMap<String, serde_json::Value>,70}7172#[derive(Debug, Deserialize)]73pub struct DrvInputs {74	#[serde(default)]75	pub srcs: Vec<String>,76	#[serde(default)]77	pub drvs: HashMap<String, DrvInputEntry>,78}7980#[derive(Debug, Deserialize)]81pub struct DrvInputEntry {82	pub outputs: Vec<String>,83}8485#[derive(Debug)]86pub struct DrvGraph {87	pub root: String,88	pub nodes: HashMap<String, DrvNode>,89}9091#[derive(Debug)]92pub struct DrvNode {93	pub name: String,94	pub input_drvs: HashMap<String, Vec<String>>,95	pub input_srcs: Vec<String>,96	pub outputs: Vec<String>,97}9899impl DrvGraph {100	pub fn resolve(drv_path: &str) -> Result<Self> {101		let sd = store_dir()?;102		let root = to_absolute_store_path(&sd, drv_path);103104		let mut nodes = HashMap::new();105		let mut queue = VecDeque::new();106		let mut visited = HashSet::new();107		queue.push_back(root.clone());108		visited.insert(root.clone());109110		while let Some(path) = queue.pop_front() {111			let drv = Derivation::from_path(&path)?;112			let parsed = drv.parsed()?;113114			let input_drvs: HashMap<String, Vec<String>> = parsed115				.inputs116				.drvs117				.into_iter()118				.map(|(k, v)| (to_absolute_store_path(&sd, &k), v.outputs))119				.collect();120121			for dep_path in input_drvs.keys() {122				if visited.insert(dep_path.clone()) {123					queue.push_back(dep_path.clone());124				}125			}126127			nodes.insert(128				path.clone(),129				DrvNode {130					name: extract_drv_name(&path),131					input_drvs,132					input_srcs: parsed.inputs.srcs,133					outputs: parsed.outputs.into_keys().collect(),134				},135			);136		}137138		Ok(Self { root, nodes })139	}140}141142fn extract_drv_name(drv_path: &str) -> String {143	drv_path144		.rsplit('/')145		.next()146		.and_then(|f| f.strip_suffix(".drv"))147		.and_then(|f| f.split_once('-').map(|(_, name)| name))148		.unwrap_or(drv_path)149		.to_owned()150}