use std::path::{Path, PathBuf};
use nichlink_build_method::scaffold::{self, DependencySource, ProjectKind};
pub(crate) fn new(args: &mut impl Iterator<Item = String>) -> Result<(), String> {
let mut name: Option<String> = None;
let mut lib = false;
let mut path: Option<PathBuf> = None;
let mut git: Option<String> = None;
let mut args = args.by_ref().peekable();
while let Some(arg) = args.next() {
match arg.as_str() {
"--lib" => lib = true,
"--path" => {
let value = args.next().ok_or("--path requires a directory")?;
let directory = std::fs::canonicalize(&value)
.map_err(|error| format!("--path {value}: {error}"))?;
if !is_checkout(&directory) {
return Err(format!(
"--path {value} is not a NichLink checkout: it has no core/, build_method/ \
and run_method/"
));
}
path = Some(directory);
}
"--git" => git = Some(args.next().ok_or("--git requires a URL")?),
_ if name.is_none() => name = Some(arg),
_ => return Err(format!("unexpected argument '{arg}'")),
}
}
let name = name.ok_or("new requires a package name")?;
let source = match (path, git) {
(Some(workspace), _) => DependencySource::Local { workspace },
(None, Some(url)) => DependencySource::Git { url },
(None, None) => scaffold::detected_source(
Path::new(env!("CARGO_MANIFEST_DIR")),
&std::env::current_exe()
.map_err(|error| format!("cannot locate current executable: {error}"))?,
),
};
let root = std::env::current_dir()
.map_err(|error| format!("cannot read current directory: {error}"))?
.join(&name);
let kind = if lib {
ProjectKind::Library
} else {
ProjectKind::Binary
};
scaffold::create_project(&root, &name, kind, &source)?;
println!(
"created {} project at {}",
if lib { "library" } else { "binary" },
root.display()
);
Ok(())
}
fn is_checkout(workspace: &Path) -> bool {
workspace.join("core").is_dir()
&& workspace.join("build_method").is_dir()
&& workspace.join("run_method").is_dir()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_a_real_checkout_is_accepted() {
let root =
std::env::temp_dir().join(format!("nichlink-new-checkout-{}", std::process::id()));
std::fs::create_dir_all(&root).expect("fixture directory");
assert!(!is_checkout(&root), "an empty directory is not a checkout");
for directory in ["core", "build_method", "run_method"] {
std::fs::create_dir_all(root.join(directory)).expect("fixture directory");
}
assert!(is_checkout(&root), "the three crates make it a checkout");
let _ = std::fs::remove_dir_all(&root);
}
}