golem_cli/
lib.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use clap_verbosity_flag::Verbosity;
16use shadow_rs::shadow;
17use tracing_subscriber::FmtSubscriber;
18
19pub mod app;
20pub mod auth;
21pub mod cloud;
22pub mod command;
23pub mod command_handler;
24pub mod config;
25pub mod context;
26pub mod diagnose;
27pub mod error;
28pub mod fs;
29pub mod fuzzy;
30pub mod log;
31pub mod model;
32pub mod validation;
33pub mod wasm_rpc_stubgen;
34
35#[cfg(test)]
36test_r::enable!();
37
38shadow!(build);
39
40pub fn command_name() -> String {
41    std::env::current_exe()
42        .ok()
43        .and_then(|path| {
44            path.file_stem()
45                .map(|name| name.to_string_lossy().to_string())
46        })
47        .unwrap_or("golem-cli".to_string())
48}
49
50pub fn version() -> &'static str {
51    if build::PKG_VERSION != "0.0.0" {
52        build::PKG_VERSION
53    } else {
54        build::GIT_DESCRIBE_TAGS
55    }
56}
57
58pub fn init_tracing(verbosity: Verbosity, pretty_mode: bool) {
59    if let Some(level) = verbosity.tracing_level() {
60        let subscriber = FmtSubscriber::builder();
61        if pretty_mode {
62            let subscriber = subscriber
63                .pretty()
64                .with_max_level(level)
65                .with_writer(std::io::stderr)
66                .finish();
67
68            tracing::subscriber::set_global_default(subscriber)
69                .expect("setting default subscriber failed");
70        } else {
71            let subscriber = subscriber
72                .with_max_level(level)
73                .with_writer(std::io::stderr)
74                .finish();
75
76            tracing::subscriber::set_global_default(subscriber)
77                .expect("setting default subscriber failed");
78        };
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use test_r::test;
85
86    use crate::command::GolemCliCommand;
87    use clap::{ArgAction, Command, CommandFactory};
88
89    #[test]
90    fn dump_commands_v_1_2() {
91        let command = GolemCliCommand::command();
92        dump_command(0, &command);
93    }
94
95    fn dump_command(level: usize, command: &Command) {
96        print!("{}{}", "\t".repeat(level), command.get_name());
97
98        let aliases = command.get_aliases().collect::<Vec<_>>();
99        if !aliases.is_empty() {
100            print!(" ({})", aliases.join(", "));
101        }
102
103        let (positional, flag_args): (Vec<_>, Vec<_>) =
104            command.get_arguments().partition(|arg| arg.is_positional());
105
106        if !positional.is_empty() {
107            for arg in positional {
108                let id = arg.get_id().to_string().to_uppercase();
109                if arg.is_required_set() && arg.get_default_values().is_empty() {
110                    print!(" <{}>", id);
111                } else {
112                    print!(" [{}]", id);
113                }
114                if let ArgAction::Append = arg.get_action() {
115                    print!("...")
116                }
117            }
118        }
119
120        println!();
121
122        if !flag_args.is_empty() {
123            print!("{}", "\t".repeat(level + 2));
124            for arg in flag_args.clone() {
125                print!(" --{}", arg.get_long().unwrap(),);
126                arg.get_short()
127                    .iter()
128                    .for_each(|short| print!("({})", short));
129            }
130            println!()
131        }
132
133        let subcommand_level = level + 1;
134        for subcommand in command.get_subcommands() {
135            dump_command(subcommand_level, subcommand);
136        }
137    }
138}