use std::fs;
use std::path::PathBuf;
use anyhow::{Context, bail};
use clap::{Args, Subcommand};
use crate::config_file::{LOCAL_FILE_NAME, home_config_path};
use crate::config_schema;
#[derive(Debug, Subcommand)]
pub enum ConfigCommand {
Init(ConfigInitArgs),
}
#[derive(Debug, Args)]
pub struct ConfigInitArgs {
#[arg(long, conflicts_with = "path")]
pub home: bool,
#[arg(long, value_name = "FILE")]
pub path: Option<PathBuf>,
#[arg(long)]
pub force: bool,
}
pub fn run(command: &ConfigCommand) -> anyhow::Result<()> {
match command {
ConfigCommand::Init(args) => run_init(args),
}
}
fn run_init(args: &ConfigInitArgs) -> anyhow::Result<()> {
let dest = resolve_dest(args)?;
if dest.exists() && !args.force {
bail!("{} already exists; pass --force to overwrite it", dest.display());
}
if let Some(parent) = dest.parent().filter(|p| !p.as_os_str().is_empty()) {
fs::create_dir_all(parent).with_context(|| format!("creating config directory {}", parent.display()))?;
}
fs::write(&dest, config_schema::render_default_toml())
.with_context(|| format!("writing config to {}", dest.display()))?;
println!("wrote {}", dest.display());
println!("Edit it, then launch the server from this directory (or pass --lake-root).");
Ok(())
}
fn resolve_dest(args: &ConfigInitArgs) -> anyhow::Result<PathBuf> {
if let Some(path) = args.path.as_deref() {
return Ok(path.to_path_buf());
}
if args.home {
return home_config_path()
.context("could not determine a home config directory; pass --path to choose a location");
}
Ok(PathBuf::from(LOCAL_FILE_NAME))
}
#[cfg(test)]
#[allow(clippy::expect_used)]
mod tests {
use super::*;
use clap::{Command, FromArgMatches};
fn parse(args: &[&str]) -> Result<ConfigInitArgs, clap::Error> {
let matches = ConfigInitArgs::augment_args(Command::new("init")).try_get_matches_from(args)?;
ConfigInitArgs::from_arg_matches(&matches)
}
#[test]
fn default_destination_is_the_project_local_file() {
let args = parse(&["init"]).expect("bare init parses");
assert_eq!(resolve_dest(&args).expect("dest"), PathBuf::from(LOCAL_FILE_NAME));
}
#[test]
fn explicit_path_wins_over_home() {
let args = parse(&["init", "--path", "/tmp/custom.toml"]).expect("path parses");
assert_eq!(resolve_dest(&args).expect("dest"), PathBuf::from("/tmp/custom.toml"));
}
#[test]
fn home_and_path_conflict() {
let err = parse(&["init", "--home", "--path", "/tmp/x.toml"]).expect_err("home + path conflict");
assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
}
}