use std::io::Write;
use std::path::{Path, PathBuf};
use shep_core::config::{Depth, FlockFormat, Scaffold, discover};
use crate::{Streams, cli::InitArgs, commands::runtime::get_cwd, exit::ExitCode};
pub async fn init(streams: &mut Streams<'_>, args: &InitArgs) -> ExitCode {
let cwd = match get_cwd(streams) {
Ok(cwd) => cwd,
Err(code) => return code,
};
let (path, format) = match target(streams, &cwd, args) {
Ok(target) => target,
Err(code) => return code,
};
let text = match Scaffold::new(format, depth(args)).build() {
Ok(text) => text,
Err(err) => {
return streams.fail(ExitCode::Usage, &err.to_string());
}
};
let written = std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)
.and_then(|mut file| file.write_all(text.as_bytes()));
match written {
Ok(()) => {
streams.note("init", &format!("wrote {}", path.display()));
ExitCode::Success
}
Err(err) => streams.fail(ExitCode::Failure, &format!("{}: {err}", path.display())),
}
}
fn depth(args: &InitArgs) -> Depth {
if args.all { Depth::All } else { Depth::Curated }
}
fn target(
streams: &mut Streams<'_>,
cwd: &Path,
args: &InitArgs,
) -> Result<(PathBuf, FlockFormat), ExitCode> {
if let Some(given) = &args.path {
let path = cwd.join(given);
let Some(format) = FlockFormat::from_path(&path) else {
return Err(refuse(
streams,
&format!(
"{} is not a Flockfile shep can read; use .toml, .yaml, \
.yml, .json or .json5",
path.display()
),
));
};
if path.exists() && !args.force {
return Err(refuse(
streams,
&format!(
"{} already exists; pass --force to replace it",
path.display()
),
));
}
if let Some(existing) = discover(cwd)
&& existing != path
{
streams.aside(
"init_shadowed",
&format!(
"{} is already here and shep reads it first; {} will be ignored \
until you remove it",
existing.display(),
path.display()
),
);
}
return Ok((path, format));
}
match discover(cwd) {
Some(existing) => {
if !args.force {
return Err(refuse(
streams,
&format!(
"{} already exists; pass --force to replace it",
existing.display()
),
));
}
let format = FlockFormat::from_path(&existing).unwrap_or(FlockFormat::Toml);
Ok((existing, format))
}
None => Ok((cwd.join("Flockfile.toml"), FlockFormat::Toml)),
}
}
fn refuse(streams: &mut Streams<'_>, message: &str) -> ExitCode {
streams.fail(ExitCode::Usage, message)
}