stellar_scaffold_cli/commands/ext/
ls.rs1use cargo_metadata::MetadataCommand;
2use clap::Parser;
3use stellar_cli::print::Print;
4
5use crate::commands::build::clients::ScaffoldEnv;
6use crate::commands::build::env_toml;
7use crate::extension::{ExtensionListStatus, list};
8
9const H_NAME: &str = "NAME";
10const H_VERSION: &str = "VERSION";
11const H_STATUS: &str = "STATUS";
12const H_HOOKS: &str = "HOOKS";
13
14#[derive(Parser, Debug)]
15pub struct Cmd {
16 #[arg(
18 env = "STELLAR_SCAFFOLD_ENV",
19 value_enum,
20 default_value = "development"
21 )]
22 pub env: ScaffoldEnv,
23}
24
25#[derive(thiserror::Error, Debug)]
26pub enum Error {
27 #[error(transparent)]
28 Metadata(#[from] cargo_metadata::Error),
29 #[error(transparent)]
30 Env(#[from] env_toml::Error),
31}
32
33impl Cmd {
34 pub fn run(&self, global_args: &stellar_cli::commands::global::Args) -> Result<(), Error> {
35 let printer = Print::new(global_args.quiet);
36
37 let metadata = MetadataCommand::new().no_deps().exec()?;
38 let workspace_root = metadata.workspace_root.as_std_path();
39
40 let Some(current_env) = env_toml::Environment::get(workspace_root, &self.env)? else {
41 printer.warnln(format!(
42 "No environments.toml found or no {:?} environment configured.",
43 self.env
44 ));
45 return Ok(());
46 };
47
48 if current_env.extensions.is_empty() {
49 printer.infoln(format!(
50 "No extensions configured for the {:?} environment.",
51 self.env
52 ));
53 return Ok(());
54 }
55
56 let entries = list(¤t_env.extensions);
57
58 let name_w = entries
60 .iter()
61 .map(|e| e.name.len())
62 .max()
63 .unwrap_or(0)
64 .max(H_NAME.len());
65 let version_w = entries
66 .iter()
67 .map(|e| match &e.status {
68 ExtensionListStatus::Found { version, .. } => version.len(),
69 _ => 1, })
71 .max()
72 .unwrap_or(0)
73 .max(H_VERSION.len());
74 let status_w = entries
75 .iter()
76 .map(|e| status_str(&e.status).len())
77 .max()
78 .unwrap_or(0)
79 .max(H_STATUS.len());
80
81 println!("{H_NAME:<name_w$} {H_VERSION:<version_w$} {H_STATUS:<status_w$} {H_HOOKS}",);
83 println!(
84 "{:-<name_w$} {:-<version_w$} {:-<status_w$} {:-<hooks_w$}",
85 "",
86 "",
87 "",
88 "",
89 hooks_w = H_HOOKS.len(),
90 );
91
92 for entry in &entries {
94 let version = match &entry.status {
95 ExtensionListStatus::Found { version, .. } => version.as_str(),
96 _ => "-",
97 };
98 let hooks = match &entry.status {
99 ExtensionListStatus::Found { hooks, .. } if !hooks.is_empty() => hooks.join(", "),
100 _ => "-".to_string(),
101 };
102 let name = &entry.name;
103 let status = status_str(&entry.status);
104 println!("{name:<name_w$} {version:<version_w$} {status:<status_w$} {hooks}");
105 }
106
107 Ok(())
108 }
109}
110
111fn status_str(status: &ExtensionListStatus) -> &'static str {
112 match status {
113 ExtensionListStatus::Found { .. } => "found",
114 ExtensionListStatus::MissingBinary => "missing",
115 ExtensionListStatus::ManifestError(_) => "error",
116 }
117}