use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let repo_root = manifest_dir.parent().unwrap_or(&manifest_dir);
sync_bpf(&manifest_dir, repo_root);
sync_frontend(&manifest_dir, repo_root);
println!("cargo:rerun-if-changed=build.rs");
}
fn sync_bpf(manifest_dir: &Path, repo_root: &Path) {
let source_dir = repo_root.join("bpf");
let vendor_dir = manifest_dir.join("vendor/bpf");
for name in ["process", "sslsniff", "stdiocap"] {
let source = source_dir.join(name);
let vendor = vendor_dir.join(name);
if source.exists() {
println!("cargo:rerun-if-changed={}", source.display());
copy_file(&source, &vendor).unwrap_or_else(|err| {
panic!(
"failed to vendor {} into {}: {err}",
source.display(),
vendor.display()
)
});
} else if !vendor.exists() {
panic!(
"missing bundled BPF loader {}. Run `make -C ../bpf` before packaging.",
vendor.display()
);
}
println!("cargo:rerun-if-changed={}", vendor.display());
}
}
fn sync_frontend(manifest_dir: &Path, repo_root: &Path) {
let source_dir = repo_root.join("frontend/dist");
let vendor_dir = manifest_dir.join("vendor/frontend/dist");
if source_dir.join("index.html").exists() {
println!("cargo:rerun-if-changed={}", source_dir.display());
if vendor_dir.exists() {
fs::remove_dir_all(&vendor_dir)
.unwrap_or_else(|err| panic!("failed to clear {}: {err}", vendor_dir.display()));
}
copy_dir(&source_dir, &vendor_dir).unwrap_or_else(|err| {
panic!(
"failed to vendor frontend {} into {}: {err}",
source_dir.display(),
vendor_dir.display()
)
});
} else if !vendor_dir.join("index.html").exists() {
panic!(
"missing bundled frontend {}. Run `npm run build` in ../frontend before packaging.",
vendor_dir.display()
);
}
}
fn copy_file(source: &Path, destination: &Path) -> io::Result<()> {
if let Some(parent) = destination.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(source, destination)?;
Ok(())
}
fn copy_dir(source: &Path, destination: &Path) -> io::Result<()> {
fs::create_dir_all(destination)?;
for entry in fs::read_dir(source)? {
let entry = entry?;
let source_path = entry.path();
let destination_path = destination.join(entry.file_name());
if source_path.is_dir() {
copy_dir(&source_path, &destination_path)?;
} else if source_path
.file_name()
.is_some_and(|name| name == "sample-trace.log")
{
continue;
} else {
copy_file(&source_path, &destination_path)?;
}
}
Ok(())
}