1use std::collections::{BTreeMap, BTreeSet};
2
3use ptree::{TreeBuilder, print_tree};
4
5use crate::db::models::{Dependency, DownloadedBottle};
6
7pub fn list_bottles() -> anyhow::Result<()> {
8 let bottles = DownloadedBottle::get_all()?;
9
10 for bottle in bottles {
11 println!("{} {}", bottle.name(), bottle.version());
12 }
13
14 Ok(())
15}
16
17pub fn display_tree() -> anyhow::Result<()> {
18 let bottles = DownloadedBottle::get_all()?;
19 let dependencies = Dependency::get_all()?;
20
21 let bottle_map = bottles
22 .into_iter()
23 .map(|b| (b.id(), b))
24 .collect::<BTreeMap<_, _>>();
25 let mut dependency_map = BTreeMap::new();
26 for dependency in dependencies {
27 dependency_map
28 .entry(dependency.dependent_id())
29 .or_insert_with(Vec::new)
30 .push(dependency.dependency_id());
31 }
32
33 let get_dependencies = |id: Option<i32>| {
34 let mut v = dependency_map
35 .get(&id)
36 .map(Vec::as_slice)
37 .unwrap_or_default()
38 .iter()
39 .map(|id| &bottle_map[id])
40 .collect::<Vec<_>>();
41 v.sort_by_key(|b| b.name());
42 v
43 };
44
45 let mut builder = TreeBuilder::new("Installed bottles:".to_owned());
46 let mut stack = vec![get_dependencies(None).into_iter()];
47 let mut processed = BTreeSet::new();
48 while let Some(children) = stack.last_mut() {
49 if let Some(child) = children.next() {
50 if processed.insert(child.id()) {
51 builder.begin_child(format!("{} {}", child.name(), child.version()));
52 stack.push(get_dependencies(Some(child.id())).into_iter());
53 } else {
54 builder.add_empty_child(format!("{} {} (*)", child.name(), child.version()));
55 }
56 } else {
57 stack.pop();
58 if !stack.is_empty() {
59 builder.end_child();
60 }
61 }
62 }
63
64 let tree = builder.build();
65 print_tree(&tree)?;
66
67 Ok(())
68}