use std::{
env,
fs::{self, File},
io::{BufRead, BufReader},
path::{Path, PathBuf},
};
use walkdir::WalkDir;
const DIRS_TO_SKIP: [&str; 9] =
[".cargo", ".circleci", ".git", ".github", ".resources", "docs", "examples", "target", "tests"];
fn compare_license_text(path: &Path, expected_lines: &[&str]) {
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
for (i, (file_line, expected_line)) in reader.lines().zip(expected_lines).enumerate() {
let file_line =
file_line.unwrap_or_else(|_| panic!("Can't read line {} in file \"{}\"!", i + 1, path.display()));
assert_eq!(
&file_line,
expected_line,
"Line {} in file \"{}\" was expected to contain the license text \"{}\", but contains \"{}\" instead! \
Consult the expected license text in \".resources/license_header\"",
i + 1,
path.display(),
expected_line,
file_line
);
}
}
fn check_file_licenses<P: AsRef<Path>>(path: P) {
let expected_license_text = match std::fs::read_to_string("../../.resources/license_header") {
Ok(s) => s,
Err(_) => return, };
let path = path.as_ref();
let license_lines: Vec<_> = expected_license_text.lines().collect();
let mut iter = WalkDir::new(path).into_iter();
while let Some(entry) = iter.next() {
let entry = entry.unwrap();
let entry_type = entry.file_type();
if entry_type.is_dir() && DIRS_TO_SKIP.contains(&entry.file_name().to_str().unwrap_or("")) {
iter.skip_current_dir();
continue;
}
if entry_type.is_file() && entry.file_name().to_str().unwrap_or("").ends_with(".rs") {
compare_license_text(entry.path(), &license_lines);
}
}
println!("cargo:rerun-if-changed=../../crates");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=../../.resources/license_header");
println!("cargo:rerun-if-changed=Cargo.toml");
println!("cargo:rerun-if-changed=../../Cargo.lock");
}
fn generate_cli_tests() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let workspace_root = manifest_dir.join("../..");
let tests_dir = workspace_root.join("tests/tests/cli");
if !tests_dir.exists() {
return;
}
println!("cargo:rerun-if-changed={}", tests_dir.display());
let mut out = String::from("use serial_test::serial;\n");
let entries = match fs::read_dir(&tests_dir) {
Ok(e) => e,
Err(_) => return,
};
for entry in entries {
let Ok(entry) = entry else { continue };
let path = entry.path();
if !path.is_dir() {
continue;
}
let name = path.file_name().unwrap().to_string_lossy();
let fn_name = format!("cli_{}", name.replace('-', "_"));
out.push_str(&format!(
r#"
#[test]
#[serial]
fn {fn_name}() {{
crate::run_single_cli_test(
std::path::Path::new(r"{path}")
);
}}
"#,
fn_name = fn_name,
path = path.display(),
));
}
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let _ = fs::write(out_dir.join("cli_tests.rs"), out);
}
fn set_version_env_vars() {
println!("cargo:rerun-if-changed=../../.git/HEAD");
let git_cmd = |args: &[&str]| -> String {
std::process::Command::new("git")
.args(args)
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
.unwrap_or_else(|| "unknown".to_string())
};
let hash = git_cmd(&["rev-parse", "--short", "HEAD"]);
let branch = git_cmd(&["rev-parse", "--abbrev-ref", "HEAD"]);
let mut features: Vec<String> = env::vars()
.filter_map(|(k, _)| k.strip_prefix("CARGO_FEATURE_").map(|f| f.to_lowercase()))
.filter(|f| f != "default")
.collect();
features.sort();
let version = env::var("CARGO_PKG_VERSION").unwrap();
let features_str = features.join(",");
println!("cargo:rustc-env=LEO_VERSION_STRING={version} ({hash} {branch}) features=[{features_str}]");
}
fn main() {
generate_cli_tests();
set_version_env_vars();
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let workspace_root = manifest_dir.join("../..");
check_file_licenses(&workspace_root);
}