winbrew_cli\services\startup/mod.rs
1//! CLI startup orchestration for `winbrew-cli`.
2//!
3//! This module owns the pre-dispatch portion of the command lifecycle. The
4//! crate entrypoint [`crate::run_app`] delegates here so startup policy stays
5//! with the CLI layer instead of leaking into `winbrew-bin`.
6//!
7//! The workflow is intentionally split into three phases:
8//!
9//! 1. Load the persisted configuration from storage.
10//! 2. Build a [`crate::CommandContext`] from that configuration and the current
11//! verbosity level.
12//! 3. Initialize process services and dispatch the selected command.
13//!
14//! The order is important because:
15//!
16//! - configuration must be loaded before the effective log and database paths
17//! are known;
18//! - logging must start before later startup failures are emitted;
19//! - database initialization must happen before runtime cleanup, because the
20//! bootstrap cleanup uses [`crate::database::get_conn`];
21//! - command dispatch runs last, after the process is fully hydrated.
22
23use anyhow::Result;
24
25use crate::cli::Command;
26use crate::commands::run as dispatch_command_impl;
27use crate::{CommandContext, database};
28
29mod config;
30mod process;
31
32/// Run the full CLI startup sequence and then execute the selected command.
33///
34/// The `verbosity` value is forwarded into
35/// [`crate::CommandContext::from_config_with_verbosity`] so the process-level
36/// runtime state can react to the caller's requested verbosity without mutating
37/// the persisted configuration snapshot.
38pub(crate) fn run(command: Command, verbosity: u8) -> Result<()> {
39 if let Command::Completions { shell } = &command {
40 return crate::services::completions::run(*shell);
41 }
42
43 let mut app_config = config::load()?;
44 let context = config::build_context(&app_config, verbosity)?;
45
46 process::init(&context)?;
47 dispatch_command(command, &context, &mut app_config)
48}
49
50/// Hand the hydrated context to the CLI dispatcher after startup side effects
51/// have completed.
52fn dispatch_command(
53 command: Command,
54 context: &CommandContext,
55 config: &mut database::Config,
56) -> Result<()> {
57 dispatch_command_impl(command, context, config)
58}