use std::path::PathBuf;
use bel7_cli::{ExitCode, ExitCodeProvider, print_error, print_info};
use frm::cli::{CompletionShell, build_cli, get_version_arg};
use frm::commands;
use frm::errors::Error;
use frm::paths::Paths;
use frm::releases::{find_latest_alpha, find_latest_ga_release};
use frm::shell::Shell;
use frm::version::Version;
fn resolve_version(paths: &Paths, version_arg: Option<&String>) -> Result<Version, Error> {
if let Some(v) = version_arg {
let v = v.trim();
if v.eq_ignore_ascii_case("latest") {
return paths
.latest_ga_version()?
.ok_or(Error::NoGAVersionsInstalled);
}
return v.parse().map_err(Into::into);
}
Err(Error::InvalidVersion("no version specified".into()))
}
fn resolve_alpha_version(paths: &Paths, version_arg: Option<&String>) -> Result<Version, Error> {
if let Some(v) = version_arg {
let v = v.trim();
if v.eq_ignore_ascii_case("latest") {
return paths
.latest_alpha_version()?
.ok_or(Error::NoAlphaVersionsInstalled);
}
return v.parse().map_err(Into::into);
}
Err(Error::InvalidVersion("no version specified".into()))
}
#[tokio::main]
async fn main() -> ExitCode {
let matches = build_cli().get_matches();
let paths = match Paths::new() {
Ok(p) => p,
Err(e) => {
print_error(e.to_string());
return ExitCode::Config;
}
};
let result = match matches.subcommand() {
Some(("status", _)) => commands::status(&paths),
Some(("releases", sub)) => match sub.subcommand() {
Some(("list", _)) => commands::list_releases(&paths),
Some(("completions", completions_sub)) => {
let shell = completions_sub.get_one::<Shell>("shell").copied();
commands::completions_releases(&paths, shell)
}
Some(("path", path_sub)) => {
let version_arg = path_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::path_release(&paths, &version),
Err(e) => Err(e),
}
}
Some(("install", install_sub)) => {
let version_arg = get_version_arg(install_sub);
let force = install_sub.get_flag("force");
match version_arg {
Some(v) if v.trim().eq_ignore_ascii_case("latest") => {
print_info("Listing GA releases on GitHub...");
let client = reqwest::Client::new();
match find_latest_ga_release(&client).await {
Ok(v) => {
print_info(format!("Found latest GA release: {}", v));
commands::install_release(&paths, &v, force).await
}
Err(e) => Err(e),
}
}
Some(v) => match v.parse::<Version>() {
Ok(version) => commands::install_release(&paths, &version, force).await,
Err(e) => Err(e.into()),
},
None => Err(Error::InvalidVersion("no version specified".into())),
}
}
Some(("reinstall", reinstall_sub)) => {
let version_arg = get_version_arg(reinstall_sub);
match resolve_version(&paths, version_arg) {
Ok(version) => commands::reinstall_release(&paths, &version).await,
Err(e) => Err(e),
}
}
Some(("uninstall", uninstall_sub)) => {
let version_arg = get_version_arg(uninstall_sub);
match resolve_version(&paths, version_arg) {
Ok(version) => commands::uninstall_release(&paths, &version),
Err(e) => Err(e),
}
}
Some(("logs", logs_sub)) => match logs_sub.subcommand() {
Some(("path", path_sub)) => {
let version_arg = path_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::logs_path_release(&paths, &version),
Err(e) => Err(e),
}
}
Some(("tail", tail_sub)) => {
let version_arg = tail_sub.get_one::<String>("version");
let lines = *tail_sub.get_one::<usize>("lines").unwrap();
match resolve_version(&paths, version_arg) {
Ok(version) => commands::logs_tail_release(&paths, &version, lines),
Err(e) => Err(e),
}
}
_ => Ok(()),
},
Some(("cp-etc-file", cp_sub)) => {
let local_path = cp_sub
.get_one::<String>("local_file_path")
.map(PathBuf::from)
.unwrap();
let etc_file_str = cp_sub.get_one::<String>("etc_file").unwrap();
let version_arg = cp_sub.get_one::<String>("version");
match etc_file_str.parse::<commands::EtcFile>() {
Ok(etc_file) => match resolve_version(&paths, version_arg) {
Ok(version) => {
commands::cp_etc_file_release(&paths, &version, &local_path, etc_file)
}
Err(e) => Err(e),
},
Err(e) => Err(e),
}
}
Some(("use", use_sub)) => {
let version_arg = get_version_arg(use_sub);
let shell = use_sub.get_one::<Shell>("shell").copied();
match resolve_version(&paths, version_arg) {
Ok(version) => commands::use_release_version(&paths, &version, shell),
Err(e) => Err(e),
}
}
Some(("check-signature", check_sub)) => {
let version_arg = check_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::check_signature(&paths, &version).await,
Err(e) => Err(e),
}
}
_ => Ok(()),
},
Some(("alphas", sub)) => match sub.subcommand() {
Some(("list", _)) => commands::list_alphas(&paths),
Some(("completions", completions_sub)) => {
let shell = completions_sub.get_one::<Shell>("shell").copied();
commands::completions_alphas(&paths, shell)
}
Some(("path", path_sub)) => {
let version_arg = path_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::path_alpha(&paths, &version),
Err(e) => Err(e),
}
}
Some(("install", install_sub)) => {
let version_arg = get_version_arg(install_sub);
let force = install_sub.get_flag("force");
match version_arg {
Some(v) if v.trim().eq_ignore_ascii_case("latest") => {
print_info("Fetching latest alpha release...");
let client = reqwest::Client::new();
match find_latest_alpha(&client).await {
Ok(alpha) => {
print_info(format!("Found: {}", alpha.version));
commands::install_alpha(&paths, &alpha.version, force).await
}
Err(e) => Err(e),
}
}
Some(v) => match v.parse::<Version>() {
Ok(version) => commands::install_alpha(&paths, &version, force).await,
Err(e) => Err(e.into()),
},
None => Err(Error::InvalidVersion("no version specified".into())),
}
}
Some(("reinstall", reinstall_sub)) => {
let version_arg = get_version_arg(reinstall_sub);
match resolve_alpha_version(&paths, version_arg) {
Ok(version) => commands::reinstall_alpha(&paths, &version).await,
Err(e) => Err(e),
}
}
Some(("uninstall", uninstall_sub)) => {
let version_arg = get_version_arg(uninstall_sub);
match resolve_alpha_version(&paths, version_arg) {
Ok(version) => commands::uninstall_alpha(&paths, &version),
Err(e) => Err(e),
}
}
Some(("use", use_sub)) => {
let version_arg = get_version_arg(use_sub);
let shell = use_sub.get_one::<Shell>("shell").copied();
match resolve_alpha_version(&paths, version_arg) {
Ok(version) => commands::use_alpha_version(&paths, &version, shell),
Err(e) => Err(e),
}
}
Some(("cp-etc-file", cp_sub)) => {
let local_path = cp_sub
.get_one::<String>("local_file_path")
.map(PathBuf::from)
.unwrap();
let etc_file_str = cp_sub.get_one::<String>("etc_file").unwrap();
let version_arg = cp_sub.get_one::<String>("version");
match etc_file_str.parse::<commands::EtcFile>() {
Ok(etc_file) => match resolve_alpha_version(&paths, version_arg) {
Ok(version) => {
commands::cp_etc_file_alpha(&paths, &version, &local_path, etc_file)
}
Err(e) => Err(e),
},
Err(e) => Err(e),
}
}
Some(("prune", _)) => commands::prune_alphas(&paths),
Some(("clean", clean_sub)) => {
let older_than = clean_sub.get_one::<String>("older_than").unwrap();
commands::clean_alphas(&paths, older_than)
}
Some(("logs", logs_sub)) => match logs_sub.subcommand() {
Some(("path", path_sub)) => {
let version_arg = path_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::logs_path_alpha(&paths, &version),
Err(e) => Err(e),
}
}
Some(("tail", tail_sub)) => {
let version_arg = tail_sub.get_one::<String>("version");
let lines = *tail_sub.get_one::<usize>("lines").unwrap();
match resolve_version(&paths, version_arg) {
Ok(version) => commands::logs_tail_alpha(&paths, &version, lines),
Err(e) => Err(e),
}
}
_ => Ok(()),
},
_ => Ok(()),
},
Some(("tanzu", sub)) => match sub.subcommand() {
Some(("install", install_sub)) => {
let tarball_path = install_sub
.get_one::<String>("tarball_path")
.map(PathBuf::from)
.unwrap();
let version_str = install_sub.get_one::<String>("version").unwrap();
let force = install_sub.get_flag("force");
match version_str.parse::<Version>() {
Ok(version) => commands::tanzu_install(&paths, &tarball_path, &version, force),
Err(e) => Err(e.into()),
}
}
Some(("use", use_sub)) => {
let version_arg = get_version_arg(use_sub);
let shell = use_sub.get_one::<Shell>("shell").copied();
match resolve_version(&paths, version_arg) {
Ok(version) => commands::use_release_version(&paths, &version, shell),
Err(e) => Err(e),
}
}
_ => Ok(()),
},
Some(("conf", sub)) => match sub.subcommand() {
Some(("get-key", get_sub)) => {
let key = get_sub.get_one::<String>("key").unwrap();
let version_arg = get_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::conf_get_key(&paths, &version, key),
Err(e) => Err(e),
}
}
Some(("set-key", set_sub)) => {
let key = set_sub.get_one::<String>("key").unwrap();
let value = set_sub.get_one::<String>("value").unwrap();
let version_arg = set_sub.get_one::<String>("version");
let force = set_sub.get_flag("force");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::conf_set_key(&paths, &version, key, value, force),
Err(e) => Err(e),
}
}
_ => Ok(()),
},
Some(("default", sub)) => {
let version_arg = get_version_arg(sub);
match resolve_version(&paths, version_arg) {
Ok(version) => commands::default(&paths, &version),
Err(e) => Err(e),
}
}
Some(("cli", sub)) => {
let tool = sub.get_one::<String>("tool").unwrap();
let version_arg = sub.get_one::<String>("version");
let args: Vec<String> = sub
.get_many::<String>("args")
.map(|v| v.cloned().collect())
.unwrap_or_default();
match resolve_version(&paths, version_arg) {
Ok(version) => commands::cli(&paths, &version, tool, &args),
Err(e) => Err(e),
}
}
Some(("fg", sub)) => match sub.subcommand() {
Some(("node", fg_sub)) => {
let version_arg = fg_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::fg_node(&paths, &version),
Err(e) => Err(e),
}
}
_ => Ok(()),
},
Some(("bg", sub)) => match sub.subcommand() {
Some(("start", start_sub)) => {
let version_arg = start_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::bg_start(&paths, &version),
Err(e) => Err(e),
}
}
Some(("stop", stop_sub)) => {
let version_arg = stop_sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::bg_stop(&paths, &version),
Err(e) => Err(e),
}
}
_ => Ok(()),
},
Some(("inspect", sub)) => {
let file = sub.get_one::<String>("file").unwrap();
let version_arg = sub.get_one::<String>("version");
match resolve_version(&paths, version_arg) {
Ok(version) => commands::inspect(&paths, &version, file),
Err(e) => Err(e),
}
}
Some(("shell", sub)) => match sub.subcommand() {
Some(("env", env_sub)) => {
let shell = env_sub.get_one::<Shell>("shell").unwrap();
commands::env(&paths, *shell)
}
Some(("completions", completions_sub)) => {
let shell = completions_sub
.get_one::<CompletionShell>("shell")
.copied()
.unwrap_or_else(CompletionShell::detect);
commands::completions(shell)
}
_ => Ok(()),
},
_ => Ok(()),
};
match result {
Ok(()) => ExitCode::Ok,
Err(e) => {
print_error(e.to_string());
e.exit_code()
}
}
}