soroban_cli/commands/contract/alias/
ls.rs

1use clap::{command, Parser};
2use std::collections::HashMap;
3use std::fmt::Debug;
4use std::path::Path;
5use std::{fs, process};
6
7use crate::commands::config::network;
8#[cfg(feature = "version_gte_23")]
9use crate::config::locator::{print_deprecation_warning, Location};
10use crate::config::{alias, locator};
11
12#[derive(Parser, Debug, Clone)]
13#[group(skip)]
14pub struct Cmd {
15    #[command(flatten)]
16    pub config_locator: locator::Args,
17}
18
19#[derive(thiserror::Error, Debug)]
20pub enum Error {
21    #[error(transparent)]
22    Locator(#[from] locator::Error),
23
24    #[error(transparent)]
25    Network(#[from] network::Error),
26
27    #[error(transparent)]
28    PatternError(#[from] glob::PatternError),
29
30    #[error(transparent)]
31    GlobError(#[from] glob::GlobError),
32
33    #[error(transparent)]
34    IoError(#[from] std::io::Error),
35}
36
37#[derive(Debug, Clone)]
38struct AliasEntry {
39    alias: String,
40    contract: String,
41}
42
43impl Cmd {
44    #[cfg(feature = "version_lt_23")]
45    pub fn run(&self) -> Result<(), Error> {
46        Self::read_from_config_dir(&self.config_locator.config_dir()?, false)
47    }
48
49    #[cfg(not(feature = "version_lt_23"))]
50    #[cfg(feature = "version_gte_23")]
51    pub fn run(&self) -> Result<(), Error> {
52        let config_dirs = self.config_locator.local_and_global()?;
53
54        for cfg in config_dirs {
55            match cfg {
56                Location::Local(config_dir) => Self::read_from_config_dir(&config_dir, true)?,
57                Location::Global(config_dir) => Self::read_from_config_dir(&config_dir, false)?,
58            }
59        }
60
61        Ok(())
62    }
63
64    fn read_from_config_dir(config_dir: &Path, deprecation_mode: bool) -> Result<(), Error> {
65        let pattern = config_dir
66            .join("contract-ids")
67            .join("*.json")
68            .to_string_lossy()
69            .into_owned();
70
71        let paths = glob::glob(&pattern)?;
72        let mut found = false;
73        let mut map: HashMap<String, Vec<AliasEntry>> = HashMap::new();
74
75        for path in paths {
76            let path = path?;
77
78            if let Some(alias) = path.file_stem() {
79                let alias = alias.to_string_lossy().into_owned();
80                let content = fs::read_to_string(path)?;
81                let data: alias::Data = serde_json::from_str(&content).unwrap_or_default();
82
83                for network_passphrase in data.ids.keys() {
84                    let network_passphrase = network_passphrase.to_string();
85                    let contract = data
86                        .ids
87                        .get(&network_passphrase)
88                        .map(ToString::to_string)
89                        .unwrap_or_default();
90                    let entry = AliasEntry {
91                        alias: alias.clone(),
92                        contract,
93                    };
94
95                    let list = map.entry(network_passphrase.clone()).or_default();
96
97                    list.push(entry.clone());
98                }
99            }
100        }
101
102        for network_passphrase in map.keys() {
103            if let Some(list) = map.clone().get_mut(network_passphrase) {
104                println!("ℹ️ Aliases available for network '{network_passphrase}'");
105
106                list.sort_by(|a, b| a.alias.cmp(&b.alias));
107
108                for entry in list {
109                    #[cfg(feature = "version_gte_23")]
110                    if !found && deprecation_mode {
111                        print_deprecation_warning(config_dir);
112                    }
113                    found = true;
114                    println!("{}: {}", entry.alias, entry.contract);
115                }
116
117                println!();
118            }
119        }
120
121        if !found && !deprecation_mode {
122            eprintln!("⚠️ No aliases defined for network");
123
124            process::exit(1);
125        }
126
127        Ok(())
128    }
129}