locate_header/
lib.rs

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}