nix_query_tree_viewer/nix_query_tree.rs
1pub mod exec_nix_store;
2pub mod parsing;
3
4use super::tree::{Path, Tree, TreePathMap};
5use std::path::PathBuf;
6use std::str::FromStr;
7
8/// This corresponds to a nix store path.
9///
10/// ```
11/// use nix_query_tree_viewer::nix_query_tree::NixQueryDrv;
12///
13/// let nix_query_drv =
14/// NixQueryDrv::from("/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10");
15/// ```
16#[derive(Clone, Debug, Eq, Hash, PartialEq)]
17pub struct NixQueryDrv(PathBuf);
18
19impl<T: ?Sized + AsRef<std::ffi::OsStr>> From<&T> for NixQueryDrv {
20 fn from(s: &T) -> NixQueryDrv {
21 NixQueryDrv(PathBuf::from(s.as_ref().to_os_string()))
22 }
23}
24
25impl std::ops::Deref for NixQueryDrv {
26 type Target = std::path::Path;
27
28 fn deref(&self) -> &std::path::Path {
29 &self.0
30 }
31}
32
33impl NixQueryDrv {
34 pub fn cmp_hash(&self, other: &Self) -> std::cmp::Ordering {
35 self.0.cmp(&other.0)
36 }
37
38 pub fn cmp_drv_name(&self, other: &Self) -> std::cmp::Ordering {
39 self.drv_name().cmp(&other.drv_name())
40 }
41
42 /// Pull out the hash and derivation name from a `NixQueryDrv`
43 ///
44 /// ```
45 /// use nix_query_tree_viewer::nix_query_tree::NixQueryDrv;
46 ///
47 /// let nix_query_drv =
48 /// NixQueryDrv::from("/nix/store/az4kl5slhbkmmy4vj98z3hzxxkan7zza-gnugrep-3.3");
49 /// assert_eq!(
50 /// nix_query_drv.hash_and_drv_name(),
51 /// String::from("az4kl5slhbkmmy4vj98z3hzxxkan7zza-gnugrep-3.3")
52 /// );
53 /// ```
54 pub fn hash_and_drv_name(&self) -> String {
55 let drv_str = self.0.to_string_lossy();
56 String::from((drv_str).trim_start_matches("/nix/store/"))
57 }
58
59 /// Pull out a truncated hash and derivation name from a `NixQueryDrv`
60 ///
61 /// ```
62 /// use nix_query_tree_viewer::nix_query_tree::NixQueryDrv;
63 ///
64 /// let nix_query_drv =
65 /// NixQueryDrv::from("/nix/store/az4kl5slhbkmmy4vj98z3hzxxkan7zza-gnugrep-3.3");
66 /// assert_eq!(
67 /// nix_query_drv.short_hash_and_drv_name(),
68 /// String::from("az4kl5s..gnugrep-3.3")
69 /// );
70 /// ```
71 pub fn short_hash_and_drv_name(&self) -> String {
72 let drv_str = self.0.to_string_lossy();
73 let drv_str_no_store =
74 String::from(drv_str.trim_start_matches("/nix/store/"));
75 let option_drv_name = drv_str_no_store
76 .find('-')
77 .and_then(|i| drv_str_no_store.get(i + 1..));
78 let option_short_hash = drv_str_no_store.get(0..7);
79 match (option_drv_name, option_short_hash) {
80 (Some(drv_name), Some(short_hash)) => {
81 format!("{}..{}", short_hash, drv_name)
82 }
83 _ => panic!("Ill-formed nix path"),
84 }
85 }
86
87 /// Pull out a derivation name from a `NixQueryDrv`.
88 ///
89 /// ```
90 /// use nix_query_tree_viewer::nix_query_tree::NixQueryDrv;
91 ///
92 /// let nix_query_drv =
93 /// NixQueryDrv::from("/nix/store/az4kl5slhbkmmy4vj98z3hzxxkan7zza-gnugrep-3.3");
94 /// assert_eq!(nix_query_drv.drv_name(), String::from("gnugrep-3.3"));
95 /// ```
96 ///
97 /// * Panics
98 ///
99 /// This panics if the derivation name doesn't have a `-` in it. All nix derivations have
100 /// a `-` in them after the hash.
101 pub fn drv_name(&self) -> String {
102 let drv_str = self.0.to_string_lossy();
103 let option_dash_index = drv_str.find('-');
104 match option_dash_index {
105 None => drv_str.into_owned(),
106 Some(dash_index) => {
107 let option_just_drv_name = drv_str.get(dash_index + 1..);
108 match option_just_drv_name {
109 None => {
110 panic!("Nix paths will always have a dash in them.")
111 }
112 Some(drv_name) => drv_name.to_string(),
113 }
114 }
115 }
116 }
117}
118
119impl FromStr for NixQueryDrv {
120 // This should really be never.
121 type Err = ();
122
123 fn from_str(s: &str) -> Result<Self, Self::Err> {
124 Ok(s.into())
125 }
126}
127
128impl std::fmt::Display for NixQueryDrv {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 write!(f, "{}", self.0.to_string_lossy())
131 }
132}
133
134/// Whether or not there is a separate entry in this tree that recurses into the dependencies for
135/// this nix store entry.
136///
137/// See `NixQueryEntry`.
138#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
139pub enum Recurse {
140 Yes,
141 No,
142}
143
144/// `NixQueryDrv` coupled with a marker for a recursive entry.
145///
146/// ```
147/// use nix_query_tree_viewer::nix_query_tree::{NixQueryEntry, Recurse};
148/// use std::str::FromStr;
149///
150/// let nix_query_entry =
151/// NixQueryEntry::from_str("/nix/store/az4kl5slhbkmmy4vj98z3hzxxkan7zza-gnugrep-3.3 [...]");
152/// let actual_nix_query_entry =
153/// NixQueryEntry::new("/nix/store/az4kl5slhbkmmy4vj98z3hzxxkan7zza-gnugrep-3.3", Recurse::Yes);
154/// assert_eq!(nix_query_entry, Ok(actual_nix_query_entry));
155/// ```
156///
157#[derive(Clone, Debug, Eq, Hash, PartialEq)]
158pub struct NixQueryEntry(pub NixQueryDrv, pub Recurse);
159
160impl FromStr for NixQueryEntry {
161 type Err = nom::Err<(String, nom::error::ErrorKind)>;
162
163 fn from_str(s: &str) -> Result<Self, Self::Err> {
164 parsing::nix_query_entry_parser(s).map_err(|err| err.to_owned())
165 }
166}
167
168impl std::ops::Deref for NixQueryEntry {
169 type Target = std::path::Path;
170
171 fn deref(&self) -> &std::path::Path {
172 &self.0
173 }
174}
175
176impl NixQueryEntry {
177 pub fn new<T>(nix_query_drv: &T, recurse: Recurse) -> NixQueryEntry
178 where
179 T: ?Sized + AsRef<std::ffi::OsStr>,
180 {
181 NixQueryEntry(NixQueryDrv::from(nix_query_drv), recurse)
182 }
183
184 pub fn cmp_hash(&self, other: &Self) -> std::cmp::Ordering {
185 self.0.cmp_hash(&other.0)
186 }
187
188 pub fn cmp_drv_name(&self, other: &Self) -> std::cmp::Ordering {
189 self.0.cmp_drv_name(&other.0)
190 }
191
192 pub fn hash_and_drv_name(&self) -> String {
193 self.0.hash_and_drv_name()
194 }
195
196 pub fn short_hash_and_drv_name(&self) -> String {
197 self.0.short_hash_and_drv_name()
198 }
199
200 pub fn drv_name(&self) -> String {
201 self.0.drv_name()
202 }
203}
204
205/// A `Tree` representing the result from `nix store --query --tree`.
206///
207/// ```
208/// use indoc::indoc;
209/// use nix_query_tree_viewer::nix_query_tree::NixQueryTree;
210/// use std::str::FromStr;
211///
212/// let raw_tree = indoc!(
213/// "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
214/// +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27
215/// | +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
216/// +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
217/// "
218/// );
219/// let nix_query_tree = NixQueryTree::from_str(raw_tree);
220///
221/// assert!(nix_query_tree.is_ok());
222/// ```
223#[derive(Clone, Debug, Eq, PartialEq)]
224pub struct NixQueryTree(pub Tree<NixQueryEntry>);
225
226impl NixQueryTree {
227 pub fn path_map(&self) -> NixQueryPathMap {
228 let tree: &Tree<NixQueryEntry> = &self.0;
229 let tree_path_map =
230 tree.path_map_map(&|nix_query_entry| nix_query_entry.0.clone());
231 NixQueryPathMap(tree_path_map)
232 }
233
234 pub fn lookup(&self, path: Path) -> Option<&NixQueryEntry> {
235 self.0.lookup(path)
236 }
237}
238
239impl FromStr for NixQueryTree {
240 type Err = nom::Err<(String, nom::error::ErrorKind)>;
241
242 fn from_str(s: &str) -> Result<Self, Self::Err> {
243 parsing::nix_query_tree_parser(s).map_err(|err| err.to_owned())
244 }
245}
246
247/// A mapping of `NixQueryDrv` to `TreePath`. This gives an easy way to
248/// figure out where a `NixQueryDrv` is an a `NixQueryTree`.
249///
250/// ```
251/// use indoc::indoc;
252/// use nix_query_tree_viewer::nix_query_tree::{NixQueryDrv, NixQueryTree};
253/// use nix_query_tree_viewer::tree::Path;
254/// use std::str::FromStr;
255///
256/// let raw_tree = indoc!(
257/// "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
258/// +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27
259/// | +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
260/// +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
261/// +---/nix/store/9ny6szla9dg61jv8q22qbnqsz37465n0-multiple-outputs.sh
262/// +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
263/// +---/nix/store/5wvmvcc3b7sisirx1vsqbqdis0sd1x5d-cc-wrapper.sh
264/// +---/nix/store/5jzbjvnrz85n454inlyxcpgap9i6k6la-pcre-8.43
265/// "
266/// );
267/// let nix_query_tree = NixQueryTree::from_str(raw_tree).unwrap();
268/// let map = nix_query_tree.path_map();
269/// let pcre_drv = NixQueryDrv::from("/nix/store/5jzbjvnrz85n454inlyxcpgap9i6k6la-pcre-8.43");
270/// let expected_path = Some(Path::from(vec![2, 0, 1]));
271///
272/// assert_eq!(map.lookup_first(&pcre_drv), expected_path.as_ref());
273/// ```
274#[derive(Clone, Debug, Eq, PartialEq)]
275pub struct NixQueryPathMap(pub TreePathMap<NixQueryDrv>);
276
277impl NixQueryPathMap {
278 pub fn lookup_first(&self, k: &NixQueryDrv) -> Option<&Path> {
279 self.0.lookup_first(k)
280 }
281}