use std::path::PathBuf;
use crate::config;
use crate::error::{Error, Result};
use clap::Args;
pub fn run(a: InitSubcmd) -> Result<()> {
let target = if a.global {
config::user_config_path().ok_or_else(|| Error::InvalidArg {
arg: "--global",
reason: "could not resolve user config path (is $HOME set?)".to_string(),
})?
} else {
PathBuf::from(".enprot.toml")
};
if target.exists() && !a.force {
return Err(Error::Io(std::io::Error::new(
std::io::ErrorKind::AlreadyExists,
format!(
"{} already exists; pass --force to overwrite",
target.display()
),
)));
}
if let Some(parent) = target.parent() {
std::fs::create_dir_all(parent)?;
}
std::fs::write(&target, config::Config::template())?;
println!("wrote {}", target.display());
if a.git {
init_gitattributes()?;
configure_git_filters(&a.git_word)?;
}
let cas_path = PathBuf::from("cas");
if !cas_path.exists() {
std::fs::create_dir(&cas_path)?;
eprintln!("created {}", cas_path.display());
}
Ok(())
}
fn init_gitattributes() -> Result<()> {
let path = PathBuf::from(".gitattributes");
let line = "*.ept filter=enprot diff=enprot merge=enprot\n";
if path.exists() {
let existing = std::fs::read_to_string(&path)?;
if existing.contains("filter=enprot") {
println!("{} already routes enprot; left as is", path.display());
} else {
std::fs::write(&path, format!("{existing}\n{line}"))?;
println!("appended enprot entry to {}", path.display());
}
} else {
std::fs::write(
&path,
format!("# Route *.ept through enprot's clean/smudge filters.\n{line}"),
)?;
println!("wrote {}", path.display());
}
Ok(())
}
fn configure_git_filters(words: &[String]) -> Result<()> {
if !PathBuf::from(".git").exists() {
println!("not a git repository; skipped .git/config (attributes still written)");
return Ok(());
}
let word_flags: String = words
.iter()
.map(|w| format!(" -w {w}"))
.collect::<Vec<_>>()
.join("");
let entries = [
("filter.enprot.clean", format!("enprot clean{word_flags}")),
("filter.enprot.smudge", format!("enprot smudge{word_flags}")),
("filter.enprot.required", "false".to_string()),
(
"diff.enprot.textconv",
format!("enprot textconv{word_flags}"),
),
(
"merge.enprot.driver",
"enprot merge-driver %O %A %B %P".to_string(),
),
("merge.enprot.name", "enprot WORD-aware merge".to_string()),
];
for (key, value) in entries {
let status = std::process::Command::new("git")
.args(["config", key, &value])
.status()
.map_err(|e| Error::Io(std::io::Error::other(format!("git config {key}: {e}"))))?;
if !status.success() {
return Err(Error::InvalidArg {
arg: "--git",
reason: format!("git config {key} failed"),
});
}
println!("git config {key} = {value}");
}
println!(
"\nFilters degrade gracefully without credentials (required=false). \
To decrypt on checkout, add `-k WORD=PASSWORD` to \
filter.enprot.smudge (or a credential helper of your choosing)."
);
Ok(())
}
#[derive(Args)]
pub struct InitSubcmd {
#[arg(long)]
pub global: bool,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub git: bool,
#[arg(long = "git-word", value_name = "WORD")]
pub git_word: Vec<String>,
}