Skip to main content

zoi_cli/cmd/
service.rs

1//! Logic for the `service` command.
2//!
3//! This module provides commands for managing background services associated
4//! with installed packages, allowing users to start, stop, enable, and monitor
5//! them.
6
7use anyhow::Result;
8use clap::{Parser, Subcommand};
9use colored::Colorize;
10use comfy_table::Table;
11use comfy_table::presets::UTF8_FULL;
12
13use crate::pkg::service::{self, ServiceAction};
14
15/// The root service management command.
16#[derive(Parser, Debug)]
17#[command(long_about = "Manages background services for installed packages.")]
18pub struct ServiceCommand {
19    /// The specific service subcommand to execute.
20    #[command(subcommand)]
21    pub command: ServiceCommands
22}
23
24/// Available service subcommands.
25#[derive(Subcommand, Debug)]
26pub enum ServiceCommands {
27    /// Start a service
28    Start {
29        /// The name of the package whose service to start
30        package: String
31    },
32    /// Stop a service
33    Stop {
34        /// The name of the package whose service to stop
35        package: String
36    },
37    /// Restart a service
38    Restart {
39        /// The name of the package whose service to restart
40        package: String
41    },
42    /// Show the status of a service
43    Status {
44        /// The name of the package whose service status to show
45        package: String
46    },
47    /// Enable a service (start at boot)
48    Enable {
49        /// The name of the package whose service to enable
50        package: String
51    },
52    /// Disable a service
53    Disable {
54        /// The name of the package whose service to disable
55        package: String
56    },
57    /// List all packages that define a service and their current status
58    #[command(alias = "ls")]
59    List
60}
61
62/// Run the service management command.
63///
64/// # Errors
65///
66/// Returns an error if the service action fails.
67pub fn run(args: ServiceCommand) -> Result<()> {
68    match args.command {
69        ServiceCommands::Start { package } => {
70            println!("Starting service for package '{}'...", package.cyan());
71            service::manage_service(&package, ServiceAction::Start)?;
72            println!("{}", "Service started successfully.".green());
73        }
74        ServiceCommands::Stop { package } => {
75            println!("Stopping service for package '{}'...", package.cyan());
76            service::manage_service(&package, ServiceAction::Stop)?;
77            println!("{}", "Service stopped successfully.".green());
78        }
79        ServiceCommands::Restart { package } => {
80            println!("Restarting service for package '{}'...", package.cyan());
81            service::manage_service(&package, ServiceAction::Restart)?;
82            println!("{}", "Service restarted successfully.".green());
83        }
84        ServiceCommands::Status { package } => {
85            service::manage_service(&package, ServiceAction::Status)?;
86        }
87        ServiceCommands::Enable { package } => {
88            println!("Enabling service for package '{}'...", package.cyan());
89            service::manage_service(&package, ServiceAction::Enable)?;
90            println!("{}", "Service enabled successfully.".green());
91        }
92        ServiceCommands::Disable { package } => {
93            println!("Disabling service for package '{}'...", package.cyan());
94            service::manage_service(&package, ServiceAction::Disable)?;
95            println!("{}", "Service disabled successfully.".green());
96        }
97        ServiceCommands::List => {
98            let services = service::list_services()?;
99            if services.is_empty() {
100                println!("No installed packages define background services.");
101                return Ok(());
102            }
103
104            let mut table = Table::new();
105            table
106                .load_style(UTF8_FULL)
107                .set_header(vec!["Package", "Status"]);
108
109            for (pkg, status) in services {
110                let status_cell = if status == "active" || status == "running" {
111                    status.green()
112                } else {
113                    status.yellow()
114                };
115                table.add_row(vec![pkg.cyan(), status_cell.to_string().into()]);
116            }
117
118            println!("{table}");
119        }
120    }
121    Ok(())
122}