90 lines
2.5 KiB
Rust
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(())
|
|
}
|