chug_cli/
tree.rs

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}