Files
xboct-deploy/src/main.rs
T

90 lines
2.5 KiB
Rust

mod cli;
mod config;
mod local;
use std::process::ExitCode;
use anyhow::{Context, Result};
use clap::Parser;
use colored::Colorize;
fn main() -> ExitCode {
let cli = cli::Cli::parse();
match run(&cli) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
eprintln!("{} {err:#}", "error:".red().bold());
ExitCode::FAILURE
}
}
}
fn run(cli: &cli::Cli) -> Result<()> {
let path = config::resolve(cli.config.as_deref())?;
let cfg = config::load(&path)?;
if cli.list {
println!("config: {}", path.display());
println!("configured projects:");
for name in cfg.projects.keys() {
println!(" - {name}");
}
return Ok(());
}
let name = cli
.project
.as_deref()
.expect("clap guarantees <PROJECT> or --list");
let project = cfg
.projects
.get(name)
.with_context(|| format!("project '{name}' not found in {}", path.display()))?;
let target = match &project.user {
Some(user) => format!("{user}@{}:{}", project.host, project.port),
None => format!("{}:{}", project.host, project.port),
};
println!(
"deploying '{name}' to {target}: {} local cmd(s), {} sync rule(s), {} remote cmd(s)",
project.local.as_ref().map_or(0, |c| c.commands.len()),
project.sync.len(),
project.remote.as_ref().map_or(0, |c| c.commands.len()),
);
let local_cmds = project
.local
.as_ref()
.map_or([].as_slice(), |c| c.commands.as_slice());
let remote_cmds = project
.remote
.as_ref()
.map_or([].as_slice(), |c| c.commands.as_slice());
if cli.dry_run {
println!("dry-run plan:");
for cmd in local_cmds {
println!(" local : {cmd}");
}
for rule in &project.sync {
println!(
" sync : {} -> {}",
rule.source.display(),
rule.target.display()
);
}
for cmd in remote_cmds {
println!(" remote: {cmd}");
}
} else {
local::run_commands(local_cmds, &project.workdir)?;
println!("[Local] done: {} cmd(s) succeeded", local_cmds.len());
if !project.sync.is_empty() {
println!("stage 4 not implemented yet: SFTP file transfer");
}
if !remote_cmds.is_empty() {
println!("stage 3 not implemented yet: SSH remote execution");
}
}
Ok(())
}