use crate::GeneratorContext;
use anyhow::anyhow;
use camino::Utf8Path;
use include_dir::{Dir, include_dir};
use toml_edit::{Array, DocumentMut, value};
static SKELETON: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/skeleton");
pub fn generate_cargo_toml(context: &GeneratorContext<'_>) -> anyhow::Result<()> {
let cargo_toml = SKELETON
.get_file("Cargo.toml_")
.or_else(|| SKELETON.get_file("Cargo.toml"))
.ok_or_else(|| anyhow!("Missing Cargo.toml skeleton"))?
.contents_utf8()
.ok_or_else(|| anyhow!("Cargo.toml skeleton is not valid UTF-8"))?;
let mut doc = cargo_toml
.parse::<DocumentMut>()
.map_err(|err| anyhow!("Cargo.toml skeleton is not a valid TOML: {err}"))?;
change_package_name(context, &mut doc);
if context.target.is_p3() {
set_p3_default_features(&mut doc);
}
let output_path = context.output.join("Cargo.toml");
crate::write_if_changed(output_path, doc.to_string())?;
Ok(())
}
fn change_package_name(context: &GeneratorContext, doc: &mut DocumentMut) {
let crate_name = &context.world_name;
doc["package"]["name"] = value(crate_name);
}
fn set_p3_default_features(doc: &mut DocumentMut) {
let mut default = Array::new();
default.push("p3");
default.push("normal-p3");
doc["features"]["default"] = value(default);
}
const GENERATED_FILES: &[&str] = &["src/lib.rs"];
pub fn copy_skeleton_lock(output: &Utf8Path) -> anyhow::Result<()> {
if let Some(lock_file) = SKELETON.get_file("Cargo.lock") {
let dest = output.join("Cargo.lock");
crate::write_if_changed(dest, lock_file.contents())?;
}
Ok(())
}
pub fn copy_skeleton_sources(output: &Utf8Path) -> anyhow::Result<()> {
if let Some(src) = SKELETON.get_dir("src") {
for file in src.files() {
let src_path = Utf8Path::from_path(file.path())
.ok_or_else(|| anyhow!("Unexpected non-UTF-8 path in skeleton"))?;
if GENERATED_FILES.contains(&src_path.as_str()) {
continue;
}
let dest_path = output.join(src_path);
crate::write_if_changed(dest_path, file.contents())?;
}
for dir in src.dirs() {
recursive_copy_sources(dir, output)?;
}
}
Ok(())
}
fn recursive_copy_sources(dir: &Dir, output: &Utf8Path) -> anyhow::Result<()> {
let dir_path = Utf8Path::from_path(dir.path())
.ok_or_else(|| anyhow!("Unexpected non-UTF-8 path in skeleton"))?;
std::fs::create_dir_all(output.join(dir_path))?;
let has_mod_rs = dir
.files()
.any(|f| f.path().file_name().and_then(|n| n.to_str()) == Some("mod.rs"));
if has_mod_rs {
let stale = output.join(format!("{dir_path}.rs"));
if stale.exists() {
std::fs::remove_file(&stale)
.map_err(|e| anyhow!("Failed to remove stale module file {stale}: {e}"))?;
}
}
for file in dir.files() {
let src_path = Utf8Path::from_path(file.path())
.ok_or_else(|| anyhow!("Unexpected non-UTF-8 path in skeleton"))?;
let dest_path = output.join(src_path);
crate::write_if_changed(dest_path, file.contents())?;
}
for dir in dir.dirs() {
recursive_copy_sources(dir, output)?;
}
Ok(())
}