use std::env;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
fn main() {
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
let archive_path = Path::new(&out_dir).join("apidoc.tar.gz");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=apidoc");
println!("cargo:rerun-if-changed=apidoc.tar.gz");
println!("cargo:rerun-if-env-changed=LIBPERL_APIDOC_URL");
if let Ok(url) = env::var("LIBPERL_APIDOC_URL") {
let _ = std::fs::remove_file(&archive_path);
println!("cargo:warning=Downloading apidoc from {}", url);
if let Err(e) = download_file(&url, &archive_path) {
panic!("LIBPERL_APIDOC_URL download failed: {}", e);
}
return;
}
let local_apidoc = Path::new("apidoc");
if local_apidoc.is_dir() {
let _ = std::fs::remove_file(&archive_path);
if let Err(e) = create_local_archive(local_apidoc, &archive_path) {
panic!("Failed to create local apidoc archive: {}", e);
}
return;
}
let bundled = Path::new("apidoc.tar.gz");
if bundled.exists() {
std::fs::copy(bundled, &archive_path)
.expect("copy bundled apidoc.tar.gz to OUT_DIR");
return;
}
println!(
"cargo:warning=No apidoc source found (no apidoc/ dir, no \
apidoc.tar.gz, no LIBPERL_APIDOC_URL). Macrogen will produce \
zero macro wrappers; this is probably not what you want."
);
let _ = std::fs::remove_file(&archive_path);
write_empty_archive(&archive_path)
.expect("write empty apidoc placeholder");
}
fn create_local_archive(_src_dir: &Path, dest: &Path) -> io::Result<()> {
use std::process::Command;
let output = Command::new("tar")
.args(["-czf", dest.to_str().unwrap(), "-C", ".", "apidoc"])
.output()?;
if !output.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!(
"tar command failed: {}",
String::from_utf8_lossy(&output.stderr)
),
));
}
Ok(())
}
fn write_empty_archive(dest: &Path) -> io::Result<()> {
let bytes: [u8; 20] = [
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let mut file = File::create(dest)?;
file.write_all(&bytes)?;
Ok(())
}
fn download_file(url: &str, dest: &Path) -> io::Result<()> {
let response = ureq::get(url)
.call()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
if response.status() != 200 {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("HTTP error: {}", response.status()),
));
}
let mut bytes = Vec::new();
response
.into_reader()
.read_to_end(&mut bytes)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
let mut file = File::create(dest)?;
file.write_all(&bytes)?;
Ok(())
}