1use log::*;
2use std::ffi::OsString;
3use std::path::PathBuf;
4
5fn find_it_in(to_find: &str, path: PathBuf) -> Option<PathBuf> {
6 debug!("Searching {:?} for {}", path, to_find);
7 if path.is_dir() {
8 match path.read_dir() {
9 Ok(read_dir) => {
10 let mut i = read_dir.into_iter();
11 while let Some(Ok(entry)) = i.next() {
12 if let Some(f) = find_it_in(to_find, entry.path()) {
13 return Some(f);
14 }
15 }
16 }
17 Err(e) => {
18 warn!("Could not search for {} in {:?}: {:?}", to_find, path, e);
19 }
20 }
21 } else if path.is_file() {
22 if let Some(os_str) = path.file_name() {
23 if os_str == to_find {
24 return Some(path);
25 }
26 }
27 }
28 None
29}
30
31fn find_it(path: OsString, to_find: &str) -> Option<PathBuf> {
32 std::env::split_paths(&path)
33 .filter_map(|dir| find_it_in(to_find, dir))
34 .next()
35}
36
37fn locate_header_from_package(
38 path: OsString,
39 header_name: &str,
40 package: Package,
41) -> Option<PathBuf> {
42 debug!(
43 "Checking package {} @ {} for {}",
44 package.name, package.version, header_name
45 );
46 if let Ok(library) = pkg_config::Config::new()
47 .atleast_version(&package.version)
48 .probe(&package.name)
49 {
50 for include_path in library.include_paths {
51 if let Some(f) = find_it_in(header_name, include_path) {
52 return Some(f);
53 }
54 }
55 }
56 debug!("Could not find package, checking path");
57 if let Some(f) = find_it(path, header_name) {
58 return Some(f);
59 }
60 None
61}
62
63pub struct Package {
64 pub version: String,
65 pub name: String,
66}
67
68pub fn locate_header(header_name: &str, package: Option<Package>) -> Option<PathBuf> {
69 let path = std::env::var_os("PATH").expect("No path defined");
70 debug!("Locating header using path {:?}", path);
71 locate_header_with_path(path, header_name, package)
72}
73
74pub fn locate_header_with_path(
75 path: OsString,
76 header_name: &str,
77 package: Option<Package>,
78) -> Option<PathBuf> {
79 if let Some(p) = package {
80 return locate_header_from_package(path, header_name, p);
81 } else {
82 return find_it(path, header_name);
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn locate_resource_header() {
92 let _ = env_logger::try_init();
93
94 let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
95 assert!(locate_header_with_path(cargo_dir.into_os_string(), "to_find.h", None).is_some());
96 }
97}