pub mod build;
pub mod check;
pub mod doc;
pub mod doctor;
pub mod exit;
pub mod format;
pub mod generate;
pub mod lint;
pub mod output;
pub mod serve;
pub mod test;
pub mod thingd_schema;
use clap::{Parser, Subcommand, ValueEnum};
use output::Output;
#[derive(Parser)]
#[command(
name = "arqen",
version,
about = "Arqen CLI for generating and running applications"
)]
pub struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, global = true)]
json: bool,
#[arg(long, global = true)]
verbose: bool,
#[arg(long, global = true)]
quiet: bool,
#[arg(long, global = true, default_value = "auto")]
color: ColorChoice,
}
#[derive(Clone, Copy, Debug, ValueEnum)]
enum ColorChoice {
Auto,
Always,
Never,
}
#[derive(Subcommand)]
pub enum Commands {
New {
name: String,
},
Generate {
#[command(subcommand)]
kind: GenerateKind,
},
Dev {
#[arg(long)]
host: Option<String>,
#[arg(short, long)]
port: Option<u16>,
#[arg(short, long)]
log: Option<String>,
#[arg(short, long)]
storage: Option<String>,
#[arg(long, value_enum)]
log_format: Option<crate::config::LogFormat>,
#[arg(long = "file")]
config_file: Option<String>,
},
#[command(visible_alias = "run", alias = "serve")]
Start {
#[arg(long)]
host: Option<String>,
#[arg(short, long)]
port: Option<u16>,
#[arg(short, long)]
log: Option<String>,
#[arg(short, long)]
storage: Option<String>,
#[arg(long, value_enum)]
log_format: Option<crate::config::LogFormat>,
#[arg(long = "file")]
config_file: Option<String>,
},
Up {
#[arg(value_name = "SERVICE")]
services: Vec<String>,
#[arg(long, default_value = "arqen.toml")]
file: std::path::PathBuf,
#[arg(long)]
dry_run: bool,
},
Check,
Doctor,
Lint,
Format,
Test {
#[arg(long)]
release: bool,
},
Build {
#[arg(long)]
release: bool,
},
Doc,
Thingd {
#[command(subcommand)]
command: ThingdCommand,
},
}
#[derive(Subcommand)]
pub enum ThingdCommand {
SchemaValidate {
path: std::path::PathBuf,
#[arg(long)]
url: Option<String>,
#[arg(long)]
token: Option<String>,
},
SchemaRemote {
url: String,
#[arg(long)]
token: Option<String>,
},
}
#[derive(Subcommand)]
pub enum GenerateKind {
Module {
name: String,
},
Tool {
name: String,
},
Job {
name: String,
},
}
fn dispatch(cli: &Cli, output: &Output) -> anyhow::Result<()> {
match &cli.command {
Commands::New { name } => {
generate::generate_project(name, output)?;
}
Commands::Generate { kind } => match kind {
GenerateKind::Module { name } => generate::generate_module(name, output)?,
GenerateKind::Tool { name } => generate::generate_tool(name, output)?,
GenerateKind::Job { name } => generate::generate_job(name, output)?,
},
Commands::Dev {
host,
port,
log,
storage,
config_file,
log_format,
} => {
let code = serve::serve_dev(
config_file.as_deref(),
host.as_deref(),
*port,
log.as_deref(),
storage.as_deref(),
log_format.as_ref(),
output,
);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Start {
host,
port,
log,
storage,
config_file,
log_format,
} => {
let code = serve::serve_start(
config_file.as_deref(),
host.as_deref(),
*port,
log.as_deref(),
storage.as_deref(),
log_format.as_ref(),
output,
);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Up {
services,
file,
dry_run,
} => {
let rt = tokio::runtime::Runtime::new().map_err(|e| anyhow::anyhow!(e))?;
rt.block_on(crate::dev::run_up(file, services, *dry_run))?;
}
Commands::Check => {
let code = check::run_check(output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Doctor => {
let code = doctor::run_doctor(output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Lint => {
let code = lint::run_lint(output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Format => {
let code = format::run_format(output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Test { release } => {
let code = test::run_test(*release, output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Build { release } => {
let code = build::run_build(*release, output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Doc => {
let code = doc::run_doc(output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
Commands::Thingd { command } => {
let code = thingd_schema::run(command, output);
if code != exit::SUCCESS {
std::process::exit(code);
}
}
}
Ok(())
}
pub fn run() -> i32 {
let cli = Cli::parse();
let color = match cli.color {
ColorChoice::Auto => "auto",
ColorChoice::Always => "always",
ColorChoice::Never => "never",
};
let output = Output::from_args(cli.json, cli.quiet, cli.verbose, color);
match dispatch(&cli, &output) {
Ok(()) => exit::SUCCESS,
Err(e) => {
output.print_error(&e.to_string());
exit::RUNTIME
}
}
}