use std::env;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
const APIDOC_DATA_VERSION: &str = "1.0";
const GITHUB_OWNER: &str = "hkoba";
const GITHUB_REPO: &str = "libperl-macrogen";
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-env-changed=DOCS_RS");
println!("cargo:rerun-if-env-changed=LIBPERL_APIDOC_URL");
if env::var("DOCS_RS").is_ok() {
let _ = std::fs::remove_file(&archive_path);
write_empty_archive(&archive_path)
.expect("write empty apidoc placeholder for docs.rs");
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;
}
if archive_path.exists() {
return;
}
let url = get_download_url();
println!("cargo:warning=Downloading apidoc from {}", url);
if let Err(e) = download_file(&url, &archive_path) {
panic!("Failed to download apidoc archive: {}", e);
}
}
fn get_download_url() -> String {
if let Ok(url) = env::var("LIBPERL_APIDOC_URL") {
return url;
}
format!(
"https://github.com/{}/{}/releases/download/apidoc-v{}/apidoc.tar.gz",
GITHUB_OWNER, GITHUB_REPO, APIDOC_DATA_VERSION
)
}
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(())
}