1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::collections::HashMap;
use std::env::var_os;
use std::fs::metadata;
use std::path::PathBuf;
use walkdir::{DirEntry, Result as WalkResult, WalkDir};
#[cfg(unix)]
const ROOT_PATH_DEFAULT: &str = "/usr/lib/oftlisp";
#[cfg(windows)]
const ROOT_PATH_DEFAULT: &str = r"C:\oftlisp";
#[cfg(not(any(unix, windows)))]
compile_error!("TODO: Choose an oftlisp::paths::ROOT_PATH_DEFAULT for this platform");
pub fn find_module<S: AsRef<str>>(import_path: S) -> Option<PathBuf> {
let import_path = import_path.as_ref().split('/').collect::<Vec<_>>();
let find_module_in = |mut path: PathBuf| -> Option<PathBuf> {
path.push("src");
for component in &import_path {
path.push(component);
}
if path.extension().is_none() {
path.set_extension("oft");
}
metadata(&path).ok().and_then(|m| if m.is_file() {
Some(path)
} else {
None
})
};
match user_path() {
Some(path) => {
match find_module_in(path) {
Some(m) => Some(m),
None => find_module_in(root_path()),
}
}
None => find_module_in(root_path()),
}
}
pub fn find_modules() -> WalkResult<HashMap<String, ModuleMeta>> {
fn is_oftlisp_source(entry: &DirEntry) -> bool {
entry.path().extension().map(|e| e == "oft").unwrap_or(
false,
)
}
fn search(
out: &mut HashMap<String, ModuleMeta>,
mut path: PathBuf,
is_root: bool,
) -> WalkResult<()> {
path.push("src");
let iter = WalkDir::new(&path).follow_links(true).into_iter().filter(
|r| {
r.as_ref().map(is_oftlisp_source).unwrap_or(false)
},
);
for r in iter {
let entry = r?;
let import_path = entry
.path()
.strip_prefix(&path)
.unwrap()
.with_extension("")
.display()
.to_string();
let metadata = ModuleMeta {
is_root,
path: entry.path().to_owned(),
};
out.entry(import_path).or_insert(metadata);
}
Ok(())
}
let mut paths = HashMap::new();
if let Some(user_path) = user_path() {
search(&mut paths, user_path, false)?;
}
search(&mut paths, root_path(), true)?;
Ok(paths)
}
pub fn root_path() -> PathBuf {
if let Some(var) = var_os("OFTLISP_ROOT") {
var.into()
} else {
option_env!("OFTLISP_ROOT")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from(ROOT_PATH_DEFAULT))
}
}
pub fn user_path() -> Option<PathBuf> {
var_os("OFTLISP_HOME").map(PathBuf::from)
}
pub struct ModuleMeta {
pub is_root: bool,
pub path: PathBuf,
}