mod commands;
mod config;
mod config_sync;
mod diagnostics;
mod exec;
mod lock;
mod logger;
mod paths;
use commands::{
add::{run_add, run_edit_lists, run_manual_add, run_manual_add_secret},
audit::run_audit_secrets,
backup::run_backup,
bootstrap::run_bootstrap,
chezmoi::{
resolve_config_drift, run_apply, run_cd, run_diff, run_edit, run_forget, run_status,
run_update,
},
history::run_clean_history,
init_config::run_init_config,
logs::run_logs,
setup::run_setup,
sync::run_sync,
};
use config::Config;
use fp_dotfiles_catalog::format_cli_help;
use std::io;
fn print_help() {
print!("{}", format_cli_help());
}
fn main() -> io::Result<()> {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
print_help();
return Ok(());
}
let config = Config::load();
let subcommand = &args[1];
match subcommand.as_str() {
"init-config" => {
run_init_config()?;
}
"setup" => {
let mut repo_url = None;
let mut ssh_key = None;
let mut age_pass = None;
let mut force = false;
let mut i = 2;
while i < args.len() {
match args[i].as_str() {
"--repo-url" => {
if i + 1 < args.len() {
repo_url = Some(args[i + 1].clone());
i += 2;
} else {
eprintln!("Error: Missing value for --repo-url");
std::process::exit(1);
}
}
"--ssh-key" => {
if i + 1 < args.len() {
ssh_key = Some(args[i + 1].clone());
i += 2;
} else {
eprintln!("Error: Missing value for --ssh-key");
std::process::exit(1);
}
}
"--age-pass" => {
if i + 1 < args.len() {
age_pass = Some(args[i + 1].clone());
i += 2;
} else {
eprintln!("Error: Missing value for --age-pass");
std::process::exit(1);
}
}
"--force" | "-f" => {
force = true;
i += 1;
}
_ => {
eprintln!("Error: Unknown option {}", args[i]);
std::process::exit(1);
}
}
}
let final_repo_url = repo_url.unwrap_or(config.repo_url);
let final_ssh_key = ssh_key.unwrap_or(config.ssh_key_path);
let final_age_pass = age_pass.unwrap_or(config.age_pass);
run_setup(&final_repo_url, &final_ssh_key, &final_age_pass, force)?;
}
"bootstrap" => {
run_bootstrap(&config.bootstrap_dir, true)?;
}
"sync" => {
let mut dry_run = false;
if args.len() >= 3 {
if args[2] == "--dry-run" || args[2] == "-n" {
dry_run = true;
}
}
run_sync(config, dry_run)?;
}
"backup" => {
let mut output_path = None;
let mut age_pass = None;
let mut i = 2;
while i < args.len() {
match args[i].as_str() {
"--age-pass" => {
if i + 1 < args.len() {
age_pass = Some(args[i + 1].clone());
i += 2;
} else {
eprintln!("Error: Missing value for --age-pass");
std::process::exit(1);
}
}
_ => {
if args[i].starts_with('-') {
eprintln!("Error: Unknown option {}", args[i]);
std::process::exit(1);
} else if output_path.is_none() {
output_path = Some(args[i].clone());
i += 1;
} else {
eprintln!("Error: Multiple output paths specified");
std::process::exit(1);
}
}
}
}
let mut final_config = config;
if let Some(pass) = age_pass {
final_config.age_pass = pass;
}
run_backup(output_path, &final_config)?;
}
"add" => {
if args.len() < 3 {
eprintln!("Error: Missing targets");
std::process::exit(1);
}
let targets = args[2..].to_vec();
run_add(&targets, &config.tracked_file, &config.home)?;
}
"add-secret" => {
if args.len() < 3 {
eprintln!("Error: Missing targets");
std::process::exit(1);
}
let targets = args[2..].to_vec();
run_add(&targets, &config.tracked_enc_file, &config.home)?;
}
"manual-add" => {
if args.len() < 3 {
eprintln!("Error: Missing targets");
std::process::exit(1);
}
let targets = args[2..].to_vec();
run_manual_add(&targets, config.scan_policy())?;
}
"manual-add-secret" => {
if args.len() < 3 {
eprintln!("Error: Missing targets");
std::process::exit(1);
}
let targets = args[2..].to_vec();
run_manual_add_secret(&targets, config.scan_policy())?;
}
"audit-secrets" => {
let mut fix = false;
for arg in &args[2..] {
match arg.as_str() {
"--fix" | "-f" => fix = true,
_ => {
eprintln!("Error: Unknown option {}", arg);
std::process::exit(1);
}
}
}
run_audit_secrets(config, fix)?;
}
"update" => {
resolve_config_drift()?;
run_update()?;
}
"apply" => {
resolve_config_drift()?;
run_apply()?;
}
"cd" => {
run_cd()?;
}
"forget" => {
if args.len() < 3 {
eprintln!("Error: Missing targets");
std::process::exit(1);
}
let targets = args[2..].to_vec();
run_forget(&targets)?;
}
"status" => {
run_status()?;
}
"diff" => {
run_diff()?;
}
"edit" => {
if args.len() < 3 {
eprintln!("Error: Missing target");
std::process::exit(1);
}
let target = &args[2];
run_edit(target)?;
}
"logs" => {
run_logs(&args)?;
}
"edit-lists" => {
run_edit_lists(&config.tracked_file, &config.tracked_enc_file)?;
}
"clean-history" => {
let mut repo_path = None;
let mut i = 2;
while i < args.len() {
match args[i].as_str() {
"--repo-path" => {
if i + 1 < args.len() {
repo_path = Some(args[i + 1].clone());
i += 2;
} else {
eprintln!("Error: Missing value for --repo-path");
std::process::exit(1);
}
}
_ => {
eprintln!("Error: Unknown option {}", args[i]);
std::process::exit(1);
}
}
}
let final_repo_path = repo_path.unwrap_or(config.repo_path);
run_clean_history(&final_repo_path)?;
}
"help" | "-h" | "--help" => {
print_help();
}
_ => {
eprintln!("Unknown subcommand: {}", subcommand);
print_help();
std::process::exit(1);
}
}
Ok(())
}