orml_build_script_utils/
license.rs

1use std::{fs::File, io::Read, path::Path};
2use walkdir::{DirEntry, WalkDir};
3
4// Check the license text that should be present at the beginning of every
5// source file.
6pub fn check_file_licenses<P: AsRef<Path>>(path: P, expected_license_text: &[u8], exclude_paths: &[&str]) {
7	// The following directories will be excluded from the license scan.
8	let skips = ["artifacts", "corpus", "target", "fuzz_targets"];
9
10	let path = path.as_ref();
11
12	let mut iter = WalkDir::new(path).into_iter();
13	while let Some(entry) = iter.next() {
14		let entry = entry.unwrap();
15		let entry_type = entry.file_type();
16
17		// Skip the hidden entries efficiently.
18		if is_hidden(&entry) {
19			if entry.file_type().is_dir() {
20				iter.skip_current_dir();
21			}
22			continue;
23		}
24
25		// Skip the specified directories and paths.
26		if entry_type.is_dir()
27			&& (skips.contains(&entry.file_name().to_str().unwrap_or(""))
28				|| exclude_paths.contains(&entry.path().to_str().unwrap_or("")))
29		{
30			iter.skip_current_dir();
31
32			continue;
33		}
34
35		// Check all files with the ".rs" extension.
36		if entry_type.is_file() && entry.file_name().to_str().unwrap_or("").ends_with(".rs") {
37			let file = File::open(entry.path()).unwrap();
38			let mut contents = Vec::with_capacity(expected_license_text.len());
39			file.take(expected_license_text.len() as u64)
40				.read_to_end(&mut contents)
41				.unwrap();
42
43			assert!(
44				contents == expected_license_text,
45				"The license in \"{}\" is either missing or it doesn't match the expected string!",
46				entry.path().display()
47			);
48		}
49	}
50
51	// Re-run upon any changes to the workspace.
52	println!("cargo:rerun-if-changed=.");
53}
54
55// hidden files and directories efficiently.
56fn is_hidden(entry: &DirEntry) -> bool {
57	entry
58		.file_name()
59		.to_str()
60		.map(|s| s.starts_with('.') && !s.starts_with(".."))
61		.unwrap_or(false)
62}