cargo_lambda_system/
lib.rs

1use std::{collections::HashMap, path::PathBuf};
2
3use cargo_lambda_metadata::{
4    cargo::CargoMetadata,
5    config::{
6        Config, ConfigOptions, general_config_figment, get_config_from_all_packages,
7        load_config_without_cli_flags,
8    },
9};
10use clap::Args;
11use miette::{IntoDiagnostic, Result};
12
13use cargo_lambda_build::{InstallOption, Zig, install_options, install_zig, print_install_options};
14use cargo_lambda_interactive::is_stdin_tty;
15use serde::{Deserialize, Serialize};
16use strum_macros::{Display, EnumString};
17use tracing::trace;
18
19#[derive(Clone, Debug, Default, Deserialize, Display, EnumString, Serialize)]
20#[strum(ascii_case_insensitive)]
21#[serde(rename_all = "lowercase")]
22pub enum OutputFormat {
23    #[default]
24    Text,
25    Json,
26}
27
28#[derive(Args, Clone, Debug)]
29#[command(
30    visible_alias = "config",
31    after_help = "Full command documentation: https://www.cargo-lambda.info/commands/system.html"
32)]
33pub struct System {
34    /// Setup and install Zig if it is not already installed.
35    #[arg(long, visible_alias = "install-zig", alias = "install")]
36    setup: bool,
37
38    /// Manifest path to show information for
39    #[arg(short, long)]
40    manifest_path: Option<PathBuf>,
41
42    /// Format to render the output (text, or json)
43    #[arg(short, long)]
44    output_format: Option<OutputFormat>,
45
46    /// Package name to show information for
47    #[arg(short, long)]
48    package: Option<String>,
49}
50
51impl System {
52    pub fn manifest_path(&self) -> PathBuf {
53        self.manifest_path
54            .clone()
55            .unwrap_or_else(|| "Cargo.toml".into())
56    }
57
58    pub fn package(&self) -> Option<String> {
59        self.package.clone()
60    }
61}
62
63#[derive(Debug, Default, Serialize)]
64struct ZigInfo {
65    #[serde(skip_serializing_if = "Option::is_none")]
66    path: Option<PathBuf>,
67    #[serde(skip_serializing_if = "Option::is_none")]
68    install_options: Option<Vec<InstallOption>>,
69}
70
71#[derive(Debug, Serialize)]
72struct Info {
73    zig: ZigInfo,
74    config: ConfigInfo,
75}
76
77#[derive(Debug, Serialize)]
78enum ConfigInfo {
79    #[serde(rename = "package")]
80    Package(Config),
81    #[serde(rename = "global")]
82    Global {
83        workspace: Config,
84        packages: HashMap<String, Config>,
85    },
86}
87
88#[tracing::instrument(target = "cargo_lambda")]
89pub async fn run(config: &System, metadata: &CargoMetadata, options: &ConfigOptions) -> Result<()> {
90    trace!("running config command");
91
92    if config.setup {
93        let options = install_options();
94        if is_stdin_tty() {
95            install_zig(options).await?;
96        } else {
97            print_install_options(&options);
98        }
99
100        return Ok(());
101    }
102
103    let config_info = if options.name.is_some() || metadata.packages.len() == 1 {
104        let config = load_config_without_cli_flags(metadata, options)?;
105        ConfigInfo::Package(config)
106    } else {
107        let (_, _, workspace) = general_config_figment(metadata, options)?;
108
109        let packages = get_config_from_all_packages(metadata)?;
110
111        ConfigInfo::Global {
112            workspace: workspace.extract().into_diagnostic()?,
113            packages,
114        }
115    };
116
117    let zig_info = if let Ok((path, _)) = Zig::find_zig() {
118        ZigInfo {
119            path: Some(path),
120            install_options: None,
121        }
122    } else {
123        let options = install_options();
124        ZigInfo {
125            path: None,
126            install_options: Some(options),
127        }
128    };
129
130    let info = Info {
131        zig: zig_info,
132        config: config_info,
133    };
134
135    match config.output_format {
136        Some(OutputFormat::Json) => {
137            println!("{}", serde_json::to_string(&info).into_diagnostic()?);
138        }
139        _ => {
140            let data = serde_yml::to_string(&info).unwrap();
141            bat::PrettyPrinter::new()
142                .language("yaml")
143                .input_from_bytes(data.as_bytes())
144                .colored_output(false)
145                .print()
146                .into_diagnostic()?;
147        }
148    }
149
150    Ok(())
151}