use crate::lockfile::ContentHash;
use crate::{PackageId, Version};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Derivation {
pub name: String,
pub version: Version,
pub package_id: PackageId,
pub inputs: Vec<DerivationRef>,
pub build: BuildScript,
pub cache_key: ContentHash,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct DerivationRef {
pub name: String,
pub cache_key: ContentHash,
}
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct BuildScript {
pub steps: Vec<BuildStep>,
#[serde(default)]
pub env: indexmap::IndexMap<String, String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BuildStep {
pub kind: BuildStepKind,
pub command: BuildCommand,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum BuildStepKind {
Fetch,
PreUnpack,
Unpack,
PostUnpack,
Patch,
PreConfigure,
Configure,
PostConfigure,
PreBuild,
Build,
PostBuild,
PreCheck,
Check,
PostCheck,
PreInstall,
Install,
PostInstall,
Custom { name: String },
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "kebab-case")]
pub enum BuildCommand {
Cargo {
subcommand: String,
args: Vec<String>,
},
Npm {
manager: String,
subcommand: String,
args: Vec<String>,
},
Pip {
subcommand: String,
args: Vec<String>,
},
Gem {
subcommand: String,
args: Vec<String>,
},
Go {
subcommand: String,
args: Vec<String>,
},
Make { target: String, env: indexmap::IndexMap<String, String> },
Copy { from: String, to: String },
Mkdir { path: String },
Symlink { target: String, link_name: String },
Native {
program: String,
args: Vec<String>,
},
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Registry;
#[test]
fn derivation_round_trips_through_serde() {
let d = Derivation {
name: "serde-1.0.228".into(),
version: Version::new(1, 0, 228),
package_id: PackageId {
name: "serde".into(),
version: Version::new(1, 0, 228),
registry: Registry::CratesIo,
},
inputs: vec![],
build: BuildScript {
steps: vec![BuildStep {
kind: BuildStepKind::Build,
command: BuildCommand::Cargo {
subcommand: "build".into(),
args: vec!["--release".into()],
},
}],
env: indexmap::IndexMap::new(),
},
cache_key: ContentHash::of(b"snapshot"),
};
let j = serde_json::to_string(&d).unwrap();
let parsed: Derivation = serde_json::from_str(&j).unwrap();
assert_eq!(d, parsed);
}
#[test]
fn build_command_variants_round_trip() {
let commands = vec![
BuildCommand::Cargo {
subcommand: "build".into(),
args: vec![],
},
BuildCommand::Npm {
manager: "pnpm".into(),
subcommand: "install".into(),
args: vec![],
},
BuildCommand::Copy {
from: "/src".into(),
to: "/out".into(),
},
];
for c in commands {
let j = serde_json::to_string(&c).unwrap();
let parsed: BuildCommand = serde_json::from_str(&j).unwrap();
assert_eq!(c, parsed);
}
}
}