use std::collections::BTreeMap;
use anyhow::Result;
use clap::{Parser, Subcommand};
use crate::{auth, verbs};
#[derive(Debug, Parser)]
#[command(
name = "hm cloud",
about = "Talk to the Harmont cloud API",
disable_help_subcommand = true
)]
struct CloudCli {
#[command(subcommand)]
command: CloudCommand,
}
#[derive(Debug, Clone, Subcommand)]
pub enum CloudCommand {
Login {
#[arg(long)]
paste: bool,
},
Logout,
Whoami,
#[command(subcommand)]
Org(OrgCommand),
#[command(subcommand)]
Pipeline(PipelineCommand),
#[command(subcommand)]
Build(BuildCommand),
#[command(subcommand)]
Job(JobCommand),
#[command(subcommand)]
Billing(BillingCommand),
Run(verbs::run::RunArgs),
}
#[derive(Debug, Clone, Subcommand)]
pub enum OrgCommand {
Switch {
slug: String,
},
}
#[derive(Debug, Clone, Subcommand)]
pub enum PipelineCommand {
List,
Show { slug: String },
}
#[derive(Debug, Clone, Subcommand)]
pub enum BuildCommand {
List {
#[arg(short, long)]
pipeline: String,
},
Show {
#[arg(short, long)]
pipeline: String,
number: i64,
},
Cancel {
#[arg(short, long)]
pipeline: String,
number: i64,
},
Watch {
#[arg(short, long)]
pipeline: String,
number: i64,
},
}
#[derive(Debug, Clone, Subcommand)]
pub enum JobCommand {
List {
#[arg(short, long)]
pipeline: String,
#[arg(short, long)]
build: i64,
},
Show {
#[arg(short, long)]
pipeline: String,
#[arg(short, long)]
build: i64,
job_id: String,
},
Log {
#[arg(short, long)]
pipeline: String,
#[arg(short, long)]
build: i64,
job_id: String,
},
}
#[derive(Debug, Clone, Subcommand)]
pub enum BillingCommand {
Balance,
Transactions {
#[arg(long, default_value = "100")]
limit: u32,
},
Usage {
#[arg(long)]
from: Option<String>,
#[arg(long)]
to: Option<String>,
},
Topup {
amount_usd: u32,
#[arg(long)]
no_browser: bool,
},
Redeem { code: String },
}
pub async fn dispatch(argv: Vec<String>, env: BTreeMap<String, String>) -> Result<i32> {
let mut full: Vec<String> = vec!["hm cloud".to_string()];
full.extend(argv.into_iter().skip(1));
let parsed = match CloudCli::try_parse_from(&full) {
Ok(p) => p,
Err(e) => {
use clap::error::ErrorKind;
let msg = e.to_string();
return match e.kind() {
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => {
#[allow(clippy::print_stdout)]
{
use std::io::Write;
std::io::stdout().write_all(msg.as_bytes()).ok();
}
Ok(0)
}
_ => {
#[allow(clippy::print_stderr)]
{
use std::io::Write;
std::io::stderr().write_all(msg.as_bytes()).ok();
}
Ok(2)
}
};
}
};
dispatch_command(parsed.command, env).await
}
pub async fn dispatch_command(command: CloudCommand, env: BTreeMap<String, String>) -> Result<i32> {
let result = match command {
CloudCommand::Login { paste } => auth::login::run(&env, paste).await,
CloudCommand::Logout => auth::logout::run(&env).await,
CloudCommand::Whoami => auth::whoami::run(&env).await,
CloudCommand::Org(cmd) => verbs::org::run(&env, cmd).await,
CloudCommand::Pipeline(cmd) => verbs::pipeline::run(&env, cmd).await,
CloudCommand::Build(cmd) => verbs::build::run(&env, cmd).await,
CloudCommand::Job(cmd) => verbs::job::run(&env, cmd).await,
CloudCommand::Billing(cmd) => verbs::billing::run(&env, cmd).await,
CloudCommand::Run(args) => verbs::run::run(&env, args).await,
};
match result {
Ok(()) => Ok(0),
Err(e) => {
tracing::error!("{e:#}");
Ok(1)
}
}
}