#![allow(clippy::result_large_err)]
use std::path::PathBuf;
use clap::Parser;
use clingwrap::config::ConfigLoader;
use directories::ProjectDirs;
use ambient_ci::{
config::{Config, ConfigError, StoredConfig},
runlog::{RunLog, RunLogSource},
};
mod cmd;
use cmd::{AmbientError, Leaf};
const QUAL: &str = "liw.fi";
const ORG: &str = "Ambient CI";
const APP: &str = env!("CARGO_BIN_NAME");
fn main() {
let mut runlog = RunLog::default();
if let Err(e) = fallible_main(&mut runlog) {
eprintln!("ERROR: {e}");
let mut source = e.source();
while let Some(src) = source {
eprintln!("caused by: {src}");
source = src.source();
}
std::process::exit(1);
}
}
fn fallible_main(runlog: &mut RunLog) -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
runlog.ambient_starts(RunLogSource::Prelude, APP, env!("CARGO_PKG_VERSION"));
let config = args.config()?;
runlog.ambient_runtime_config(RunLogSource::Prelude, &config);
match &args.cmd {
Command::Actions(x) => x.run(&config, runlog)?,
Command::Config(x) => x.run(&config, runlog)?,
Command::Image(x) => x.run(&config, runlog)?,
Command::Log(x) => x.run(&config, runlog)?,
Command::Plan(x) => x.run(&config, runlog)?,
Command::Projects(x) => x.run(&config, runlog)?,
Command::Qemu(x) => x.run(&config, runlog)?,
Command::Run(x) => x.run(&config, runlog)?,
Command::State(x) => x.run(&config, runlog)?,
}
runlog.ambient_ends_successfully(RunLogSource::Epilog);
Ok(())
}
#[derive(Debug, Parser)]
#[clap(name = APP, version = env!("VERSION"))]
pub struct Args {
#[clap(long)]
config: Vec<PathBuf>,
#[clap(long)]
no_config: bool,
#[clap(subcommand)]
cmd: Command,
}
impl Args {
fn config(&self) -> Result<Config, ConfigError> {
let mut loader = ConfigLoader::default();
if self.no_config {
} else {
let dirs = ProjectDirs::from(QUAL, ORG, APP).ok_or(ConfigError::ProjectDirs)?;
let filename = dirs.config_dir().join("config.yaml");
loader.allow_yaml(&filename);
}
for filename in self.config.iter() {
loader.require_yaml(filename);
}
let validator = StoredConfig::default();
let config = loader
.load(None, None, &validator)
.map_err(ConfigError::Load)?;
Ok(config)
}
}
#[derive(Debug, Parser)]
enum Command {
Actions(cmd::actions::Actions),
Image(ImageCmd),
Config(cmd::config::ConfigCmd),
Log(cmd::log::Log),
Plan(cmd::plan::Plan),
Projects(cmd::projects::ProjectsCmd),
Qemu(cmd::qemu::QemuCmd),
Run(cmd::run::Run),
State(cmd::state::State),
}
#[derive(Debug, Parser)]
pub struct ImageCmd {
#[clap(subcommand)]
cmd: ImageSubCmd,
}
impl ImageCmd {
fn run(&self, config: &Config, runlog: &mut RunLog) -> Result<(), AmbientError> {
match &self.cmd {
ImageSubCmd::CloudInit(x) => x.run(config, runlog)?,
ImageSubCmd::Import(x) => x.run(config, runlog)?,
ImageSubCmd::List(x) => x.run(config, runlog)?,
ImageSubCmd::Prepare(x) => x.run(config, runlog)?,
ImageSubCmd::Remove(x) => x.run(config, runlog)?,
ImageSubCmd::Show(x) => x.run(config, runlog)?,
ImageSubCmd::Verify(x) => x.run(config, runlog)?,
}
Ok(())
}
}
#[derive(Debug, Parser)]
enum ImageSubCmd {
CloudInit(cmd::image::CloudInit),
Import(cmd::image::ImportImage),
List(cmd::image::ListImages),
Prepare(cmd::image::PrepareImage),
Remove(cmd::image::RemoveImages),
Show(cmd::image::ShowImage),
Verify(cmd::image::VerifyImage),
}