warg_cli/commands/
info.rs

1use super::CommonOptions;
2use anyhow::Result;
3use clap::{ArgAction, Args};
4use warg_client::{
5    keyring::Keyring,
6    storage::{ContentStorage, NamespaceMapStorage, PackageInfo, RegistryStorage},
7    Client,
8};
9use warg_crypto::hash::AnyHash;
10use warg_protocol::{registry::PackageName, Version};
11
12/// Display client storage information.
13#[derive(Args)]
14pub struct InfoCommand {
15    /// The common command options.
16    #[clap(flatten)]
17    pub common: CommonOptions,
18
19    /// Only show information for the specified package.
20    #[clap(value_name = "PACKAGE")]
21    pub package: Option<PackageName>,
22
23    /// Only show the namespace map
24    #[clap(short, long, value_name = "NAMESPACES", action = ArgAction::SetTrue)]
25    pub namespaces: bool,
26}
27
28impl InfoCommand {
29    /// Executes the command.
30    pub async fn exec(self) -> Result<()> {
31        let config = self.common.read_config()?;
32        let client = self.common.create_client(&config).await?;
33
34        print!("\nRegistry: {url} ", url = client.url().registry_domain());
35        if config.keyring_auth
36            && Keyring::from_config(&config)?
37                .get_auth_token(client.url())?
38                .is_some()
39        {
40            println!(
41                "(Using credentials{keyring_backend})",
42                keyring_backend = if let Some(keyring_backend) = &config.keyring_backend {
43                    format!(" stored in `{keyring_backend}` keyring backend")
44                } else {
45                    "".to_string()
46                }
47            );
48        } else {
49            println!("(Not logged in)");
50        }
51        println!("\nPackages in client storage:");
52        match self.package {
53            Some(package) => {
54                let info = client.package(&package).await?;
55                if let Some(registry) = client.get_warg_registry(package.namespace()).await? {
56                    println!("Registry: {registry}");
57                }
58                Self::print_package_info(&info);
59            }
60            None => {
61                client
62                    .registry()
63                    .load_all_packages()
64                    .await?
65                    .iter()
66                    .for_each(|(registry, packages)| {
67                        println!("\nRegistry: {registry}");
68                        packages.iter().for_each(Self::print_package_info);
69                    });
70            }
71        }
72
73        if self.namespaces {
74            println!("\nNamespace mappings in client storage");
75            Self::print_namespace_map(&client).await?;
76            return Ok(());
77        }
78
79        println!();
80
81        Ok(())
82    }
83
84    fn print_package_info(info: &PackageInfo) {
85        println!("  Name: {name}", name = info.name);
86        println!("  Versions:");
87        info.state.releases().for_each(|r| {
88            if let Some(content) = r.content() {
89                Self::print_release(&r.version, content);
90            }
91        });
92    }
93
94    fn print_release(version: &Version, content: &AnyHash) {
95        println!("    {version} ({content})");
96    }
97
98    async fn print_namespace_map<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage>(
99        client: &Client<R, C, N>,
100    ) -> Result<()> {
101        if let Some(map) = client.namespace_map().load_namespace_map().await? {
102            for (namespace, registry) in map {
103                println!("  {namespace}={registry}");
104            }
105        };
106
107        Ok(())
108    }
109}