Skip to main content

systemprompt_cli/commands/cloud/tenant/
select.rs

1use anyhow::{Result, anyhow, bail};
2use systemprompt_cloud::{
3    CloudCredentials, CloudPath, CredentialsBootstrap, StoredTenant, TenantType, get_cloud_paths,
4};
5use systemprompt_config::ProfileBootstrap;
6use systemprompt_identifiers::TenantId;
7
8use crate::interactive::Prompter;
9
10pub fn get_credentials() -> Result<CloudCredentials> {
11    if CredentialsBootstrap::is_initialized() {
12        return CredentialsBootstrap::require()
13            .map_err(|e| {
14                anyhow!(
15                    "Credentials required. Run 'systemprompt cloud login': {}",
16                    e
17                )
18            })?
19            .clone()
20            .pipe(Ok);
21    }
22
23    let cloud_paths = get_cloud_paths();
24    let creds_path = cloud_paths.resolve(CloudPath::Credentials);
25
26    if creds_path.exists() {
27        CloudCredentials::load_from_path(&creds_path).map_err(Into::into)
28    } else {
29        bail!("Not logged in. Run 'systemprompt cloud login' first.")
30    }
31}
32
33pub fn select_tenant<'a>(
34    prompter: &dyn Prompter,
35    tenants: &'a [StoredTenant],
36) -> Result<&'a StoredTenant> {
37    let options: Vec<String> = tenants
38        .iter()
39        .map(|t| {
40            let type_str = match t.tenant_type {
41                TenantType::Local => "local",
42                TenantType::Cloud => "cloud",
43            };
44            format!("{} ({})", t.name, type_str)
45        })
46        .collect();
47
48    let selection = prompter.select("Select tenant", &options)?;
49
50    Ok(&tenants[selection])
51}
52
53pub fn resolve_tenant_id(tenant: Option<String>) -> Result<TenantId> {
54    if let Some(id) = tenant {
55        return Ok(TenantId::new(id));
56    }
57
58    ProfileBootstrap::get()
59        .ok()
60        .and_then(|p| p.cloud.as_ref()?.tenant_id.as_ref().map(TenantId::new))
61        .ok_or_else(|| {
62            anyhow!("No tenant specified. Use --tenant or configure a tenant in your profile.")
63        })
64}
65
66trait Pipe: Sized {
67    fn pipe<F, R>(self, f: F) -> R
68    where
69        F: FnOnce(Self) -> R,
70    {
71        f(self)
72    }
73}
74
75impl<T> Pipe for T {}