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
122
123
124
125
126
use dev_prefix::*;
use core::types::*;
lazy_static!{
pub static ref ART_LOC: Regex = Regex::new(
&format!(r"(?i)(?:#({}))|(\n)", ART_VALID_STR)).unwrap();
}
pub fn find_locs_text(path: &Path, text: &str, locs: &mut HashMap<ArtName, Loc>) -> Result<()> {
let mut line = 1;
for cap in ART_LOC.captures_iter(text) {
if let Some(m) = cap.get(1) {
debug_assert!(cap.get(2).is_none());
let name = ArtName::from_str(m.as_str()).expect("regex validated");
let loc = Loc {
path: path.to_path_buf(),
line: line,
};
if let Some(first) = locs.insert(name, loc) {
warn!("locations found twice. first: {}({}), \
second: {}({})",
first.path.display(),
first.line,
path.display(),
line);
}
} else {
debug_assert!(cap.get(2).is_some());
line += 1;
}
}
Ok(())
}
pub fn find_locs_file(path: &Path, locs: &mut HashMap<ArtName, Loc>) -> Result<()> {
debug!("resolving locs at: {:?}", path);
let mut text = String::new();
let mut f = fs::File::open(path).chain_err(|| format!("opening file: {}", path.display()))?;
if let Err(e) = f.read_to_string(&mut text) {
if e.kind() == io::ErrorKind::InvalidData {
warn!("non-utf8 file: {}", path.display());
return Ok(());
} else {
Err(e).chain_err(|| format!("reading file: {}", path.display()))?;
}
}
find_locs_text(path, &text, locs)
}
fn find_locs_dir(path: &PathBuf,
loaded_dirs: &mut HashSet<PathBuf>,
locs: &mut HashMap<ArtName, Loc>)
-> Result<()> {
loaded_dirs.insert(path.to_path_buf());
let read_dir = fs::read_dir(path).chain_err(|| format!("loading dir {}", path.display()))?;
let mut dirs_to_load: Vec<PathBuf> = Vec::new();
for entry in read_dir.filter_map(|e| e.ok()) {
let fpath = entry.path();
match fpath.extension() {
None => {}
Some(ext) => {
if ext == "toml" {
continue;
}
}
}
let ftype = entry.file_type().chain_err(|| format!("{}", fpath.display()))?;
if ftype.is_dir() {
dirs_to_load.push(fpath.clone());
} else if ftype.is_file() {
find_locs_file(&fpath, locs)?
}
}
for d in dirs_to_load {
if !loaded_dirs.contains(&d) {
find_locs_dir(&d, loaded_dirs, locs)?;
}
}
Ok(())
}
pub fn find_locs(settings: &Settings) -> Result<HashMap<ArtName, Loc>> {
info!("parsing code files for artifacts...");
let mut locs: HashMap<ArtName, Loc> = HashMap::new();
let mut loaded_dirs: HashSet<PathBuf> =
HashSet::from_iter(settings.exclude_code_paths.iter().map(|p| p.to_path_buf()));
debug!("excluded code paths: {:?}", loaded_dirs);
for dir in &settings.code_paths {
if loaded_dirs.contains(dir) {
continue;
}
debug!("Loading from code: {:?}", dir);
find_locs_dir(dir, &mut loaded_dirs, &mut locs)?;
}
Ok(locs)
}
pub fn attach_locs(artifacts: &mut Artifacts,
mut locs: HashMap<ArtName, Loc>)
-> Result<HashMap<ArtName, Loc>> {
let mut dne: HashMap<ArtName, Loc> = HashMap::new();
for (lname, loc) in locs.drain() {
let artifact = match artifacts.get_mut(&lname) {
Some(a) => a,
None => {
dne.insert(lname, loc);
continue;
}
};
if let Done::Defined(_) = artifact.done {
return Err(ErrorKind::DoneTwice(lname.to_string()).into());
}
artifact.done = Done::Code(loc);
}
Ok(dne)
}