use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use lds_core::config::{Config, tilde_expand};
#[derive(Debug, Parser)]
#[command(name = "lds", about = "Local develop server CLI")]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
#[command(name = "recipe-dir")]
RecipeDir {
#[command(subcommand)]
action: RecipeDirAction,
},
}
#[derive(Debug, Subcommand)]
pub enum RecipeDirAction {
Add {
path: String,
},
List,
Remove {
path: String,
},
}
pub fn run() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::RecipeDir { action } => handle_recipe_dir(action),
}
}
fn default_config_path() -> Result<PathBuf> {
let home = dirs::home_dir().context("HOME directory is not set")?;
Ok(home.join(".config/lds/config.toml"))
}
fn handle_recipe_dir(action: RecipeDirAction) -> Result<()> {
match action {
RecipeDirAction::Add { path } => cmd_add(&path),
RecipeDirAction::List => cmd_list(),
RecipeDirAction::Remove { path } => cmd_remove(&path),
}
}
fn cmd_add(raw: &str) -> Result<()> {
let expanded = tilde_expand(raw).with_context(|| format!("failed to expand path '{raw}'"))?;
let abs = std::path::absolute(&expanded)
.with_context(|| format!("failed to make path absolute: {}", expanded.display()))?;
let config_path = default_config_path()?;
let mut config = Config::load_or_default();
if config.recipes.dirs.contains(&abs) {
eprintln!(
"warn: '{}' is already in recipes.dirs — skipping",
abs.display()
);
return Ok(());
}
config.recipes.dirs.push(abs.clone());
Config::save(&config_path, &config.recipes.dirs)
.with_context(|| format!("failed to save config at {}", config_path.display()))?;
println!("added: {}", abs.display());
Ok(())
}
fn cmd_list() -> Result<()> {
let config = Config::load_or_default();
for dir in &config.recipes.dirs {
println!("{}", dir.display());
}
Ok(())
}
fn cmd_remove(raw: &str) -> Result<()> {
let expanded = tilde_expand(raw).with_context(|| format!("failed to expand path '{raw}'"))?;
let target = std::path::absolute(&expanded)
.with_context(|| format!("failed to make path absolute: {}", expanded.display()))?;
let config_path = default_config_path()?;
let mut config = Config::load_or_default();
let before = config.recipes.dirs.len();
config.recipes.dirs.retain(|p| p != &target);
if config.recipes.dirs.len() == before {
eprintln!("error: '{}' not found in recipes.dirs", target.display());
std::process::exit(1);
}
Config::save(&config_path, &config.recipes.dirs)
.with_context(|| format!("failed to save config at {}", config_path.display()))?;
println!("removed: {}", target.display());
Ok(())
}