Reorganize path traversal
MODIFY
Cargo.toml
Cargo.toml
@@ -64,7 +64,6 @@ binding-generator = { package = "opencv-binding-generator", version = "0.47.1",
cc = { version = "1", features = ["parallel"] }
clang = { version = "2", features = ["clang_6_0", "runtime"] }
dunce = "1"
-glob = "0.3"
jobserver = "0.1"
once_cell = "1"
pkg-config = "0.3"

MODIFY
build.rs
build.rs
@@ -9,7 +9,6 @@ use std::{
process::{Child, Command, Stdio},
};
-use glob::glob;
use once_cell::sync::{Lazy, OnceCell};
use semver::{Version, VersionReq};
@@ -53,6 +52,12 @@ static ENV_VARS: [&str; 14] = [
"VCPKGRS_DYNAMIC",
];
+fn files_with_extension<'e>(dir: &Path, extension: impl AsRef<OsStr> + 'e) -> Result<impl Iterator<Item=PathBuf> + 'e> {
+ Ok(dir.read_dir()?.flatten()
+ .map(|e| e.path())
+ .filter(move |p| p.is_file() && p.extension().map_or(false, |e| e.eq_ignore_ascii_case(extension.as_ref()))))
+}
+
fn cleanup_lib_filename(filename: &OsStr) -> Option<&OsStr> {
let mut strip_performed = false;
let mut filename_path = Path::new(filename);
@@ -160,9 +165,7 @@ fn make_modules(opencv_dir: &Path) -> Result<()> {
)
).collect::<HashSet<_>>();
- let modules = glob(&format!("{}/*.hpp", opencv_dir.to_str().ok_or("Can't OpenCV header directory to UTF-8 string")?))?
- .filter_map(|entry| {
- let entry = entry.expect("Can't get path for module file");
+ let mut modules = files_with_extension(opencv_dir, "hpp")?.filter_map(|entry| {
let module = entry.file_stem()
.and_then(OsStr::to_str).expect("Can't calculate file stem");
Some(module)
@@ -170,7 +173,8 @@ fn make_modules(opencv_dir: &Path) -> Result<()> {
.filter(|&m| enable_modules.contains(m))
.map(str::to_string)
})
- .collect();
+ .collect::<Vec<_>>();
+ modules.sort_unstable();
MODULES.set(modules).expect("Can't set MODULES cache");
Ok(())

MODIFY
build/generator.rs
build/generator.rs
use std::{
ffi::OsStr,
- fs::{self, DirEntry, File, OpenOptions},
+ fs::{self, File, OpenOptions},
io::{self, BufRead, BufReader, Write},
path::{Path, PathBuf},
process::{Child, Command},
@@ -9,9 +9,8 @@ use std::{
time::Instant,
};
-use glob::glob;
-
use super::{
+ files_with_extension,
HOST_TRIPLE,
Library,
MODULES,
@@ -21,8 +20,15 @@ use super::{
SRC_DIR,
};
-fn read_dir(path: &Path) -> Result<impl Iterator<Item=DirEntry>> {
- Ok(path.read_dir()?.filter_map(|e| e.ok()))
+fn is_type_file(path: &Path, module: &str) -> bool {
+ path.file_stem().and_then(OsStr::to_str).map_or(false, |stem| {
+ let mut stem_chars = stem.chars();
+ (&mut stem_chars).take(3).all(|c| c.is_ascii_digit()) && // first 3 chars are digits
+ matches!(stem_chars.next(), Some('-')) && // dash
+ module.chars().zip(&mut stem_chars).all(|(m, s)| m == s) && // module name
+ matches!(stem_chars.next(), Some('-')) && // dash
+ stem.ends_with(".type") // ends with ".type"
+ })
}
fn copy_indent(mut read: impl BufRead, mut write: impl Write, indent: &str) -> Result<()> {
@@ -51,18 +57,17 @@ fn file_move_to_dir(src_file: &Path, target_dir: &Path) -> Result<PathBuf> {
}
pub fn gen_wrapper(opencv_header_dir: &Path, opencv: &Library, job_server: jobserver::Client, generator_build: Child) -> Result<()> {
- let out_dir_as_str = OUT_DIR.to_str().unwrap();
let target_hub_dir = SRC_DIR.join("opencv");
let target_module_dir = target_hub_dir.join("hub");
let manual_dir = SRC_DIR.join("manual");
- eprintln!("=== Generating code in: {}", out_dir_as_str);
+ eprintln!("=== Generating code in: {}", OUT_DIR.display());
eprintln!("=== Placing generated bindings into: {}", target_hub_dir.display());
eprintln!("=== Using OpenCV headers from: {}", opencv_header_dir.display());
- for entry in read_dir(&OUT_DIR)? {
+ for entry in OUT_DIR.read_dir()?.flatten() {
let path = entry.path();
- if path.is_file() && path.extension().and_then(OsStr::to_str).map_or(true, |ext| !ext.eq_ignore_ascii_case("dll")) {
+ if path.is_file() && path.extension().map_or(true, |ext| !ext.eq_ignore_ascii_case("dll")) {
let _ = fs::remove_file(path);
}
}
@@ -128,12 +133,9 @@ pub fn gen_wrapper(opencv_header_dir: &Path, opencv: &Library, job_server: jobse
}
eprintln!("=== Total binding generation time: {:?}", start.elapsed());
- for entry in read_dir(&target_module_dir)? {
- let path = entry.path();
- if path.extension().map_or(false, |e| e == "rs") {
+ for path in files_with_extension(&target_module_dir, "rs")? {
let _ = fs::remove_file(path);
}
- }
fn write_has_module(write: &mut File, module: &str) -> Result<()> {
Ok(writeln!(write, "#[cfg(ocvrs_has_module_{})]", module)?)
@@ -163,10 +165,9 @@ pub fn gen_wrapper(opencv_header_dir: &Path, opencv: &Library, job_server: jobse
if module_cpp.is_file() {
let module_types_cpp = OUT_DIR.join(format!("{}_types.hpp", module));
let mut module_types_file = OpenOptions::new().create(true).truncate(true).write(true).open(&module_types_cpp)?;
- let mut type_files: Vec<PathBuf> = glob(&format!("{}/???-{}-*.type.cpp", out_dir_as_str, module))?
- .collect::<Result<_, glob::GlobError>>()?;
- type_files.sort_unstable();
- for entry in type_files.into_iter() {
+ let type_files = files_with_extension(&OUT_DIR, "cpp")?
+ .filter(|f| is_type_file(f, module));
+ for entry in type_files {
io::copy(&mut File::open(&entry)?, &mut module_types_file)?;
let _ = fs::remove_file(entry);
}
@@ -182,8 +183,11 @@ pub fn gen_wrapper(opencv_header_dir: &Path, opencv: &Library, job_server: jobse
// merge multiple *-.type.rs files into a single types.rs
let mut header_written = false;
- for entry in glob(&format!("{}/???-{}-*.type.rs", out_dir_as_str, module))? {
- let entry = entry?;
+ let mut type_files = files_with_extension(&OUT_DIR, "rs")?
+ .filter(|f| is_type_file(f, module))
+ .collect::<Vec<_>>();
+ type_files.sort_unstable();
+ for entry in type_files {
if entry.metadata().map(|meta| meta.len()).unwrap_or(0) > 0 {
if !header_written {
write_has_module(&mut types_rs, module)?;

MODIFY
build/library.rs
build/library.rs
@@ -9,7 +9,6 @@ use std::{
};
use dunce::canonicalize;
-use glob::glob;
use semver::Version;
use super::{
@@ -184,6 +183,22 @@ impl Library {
.map(move |l| Self::emit_link_lib(&l, typ))
}
+ fn find_vcpkg_tool(vcpkg_root: &Path, tool_name: &str) -> Option<PathBuf> {
+ let tool_dirs = vcpkg_root.join("downloads/tools").read_dir().into_iter().flatten().flatten()
+ .map(|e| e.path())
+ .filter(|p| p.is_dir() && p.file_name().and_then(OsStr::to_str).map_or(false, |n| n.starts_with(tool_name)));
+
+ tool_dirs
+ .flat_map(|d| d.read_dir().into_iter().flatten().flatten()) // all subdirs inside tool dirs
+ .map(|e| e.path())
+ .filter(|p| p.is_dir())
+ .flat_map(|p| p.read_dir().into_iter().flatten().flatten()) // all subdirs inside those dirs
+ .map(|e| e.path())
+ .flat_map(|p| [p.join(format!("bin/{}", tool_name)), p.join(format!("bin/{}.exe", tool_name))])
+ .filter_map(|p| canonicalize(p).ok())
+ .find(|p| p.is_file())
+ }
+
pub fn probe_from_paths(include_paths: Option<EnvList>, link_paths: Option<EnvList>, link_libs: Option<EnvList>) -> Result<Self> {
if let (Some(include_paths), Some(link_paths), Some(link_libs)) = (include_paths, link_paths, link_libs) {
if include_paths.is_extend() || link_paths.is_extend() || link_libs.is_extend() {
@@ -353,28 +368,8 @@ impl Library {
let vcpkg_root = canonicalize(vcpkg::find_vcpkg_root(&config)?)?;
eprintln!("=== Discovered vcpkg root: {}", vcpkg_root.display());
- let vcpkg_cmake = vcpkg_root.to_str()
- .and_then(|vcpkg_root| {
- glob(&format!("{}/downloads/tools/cmake*/*/bin/cmake", vcpkg_root)).ok()
- .and_then(|cmake_iter| glob(&format!("{}/downloads/tools/cmake*/*/bin/cmake.exe", vcpkg_root)).ok()
- .map(|cmake_exe_iter| cmake_iter.chain(cmake_exe_iter))
- )
- })
- .and_then(|paths| paths.filter_map(|r| r.ok())
- .filter_map(|p| canonicalize(p).ok())
- .find(|p| p.is_file())
- );
- let vcpkg_ninja = vcpkg_root.to_str()
- .and_then(|vcpkg_root| {
- glob(&format!("{}/downloads/tools/ninja*/ninja", vcpkg_root)).ok()
- .and_then(|ninja_iter| glob(&format!("{}/downloads/tools/ninja*/*/ninja.exe", vcpkg_root)).ok()
- .map(|ninja_exe_iter| ninja_iter.chain(ninja_exe_iter))
- )
- })
- .and_then(|paths| paths.filter_map(|r| r.ok())
- .filter_map(|p| canonicalize(p).ok())
- .find(|p| p.is_file())
- );
+ let vcpkg_cmake = Self::find_vcpkg_tool(&vcpkg_root, "cmake");
+ let vcpkg_ninja = Self::find_vcpkg_tool(&vcpkg_root, "ninja");
let toolchain = vcpkg_root.join("scripts/buildsystems/vcpkg.cmake");
Self::probe_cmake(include_paths, link_paths, link_libs, Some(&toolchain), vcpkg_cmake.as_deref(), vcpkg_ninja.as_deref())
}

Reorganize path traversal