use std::path::Path;
pub(crate) fn copy_project_src_tree_into_output(output_dir: &Path) -> std::io::Result<()> {
use std::fs;
let Some(root) = output_dir.parent() else {
return Ok(());
};
let root = if root.as_os_str().is_empty() {
Path::new(".")
} else {
root
};
let src_dir = root.join("src");
if !src_dir.is_dir() {
return Ok(());
}
for entry in fs::read_dir(&src_dir)? {
let entry = entry?;
let p = entry.path();
let name = entry.file_name();
let dest = output_dir.join(&name);
if p.is_file() {
if p.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
if let Some(stem) = p.file_stem().and_then(|s| s.to_str()) {
if src_dir.join(stem).is_dir() {
continue;
}
}
if !dest.exists() {
fs::copy(&p, &dest)?;
}
} else if p.is_dir() && p.join("mod.rs").exists() {
copy_dir_merge_shallow(&p, &dest)?;
}
}
Ok(())
}
pub(crate) fn copy_dir_merge_shallow(src: &Path, dst: &Path) -> std::io::Result<()> {
use std::fs;
if !dst.exists() {
fs::create_dir_all(dst)?;
}
for entry in fs::read_dir(src)? {
let entry = entry?;
let from = entry.path();
let to = dst.join(entry.file_name());
if from.is_dir() {
copy_dir_merge_shallow(&from, &to)?;
} else if !to.exists() {
if let Some(parent) = to.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(&from, &to)?;
}
}
Ok(())
}
pub(crate) fn copy_sibling_rs_from_parent(output_dir: &Path) -> std::io::Result<()> {
use std::fs;
let Some(parent) = output_dir.parent() else {
return Ok(());
};
let parent = if parent.as_os_str().is_empty() {
Path::new(".")
} else {
parent
};
for entry in fs::read_dir(parent)? {
let entry = entry?;
let p = entry.path();
if !p.is_file() {
continue;
}
if p.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let stem = p.file_stem().and_then(|s| s.to_str()).unwrap_or("");
if matches!(stem, "build" | "main" | "lib") {
continue;
}
if stem.ends_with("_test")
|| stem.ends_with("_tests")
|| stem.starts_with("test_")
|| stem == "tests"
{
continue;
}
let dest = output_dir.join(p.file_name().unwrap());
if !dest.exists() {
fs::copy(&p, &dest)?;
}
}
Ok(())
}
pub fn strip_main_functions(output_dir: &Path) -> anyhow::Result<()> {
use colored::*;
use std::fs;
let mut stripped_count = 0;
for entry in fs::read_dir(output_dir)? {
let entry = entry?;
let path = entry.path();
if path.is_file() {
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
if file_name.ends_with(".rs") && file_name != "mod.rs" {
let content = fs::read_to_string(&path)?;
let mut new_lines = Vec::new();
let mut found_main = false;
for line in content.lines() {
let trimmed = line.trim();
if trimmed.starts_with("fn main()") || trimmed.starts_with("pub fn main()")
{
found_main = true;
stripped_count += 1;
break;
}
new_lines.push(line);
}
if found_main {
let new_content = new_lines.join("\n") + "\n";
fs::write(&path, new_content)?;
}
}
}
}
}
if stripped_count > 0 {
println!(
"{} Stripped {} main() functions (library mode)",
"✓".green(),
stripped_count
);
}
Ok(())
}