soroban_cli/commands/contract/alias/
ls.rs

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