1use tatara_nix::derivation::{BridgeTarget, Derivation};
6
7use crate::set::{PackageLookup, PackageSet, PackageSetError};
8
9pub struct NixpkgsBridge {
13 pub pkg_set: Option<String>,
15 pub known_names: Vec<String>,
18 pub label: String,
20}
21
22impl Default for NixpkgsBridge {
23 fn default() -> Self {
24 Self {
25 pkg_set: None,
26 known_names: vec![],
27 label: "nixpkgs-bridge".into(),
28 }
29 }
30}
31
32impl NixpkgsBridge {
33 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn with_pkg_set(mut self, expr: impl Into<String>) -> Self {
38 self.pkg_set = Some(expr.into());
39 self
40 }
41
42 pub fn with_names(mut self, names: Vec<String>) -> Self {
43 self.known_names = names;
44 self
45 }
46
47 pub fn with_label(mut self, label: impl Into<String>) -> Self {
48 self.label = label.into();
49 self
50 }
51
52 pub fn derivation(&self, attr_path: impl Into<String>) -> Derivation {
55 let attr = attr_path.into();
56 Derivation {
57 name: attr.clone(),
58 version: None,
59 inputs: vec![],
60 source: Default::default(),
61 builder: Default::default(),
62 outputs: Default::default(),
63 env: vec![],
64 sandbox: Default::default(),
65 bridge: Some(BridgeTarget {
66 attr_path: attr,
67 pkg_set: self.pkg_set.clone(),
68 }),
69 nix_expr: None,
70 }
71 }
72}
73
74impl PackageSet for NixpkgsBridge {
75 fn get(&self, name: &str) -> Result<PackageLookup, PackageSetError> {
76 if self.known_names.is_empty() {
78 return Ok(Some(self.derivation(name)));
79 }
80 if self.known_names.iter().any(|n| n == name) {
82 Ok(Some(self.derivation(name)))
83 } else {
84 Ok(None)
85 }
86 }
87
88 fn names(&self) -> Vec<String> {
89 self.known_names.clone()
90 }
91
92 fn label(&self) -> &str {
93 &self.label
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn open_bridge_resolves_anything() {
103 let b = NixpkgsBridge::new();
104 let d = b.get("hello").unwrap().expect("should resolve");
105 assert_eq!(d.name, "hello");
106 assert!(d.bridge.is_some());
107 assert_eq!(d.bridge.as_ref().unwrap().attr_path, "hello");
108 assert!(d.bridge.as_ref().unwrap().pkg_set.is_none());
109 }
110
111 #[test]
112 fn closed_bridge_only_resolves_known_names() {
113 let b = NixpkgsBridge::new().with_names(vec!["hello".into(), "bash".into()]);
114 assert!(b.get("hello").unwrap().is_some());
115 assert!(b.get("nonexistent").unwrap().is_none());
116 assert_eq!(b.names().len(), 2);
117 }
118
119 #[test]
120 fn custom_pkg_set_carries_through() {
121 let b = NixpkgsBridge::new().with_pkg_set("import ./release.nix {}");
122 let d = b.get("mypkg").unwrap().unwrap();
123 assert_eq!(
124 d.bridge.as_ref().unwrap().pkg_set.as_deref(),
125 Some("import ./release.nix {}")
126 );
127 }
128
129 #[test]
130 fn derivation_exposes_dotted_attr_path() {
131 let b = NixpkgsBridge::new();
132 let d = b.derivation("python3Packages.requests");
133 assert_eq!(d.name, "python3Packages.requests");
134 assert_eq!(
135 d.bridge.as_ref().unwrap().attr_path,
136 "python3Packages.requests"
137 );
138 }
139}