winbrew_cli\commands/
list.rs1use anyhow::Result;
7use std::io::Write;
8
9use crate::{CommandContext, app::list};
10use winbrew_ui::Ui;
11
12pub fn run(ctx: &CommandContext, query: &[String]) -> Result<()> {
13 let mut ui = ctx.ui();
14 run_with_ui(&mut ui, query)
15}
16
17fn run_with_ui<W: Write>(ui: &mut Ui<W>, query: &[String]) -> Result<()> {
18 ui.page_title("Installed Packages");
19
20 let query_text = (!query.is_empty()).then(|| query.join(" "));
21
22 let packages = list::list_packages(query_text.as_deref())?;
23
24 if packages.is_empty() {
25 match query_text {
26 Some(q) => ui.notice(format!("No installed packages matching '{q}'.")),
27 None => ui.notice("No packages are currently installed."),
28 }
29
30 return Ok(());
31 }
32
33 ui.display_packages(&packages);
34 ui.info(format!("\nTotal: {} package(s) installed.", packages.len()));
35
36 Ok(())
37}
38
39#[cfg(test)]
40mod tests {
41 use super::run_with_ui;
42 use crate::commands::test_support::{buffer_text, buffered_ui};
43 use crate::database::{self, Config};
44 use crate::models::domains::install::{EngineKind, InstallerType};
45 use crate::models::domains::installed::{InstalledPackage, PackageStatus};
46 use tempfile::tempdir;
47 use winbrew_ui::UiSettings;
48
49 fn sample_package() -> InstalledPackage {
50 InstalledPackage {
51 name: "Contoso App".to_string(),
52 version: "1.2.3".to_string(),
53 kind: InstallerType::Portable,
54 deployment_kind: InstallerType::Portable.deployment_kind(),
55 engine_kind: EngineKind::Portable,
56 engine_metadata: None,
57 install_dir: r"C:\Apps\Contoso".to_string(),
58 dependencies: Vec::new(),
59 status: PackageStatus::Ok,
60 installed_at: "2026-04-07T12:00:00Z".to_string(),
61 }
62 }
63
64 #[test]
65 fn run_with_ui_reports_query_specific_empty_state() {
66 let temp_dir = tempdir().expect("temp dir");
67 let config = Config::load_at(temp_dir.path()).expect("config should load");
68 database::init(&config.resolved_paths()).expect("database should initialize");
69
70 let (mut ui, out, err) = buffered_ui(UiSettings::default());
71 let query = ["Contoso".to_string(), "App".to_string()];
72
73 run_with_ui(&mut ui, &query).expect("list should succeed");
74
75 assert!(buffer_text(&out).trim().is_empty());
76 assert!(buffer_text(&err).contains("No installed packages matching 'Contoso App'."));
77 }
78
79 #[test]
80 fn run_with_ui_renders_installed_packages() {
81 let temp_dir = tempdir().expect("temp dir");
82 let config = Config::load_at(temp_dir.path()).expect("config should load");
83 database::init(&config.resolved_paths()).expect("database should initialize");
84
85 {
86 let conn = database::get_conn().expect("database connection");
87 database::insert_package(&conn, &sample_package()).expect("package should seed");
88 }
89
90 let (mut ui, out, err) = buffered_ui(UiSettings::default());
91
92 run_with_ui(&mut ui, &[]).expect("list should succeed");
93
94 let out = buffer_text(&out);
95 let err = buffer_text(&err);
96
97 assert!(out.contains("installed packages"));
98 assert!(out.contains("Contoso App"));
99 assert!(out.contains("1.2.3"));
100 assert!(err.contains("Total: 1 package(s) installed."));
101 }
102}