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}