cargo_lambda_system/
lib.rs

1use std::{collections::HashMap, path::PathBuf};
2
3use cargo_lambda_metadata::{
4    cargo::load_metadata,
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::zig::{ZigInfo, check_installation, get_zig_info};
14use serde::{Deserialize, Serialize};
15use strum_macros::{Display, EnumString};
16use tracing::trace;
17
18#[derive(Clone, Debug, Default, Deserialize, Display, EnumString, Serialize)]
19#[strum(ascii_case_insensitive)]
20#[serde(rename_all = "lowercase")]
21pub enum OutputFormat {
22    #[default]
23    Text,
24    Json,
25}
26
27#[derive(Args, Clone, Debug)]
28#[command(
29    visible_alias = "config",
30    after_help = "Full command documentation: https://www.cargo-lambda.info/commands/system.html"
31)]
32pub struct System {
33    /// Setup and install Zig if it is not already installed.
34    #[arg(long, visible_alias = "install-zig", alias = "install")]
35    setup: bool,
36
37    /// Manifest path to show information for
38    #[arg(short, long)]
39    manifest_path: Option<PathBuf>,
40
41    /// Format to render the output (text, or json)
42    #[arg(short, long)]
43    output_format: Option<OutputFormat>,
44
45    /// Package name to show information for
46    #[arg(short, long)]
47    package: Option<String>,
48}
49
50impl System {
51    pub fn manifest_path(&self) -> PathBuf {
52        self.manifest_path
53            .clone()
54            .unwrap_or_else(|| "Cargo.toml".into())
55    }
56
57    pub fn pkg_name(&self) -> Option<String> {
58        self.package.clone()
59    }
60}
61
62#[derive(Debug, Serialize)]
63struct Info {
64    zig: ZigInfo,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    config: Option<ConfigInfo>,
67}
68
69#[derive(Debug, Serialize)]
70enum ConfigInfo {
71    #[serde(rename = "package")]
72    Package(Config),
73    #[serde(rename = "global")]
74    Global {
75        workspace: Config,
76        packages: HashMap<String, Config>,
77    },
78}
79
80#[tracing::instrument(target = "cargo_lambda")]
81pub async fn run(config: &System, options: &ConfigOptions) -> Result<()> {
82    trace!("running config command");
83
84    if config.setup {
85        let zig_info = check_installation().await?;
86        return print_config(config.output_format.as_ref(), zig_info);
87    }
88
89    let mut info = Info {
90        zig: get_zig_info()?,
91        config: None,
92    };
93    let manifest_path = config.manifest_path();
94
95    if manifest_path.exists() {
96        let metadata = load_metadata(manifest_path)?;
97
98        let config_info = if !options.names.is_empty() || metadata.packages.len() == 1 {
99            let config = load_config_without_cli_flags(&metadata, options)?;
100            ConfigInfo::Package(config)
101        } else {
102            let (_, _, workspace) = general_config_figment(&metadata, options)?;
103
104            let packages = get_config_from_all_packages(&metadata)?;
105
106            ConfigInfo::Global {
107                workspace: workspace.extract().into_diagnostic()?,
108                packages,
109            }
110        };
111
112        info.config = Some(config_info);
113    }
114
115    print_config(config.output_format.as_ref(), info)
116}
117
118fn print_config(format: Option<&OutputFormat>, info: impl Serialize) -> Result<()> {
119    match format {
120        Some(OutputFormat::Json) => {
121            serde_json::to_writer_pretty(std::io::stdout(), &info).into_diagnostic()
122        }
123        _ => serde_yml::to_writer(std::io::stdout(), &info).into_diagnostic(),
124    }
125}