nix_query_tree_viewer/nix_query_tree/
parsing.rs1use nom::character::complete::{newline, space1};
2use nom::combinator::complete;
3use nom::multi::{many0, many_m_n};
4use nom::{alt, do_parse, eof, map, named, opt, tag, take_till, IResult};
5
6use super::super::tree::Tree;
7use super::{NixQueryDrv, NixQueryEntry, NixQueryTree, Recurse};
8
9named!(parse_nix_query_drv<&str, NixQueryDrv>,
10 map!(take_till!(char::is_whitespace), NixQueryDrv::from));
11
12named!(parse_recurse<&str, &str>,
13 tag!("[...]"));
14
15named!(parse_nix_query_entry<&str, NixQueryEntry>,
16 do_parse!(
17 drv: parse_nix_query_drv >>
18 opt_recurse: opt!(
19 do_parse!(
20 space1 >>
21 parse_recurse >>
22 (Recurse::Yes)
23 )) >>
24 (NixQueryEntry(drv, opt_recurse.unwrap_or(Recurse::No)))
25 ));
26
27pub fn nix_query_entry_parser(
28 input: &str,
29) -> Result<NixQueryEntry, nom::Err<(&str, nom::error::ErrorKind)>> {
30 parse_nix_query_entry(input).map(|(_, nix_query_entry)| nix_query_entry)
31}
32
33named!(parse_branch_start<&str, &str>,
34 alt!(tag!("+---") | tag!("├───") | tag!("└───")));
35
36named!(parse_extra_level<&str, &str>,
37 alt!(tag!("| ") | tag!(" ") | tag!("│ ")));
38
39fn parse_extra_levels(level: usize) -> impl Fn(&str) -> IResult<&str, ()> {
41 move |input| {
42 let (input, _) = many_m_n(level, level, parse_extra_level)(input)?;
43 Ok((input, ()))
44 }
45}
46
47fn parse_single_branch(
49 level: usize,
50) -> impl Fn(&str) -> IResult<&str, NixQueryEntry> {
51 move |input| {
52 let (input, _) = parse_extra_levels(level)(input)?;
53 let (input, _) = parse_branch_start(input)?;
54 let (input, nix_query_entry) = parse_nix_query_entry(input)?;
55 let (input, _) = newline(input)?;
56 Ok((input, nix_query_entry))
57 }
58}
59
60fn parse_branch_with_children(
62 level: usize,
63) -> impl Fn(&str) -> IResult<&str, Tree<NixQueryEntry>> {
64 move |input| {
65 let (input, nix_query_entry) = parse_single_branch(level)(input)?;
66 let (input, children) = parse_branches(level + 1)(input)?;
67 Ok((input, Tree::new(nix_query_entry, children)))
68 }
69}
70
71fn parse_branches(
72 level: usize,
73) -> impl Fn(&str) -> IResult<&str, Vec<Tree<NixQueryEntry>>> {
74 move |input| {
75 let (input, children) =
76 many0(complete(parse_branch_with_children(level)))(input)?;
77 Ok((input, children))
78 }
79}
80
81fn parse_nix_query_tree(input: &str) -> IResult<&str, NixQueryTree> {
82 let (input, top_drv): (&str, NixQueryDrv) = parse_nix_query_drv(input)?;
83 let (input, _) = newline(input)?;
84 let top_entry = NixQueryEntry(top_drv, Recurse::No);
85 let (input, children) = parse_branches(0)(input)?;
86 let tree = Tree::new(top_entry, children);
87 Ok((input, NixQueryTree(tree)))
88}
89
90named!(parse_nix_query_tree_final<&str, NixQueryTree>,
91 do_parse!(
92 nix_query_tree: parse_nix_query_tree >>
93 eof!() >>
94 (nix_query_tree)));
95
96pub fn nix_query_tree_parser(
98 input: &str,
99) -> Result<NixQueryTree, nom::Err<(&str, nom::error::ErrorKind)>> {
100 parse_nix_query_tree(input).map(|(_, nix_query_tree)| nix_query_tree)
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 use indoc::indoc;
108
109 #[test]
110 fn test_parse_nix_query_drv() {
111 let raw_input =
112 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]";
113 let raw_path = "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10";
114 let nix_query_drv: NixQueryDrv = raw_path.into();
115 let r = parse_nix_query_drv(raw_input);
116 assert_eq!(r, Ok((" [...]", nix_query_drv)));
117 }
118
119 #[test]
120 fn test_parse_nix_query_entry_no_recurse() {
121 let raw_input =
122 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10\n";
123 let raw_path = "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10";
124 let nix_query_entry: NixQueryEntry =
125 NixQueryEntry(raw_path.into(), Recurse::No);
126 let r = parse_nix_query_entry(raw_input);
127 assert_eq!(r, Ok(("\n", nix_query_entry)));
128 }
129
130 #[test]
131 fn test_parse_nix_query_entry_recurse() {
132 let raw_input =
133 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]\n";
134 let raw_path = "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10";
135 let nix_query_entry: NixQueryEntry =
136 NixQueryEntry(raw_path.into(), Recurse::Yes);
137 let r = parse_nix_query_entry(raw_input);
138 assert_eq!(r, Ok(("\n", nix_query_entry)));
139 }
140
141 #[test]
142 fn test_parse_nix_query_tree_simple() {
143 let raw_input = indoc!(
144 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
145 +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
146 "
147 );
148 let hello_drv: NixQueryDrv =
149 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
150 let actual_tree = Tree::new(
151 NixQueryEntry(hello_drv.clone(), Recurse::No),
152 vec![Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes))],
153 );
154
155 let r = parse_nix_query_tree(raw_input);
156 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
157 }
158
159 #[test]
160 fn test_parse_nix_query_tree_simple_unicode() {
161 let raw_input = indoc!(
162 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
163 └───/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
164 "
165 );
166 let hello_drv: NixQueryDrv =
167 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
168 let actual_tree = Tree::new(
169 NixQueryEntry(hello_drv.clone(), Recurse::No),
170 vec![Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes))],
171 );
172
173 let r = parse_nix_query_tree(raw_input);
174 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
175 }
176
177 #[test]
178 fn test_parse_nix_query_tree_simple_unicode2() {
179 let raw_input = indoc!(
180 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
181 ├───/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
182 "
183 );
184 let hello_drv: NixQueryDrv =
185 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
186 let actual_tree = Tree::new(
187 NixQueryEntry(hello_drv.clone(), Recurse::No),
188 vec![Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes))],
189 );
190
191 let r = parse_nix_query_tree(raw_input);
192 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
193 }
194
195 #[test]
196 fn test_parse_branch_start() {
197 let raw_input = "+---";
198 let r = parse_branch_start(raw_input);
199 assert_eq!(r, Ok(("", "+---")));
200 }
201
202 #[test]
203 fn test_parse_single_branch() {
204 let raw_input = indoc!(
205 "
206 +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
207 "
208 );
209 let hello_drv: NixQueryDrv =
210 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
211 let actual_tree = NixQueryEntry(hello_drv.clone(), Recurse::Yes);
212
213 let r = parse_single_branch(0)(raw_input);
214 assert_eq!(r, Ok(("", actual_tree)));
215 }
216
217 #[test]
218 fn test_parse_branch_with_children_no_children() {
219 let raw_input = indoc!(
220 "
221 +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
222 "
223 );
224 let hello_drv: NixQueryDrv =
225 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
226 let actual_tree =
227 Tree::singleton(NixQueryEntry(hello_drv.clone(), Recurse::Yes));
228
229 let r = parse_branch_with_children(0)(raw_input);
230 assert_eq!(r, Ok(("", actual_tree)));
231 }
232
233 #[test]
234 fn test_parse_empty_branches() {
235 let raw_input = "foobar";
236 let actual_children = vec![];
237
238 let r = parse_branches(0)(raw_input);
239 assert_eq!(r, Ok(("foobar", actual_children)));
240 }
241
242 #[test]
243 fn test_parse_nix_query_tree_simple_multi_children() {
244 let raw_input = indoc!(
245 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
246 +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27
247 +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
248 +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
249 "
250 );
251 let hello_drv: NixQueryDrv =
252 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
253 let glibc_drv: NixQueryDrv =
254 "/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27".into();
255 let actual_tree = Tree::new(
256 NixQueryEntry(hello_drv.clone(), Recurse::No),
257 vec![
258 Tree::singleton(NixQueryEntry(glibc_drv.clone(), Recurse::No)),
259 Tree::singleton(NixQueryEntry(glibc_drv, Recurse::Yes)),
260 Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes)),
261 ],
262 );
263
264 let r = parse_nix_query_tree(raw_input);
265 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
266 }
267
268 #[test]
269 fn test_parse_nix_query_tree_simple_multi_children_unicode() {
270 let raw_input = indoc!(
271 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
272 ├───/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27
273 ├───/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
274 └───/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
275 "
276 );
277 let hello_drv: NixQueryDrv =
278 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
279 let glibc_drv: NixQueryDrv =
280 "/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27".into();
281 let actual_tree = Tree::new(
282 NixQueryEntry(hello_drv.clone(), Recurse::No),
283 vec![
284 Tree::singleton(NixQueryEntry(glibc_drv.clone(), Recurse::No)),
285 Tree::singleton(NixQueryEntry(glibc_drv, Recurse::Yes)),
286 Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes)),
287 ],
288 );
289
290 let r = parse_nix_query_tree(raw_input);
291 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
292 }
293
294 #[test]
295 fn test_parse_nix_query_tree_simple_multi_levels() {
296 let raw_input = indoc!(
297 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
298 +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27
299 | +---/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
300 +---/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
301 "
302 );
303 let hello_drv: NixQueryDrv =
304 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
305 let glibc_drv: NixQueryDrv =
306 "/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27".into();
307 let actual_tree = Tree::new(
308 NixQueryEntry(hello_drv.clone(), Recurse::No),
309 vec![
310 Tree::new(
311 NixQueryEntry(glibc_drv.clone(), Recurse::No),
312 vec![Tree::singleton(NixQueryEntry(
313 glibc_drv,
314 Recurse::Yes,
315 ))],
316 ),
317 Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes)),
318 ],
319 );
320
321 let r = parse_nix_query_tree(raw_input);
322 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
323 }
324
325 #[test]
326 fn test_parse_nix_query_tree_simple_multi_levels_unicode() {
327 let raw_input = indoc!(
328 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
329 ├───/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27
330 │ └───/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27 [...]
331 └───/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10 [...]
332 "
333 );
334 let hello_drv: NixQueryDrv =
335 "/nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10".into();
336 let glibc_drv: NixQueryDrv =
337 "/nix/store/pnd2kl27sag76h23wa5kl95a76n3k9i3-glibc-2.27".into();
338 let actual_tree = Tree::new(
339 NixQueryEntry(hello_drv.clone(), Recurse::No),
340 vec![
341 Tree::new(
342 NixQueryEntry(glibc_drv.clone(), Recurse::No),
343 vec![Tree::singleton(NixQueryEntry(
344 glibc_drv,
345 Recurse::Yes,
346 ))],
347 ),
348 Tree::singleton(NixQueryEntry(hello_drv, Recurse::Yes)),
349 ],
350 );
351
352 let r = parse_nix_query_tree(raw_input);
353 assert_eq!(r, Ok(("", NixQueryTree(actual_tree))));
354 }
355}