use anyhow::{bail, Context};
use wasmer_api::backend::gql::DeployApp;
use wasmer_deploy_schema::schema::AppConfigV1;
use crate::{cmd::AsyncCliCommand, ApiOpts, ItemFormatOpts};
use super::AppIdent;
#[derive(clap::Parser, Debug)]
pub struct CmdAppGet {
#[clap(flatten)]
api: ApiOpts,
#[clap(flatten)]
fmt: ItemFormatOpts,
ident: Option<AppIdent>,
}
impl CmdAppGet {
async fn run(self) -> Result<(), anyhow::Error> {
let app = self.get_app().await?;
println!("{}", self.fmt.format.render(&app));
Ok(())
}
async fn get_app(&self) -> Result<DeployApp, anyhow::Error> {
let client = self.api.client()?;
let app = if let Some(ident) = &self.ident {
ident.resolve(&client).await?
} else {
let (config, app_config_path) = Self::get_app_config_from_current_dir()?;
eprintln!("Loaded app config from: {}", app_config_path.display());
if let Some(app_id) = config.app_id {
AppIdent::AppId(app_id.clone())
.resolve(&client)
.await
.with_context(|| format!("Could not find app with id '{}'", app_id))?
} else {
let user_accessible_apps =
wasmer_api::backend::user_accessible_apps(&client).await?;
let apps = user_accessible_apps
.iter()
.filter(|app| app.name == config.name)
.collect::<Vec<_>>();
if apps.len() > 1 {
let names = apps
.iter()
.map(|app| format!("{}/{}", app.owner.global_name, app.name))
.collect::<Vec<_>>()
.join(",");
bail!(
"Found multiple applicable with the name '{}': {}",
config.name,
names
);
}
apps.get(0)
.map(|x| (**x).clone())
.with_context(|| format!("Could not find app named '{}'", config.name))?
}
};
Ok(app)
}
fn get_app_config_from_current_dir() -> Result<(AppConfigV1, std::path::PathBuf), anyhow::Error>
{
let current_dir = std::env::current_dir()?;
let app_config_path = current_dir.join(AppConfigV1::CANONICAL_FILE_NAME);
if !app_config_path.exists() || !app_config_path.is_file() {
bail!(
"Could not find app.yaml at path: '{}'.\nPlease specify an app like 'wasmer app get <namespace>/<name>' or 'wasmer app get <name>`'",
app_config_path.display()
);
}
let raw_app_config = std::fs::read_to_string(&app_config_path)
.with_context(|| format!("Could not read file '{}'", app_config_path.display()))?;
let config = AppConfigV1::parse_yaml(&raw_app_config)
.map_err(|err| anyhow::anyhow!("Could not parse app.yaml: {err:?}"))?;
Ok((config, app_config_path))
}
}
impl AsyncCliCommand for CmdAppGet {
fn run_async(self) -> futures::future::BoxFuture<'static, Result<(), anyhow::Error>> {
Box::pin(self.run())
}
}
#[derive(clap::Parser, Debug)]
pub struct CmdAppInfo {
#[clap(flatten)]
api: ApiOpts,
#[clap(flatten)]
fmt: ItemFormatOpts,
ident: Option<AppIdent>,
}
impl CmdAppInfo {
async fn run(self) -> Result<(), anyhow::Error> {
let cmd_app_get = CmdAppGet {
api: self.api,
fmt: self.fmt,
ident: self.ident,
};
let app = cmd_app_get.get_app().await?;
let app_url = app.url;
let versioned_url = app.active_version.url;
let dashboard_url = app.admin_url;
eprintln!(" App Info ");
eprintln!("> App Name: {}", app.name);
eprintln!("> App URL: {}", app_url);
eprintln!("> Versioned URL: {}", versioned_url);
eprintln!("> Admin dashboard: {}", dashboard_url);
Ok(())
}
}
impl AsyncCliCommand for CmdAppInfo {
fn run_async(self) -> futures::future::BoxFuture<'static, Result<(), anyhow::Error>> {
Box::pin(self.run())
}
}