winbrew_cli\commands/
mod.rs

1//! Command handler dispatch for WinBrew.
2//!
3//! This module maps parsed CLI commands to the concrete wrapper handlers in
4//! the sibling modules. Each handler owns the user-facing UI behavior for its
5//! command while delegating business logic to `winbrew-app`.
6
7use anyhow::Result;
8
9use crate::CommandContext;
10use crate::cli::Command;
11
12pub mod config;
13pub mod doctor;
14pub mod error;
15pub mod info;
16pub mod install;
17pub mod list;
18pub mod remove;
19pub mod repair;
20pub mod search;
21pub mod update;
22pub mod version;
23
24/// Dispatch a parsed command to its wrapper handler.
25pub fn run(
26    command: Command,
27    ctx: &CommandContext,
28    config: &mut crate::database::Config,
29) -> Result<()> {
30    match command {
31        Command::List { query } => list::run(ctx, &query),
32        Command::Install {
33            query,
34            ignore_checksum_security,
35            plan,
36        } => install::run(ctx, &query, ignore_checksum_security, plan),
37        Command::Search { query } => search::run(ctx, &query),
38        Command::Info => info::run(ctx),
39        Command::Version => version::run(ctx),
40        Command::Doctor {
41            json,
42            warn_as_error,
43        } => doctor::run(ctx, json, warn_as_error),
44        Command::Update => update::run(ctx),
45        Command::Remove { name, yes, force } => remove::run(ctx, &name, yes, force),
46        Command::Repair { yes } => repair::run(ctx, yes),
47        Command::Config { command } => config::run(ctx, config, command),
48        Command::Completions { .. } => unreachable!("completion command is handled during startup"),
49    }
50}
51
52#[cfg(test)]
53pub(crate) mod test_support {
54    use std::io::{Result as IoResult, Write};
55    use std::sync::{Arc, Mutex};
56
57    use winbrew_ui::{Ui, UiBuilder, UiSettings};
58
59    pub(crate) type BufferBytes = Arc<Mutex<Vec<u8>>>;
60    pub(crate) type BufferedUi = Ui<SharedBuffer>;
61    pub(crate) type BufferedUiBundle = (BufferedUi, BufferBytes, BufferBytes);
62
63    pub(crate) struct SharedBuffer {
64        bytes: BufferBytes,
65    }
66
67    impl SharedBuffer {
68        pub(crate) fn new(bytes: BufferBytes) -> Self {
69            Self { bytes }
70        }
71    }
72
73    impl Write for SharedBuffer {
74        fn write(&mut self, buffer: &[u8]) -> IoResult<usize> {
75            self.bytes
76                .lock()
77                .expect("buffer lock should be available")
78                .extend_from_slice(buffer);
79            Ok(buffer.len())
80        }
81
82        fn flush(&mut self) -> IoResult<()> {
83            Ok(())
84        }
85    }
86
87    pub(crate) fn buffered_ui(settings: UiSettings) -> BufferedUiBundle {
88        let out: BufferBytes = Arc::new(Mutex::new(Vec::new()));
89        let err: BufferBytes = Arc::new(Mutex::new(Vec::new()));
90        let ui = UiBuilder::with_writer(SharedBuffer::new(Arc::clone(&out)), settings)
91            .with_error_writer(Box::new(SharedBuffer::new(Arc::clone(&err))))
92            .color_enabled(false)
93            .build();
94
95        (ui, out, err)
96    }
97
98    pub(crate) fn buffer_text(buffer: &BufferBytes) -> String {
99        String::from_utf8(
100            buffer
101                .lock()
102                .expect("buffer lock should be available")
103                .clone(),
104        )
105        .expect("buffer should be utf-8")
106    }
107}