Add support for converting between libnix and harmonia derivations

This commit is contained in:
Artemis Tosini 2026-01-15 09:26:14 -05:00 committed by John Ericson
parent aae065cb3e
commit 714dcd95c0
3 changed files with 108 additions and 1 deletions

View file

@ -19,6 +19,7 @@ nix-bindings-store-sys = { path = "../nix-bindings-store-sys", version = "0.2.1"
lazy_static = "1.4"
zerocopy = "0.8"
harmonia-store-core = { version = "0.0.0-alpha.0", optional = true }
serde_json = { version = "1.0", optional = true }
[dev-dependencies]
ctor = "0.2"
@ -32,7 +33,7 @@ pkg-config = "0.3"
nix-bindings-util = { path = "../nix-bindings-util", version = "0.2.1" }
[features]
harmonia = [ "dep:harmonia-store-core" ]
harmonia = [ "dep:harmonia-store-core", "dep:serde_json" ]
[lints.rust]
warnings = "deny"

View file

@ -0,0 +1,100 @@
use anyhow::Context as _;
use super::Derivation;
impl Derivation {
/// Convert harmonia Derivation to nix-bindings Derivation.
///
/// This requires a Store instance because the Nix C API needs it for internal validation.
pub fn from_harmonia(
store: &mut crate::store::Store,
harmonia_drv: &harmonia_store_core::derivation::Derivation,
) -> anyhow::Result<Self> {
let json = serde_json::to_string(harmonia_drv)
.context("Failed to serialize harmonia Derivation to JSON")?;
store.derivation_from_json(&json)
}
}
impl TryFrom<&Derivation> for harmonia_store_core::derivation::Derivation {
type Error = anyhow::Error;
fn try_from(nix_drv: &Derivation) -> anyhow::Result<Self> {
let json = nix_drv
.to_json_string()
.context("Failed to convert nix Derivation to JSON")?;
serde_json::from_str(&json).context("Failed to parse JSON as harmonia Derivation")
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_harmonia_derivation() -> harmonia_store_core::derivation::Derivation {
use harmonia_store_core::derivation::{Derivation, DerivationOutput};
use harmonia_store_core::derived_path::OutputName;
use harmonia_store_core::store_path::StorePath;
use std::collections::{BTreeMap, BTreeSet};
use std::str::FromStr;
let system = format!("{}-{}", std::env::consts::ARCH, std::env::consts::OS);
let out_path = "8bs8sd27bzzy6w94fznjd2j8ldmdg7x6-myname";
let env = BTreeMap::from([
("builder".into(), "/bin/sh".into()),
("name".into(), "myname".into()),
("out".into(), format!("/{out_path}").into()),
("system".into(), system.clone().into()),
]);
let mut outputs = BTreeMap::new();
outputs.insert(
OutputName::from_str("out").unwrap(),
DerivationOutput::InputAddressed(StorePath::from_base_path(out_path).unwrap()),
);
Derivation {
args: vec!["-c".into(), "echo $name foo > $out".into()],
builder: "/bin/sh".into(),
env,
inputs: BTreeSet::new(),
name: b"myname".as_slice().try_into().unwrap(),
outputs,
platform: system.into(),
structured_attrs: None,
}
}
#[test]
fn derivation_round_trip_harmonia() {
let mut store = crate::store::Store::open(Some("dummy://"), []).unwrap();
let harmonia_drv = create_harmonia_derivation();
// Convert to nix-bindings Derivation
let nix_drv = Derivation::from_harmonia(&mut store, &harmonia_drv).unwrap();
// Convert back to harmonia Derivation
let harmonia_round_trip: harmonia_store_core::derivation::Derivation =
(&nix_drv).try_into().unwrap();
assert_eq!(harmonia_drv, harmonia_round_trip);
}
#[test]
fn derivation_clone() {
let mut store = crate::store::Store::open(Some("dummy://"), []).unwrap();
let harmonia_drv = create_harmonia_derivation();
let derivation = Derivation::from_harmonia(&mut store, &harmonia_drv).unwrap();
let cloned_derivation = derivation.clone();
let original_harmonia: harmonia_store_core::derivation::Derivation =
(&derivation).try_into().unwrap();
let cloned_harmonia: harmonia_store_core::derivation::Derivation =
(&cloned_derivation).try_into().unwrap();
assert_eq!(original_harmonia, cloned_harmonia);
}
}

View file

@ -84,3 +84,9 @@ impl Drop for Derivation {
}
}
}
#[cfg(feature = "harmonia")]
mod harmonia;
#[cfg(test)]
mod tests {}