1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use super::CommonOptions;
use anyhow::Result;
use clap::{ArgAction, Args};
use warg_client::{
    keyring::Keyring,
    storage::{ContentStorage, NamespaceMapStorage, PackageInfo, RegistryStorage},
    Client,
};
use warg_crypto::hash::AnyHash;
use warg_protocol::{registry::PackageName, Version};

/// Display client storage information.
#[derive(Args)]
pub struct InfoCommand {
    /// The common command options.
    #[clap(flatten)]
    pub common: CommonOptions,

    /// Only show information for the specified package.
    #[clap(value_name = "PACKAGE")]
    pub package: Option<PackageName>,

    /// Only show the namespace map
    #[clap(short, long, value_name = "NAMESPACES", action = ArgAction::SetTrue)]
    pub namespaces: bool,
}

impl InfoCommand {
    /// Executes the command.
    pub async fn exec(self) -> Result<()> {
        let config = self.common.read_config()?;
        let client = self.common.create_client(&config).await?;

        print!("\nRegistry: {url} ", url = client.url().registry_domain());
        if config.keyring_auth
            && Keyring::from_config(&config)?
                .get_auth_token(client.url())?
                .is_some()
        {
            println!(
                "(Using credentials{keyring_backend})",
                keyring_backend = if let Some(keyring_backend) = &config.keyring_backend {
                    format!(" stored in `{keyring_backend}` keyring backend")
                } else {
                    "".to_string()
                }
            );
        } else {
            println!("(Not logged in)");
        }
        println!("\nPackages in client storage:");
        match self.package {
            Some(package) => {
                let info = client.package(&package).await?;
                if let Some(registry) = client.get_warg_registry(package.namespace()).await? {
                    println!("Registry: {registry}");
                }
                Self::print_package_info(&info);
            }
            None => {
                client
                    .registry()
                    .load_all_packages()
                    .await?
                    .iter()
                    .for_each(|(registry, packages)| {
                        println!("\nRegistry: {registry}");
                        packages.iter().for_each(Self::print_package_info);
                    });
            }
        }

        if self.namespaces {
            println!("\nNamespace mappings in client storage");
            Self::print_namespace_map(&client).await?;
            return Ok(());
        }

        println!();

        Ok(())
    }

    fn print_package_info(info: &PackageInfo) {
        println!("  Name: {name}", name = info.name);
        println!("  Versions:");
        info.state.releases().for_each(|r| {
            if let Some(content) = r.content() {
                Self::print_release(&r.version, content);
            }
        });
    }

    fn print_release(version: &Version, content: &AnyHash) {
        println!("    {version} ({content})");
    }

    async fn print_namespace_map<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage>(
        client: &Client<R, C, N>,
    ) -> Result<()> {
        if let Some(map) = client.namespace_map().load_namespace_map().await? {
            for (namespace, registry) in map {
                println!("  {namespace}={registry}");
            }
        };

        Ok(())
    }
}