use std::io;
use super::types::*;
lazy_static!{
pub static ref SPC: VecDeque<char> = VecDeque::from_iter(vec!['#', 'S', 'P', 'C', '-']);
pub static ref TST: VecDeque<char> = VecDeque::from_iter(vec!['#', 'T', 'S', 'T', '-']);
}
pub fn find_locs_text(path: &Path,
text: &str,
locs: &mut HashMap<ArtName, Loc>)
-> bool {
let mut error = false;
let text = text;
let mut prev: VecDeque<char> = VecDeque::with_capacity(5);
let mut prev_char = ' ';
let mut start_pos = 0;
let mut start_col = 0;
let (mut pos, mut line, mut col) = (0, 1, 0); for c in text.chars() {
if prev == *SPC || prev == *TST { if prev_char == ' ' {
start_pos = pos - 5;
start_col = col - 5;
}
match c {
'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => {
prev_char = c; }
_ => { if prev_char != ' ' { let art_start = start_pos + 1; let (_, end) = text.split_at(art_start);
let (name, _) = match prev_char {
'-' => end.split_at(pos - art_start - 1),
_ => end.split_at(pos - art_start),
};
let locname = ArtName::from_str(name).unwrap();
debug!("Found loc: {}", locname);
let loc = Loc {
path: path.to_path_buf(),
line_col: (line, start_col)
};
match locs.insert(locname, loc) {
None => {},
Some(l) => {
error!("detected overlapping loc {} in files: {:?} and {}",
name, l, path.display());
error = true;
}
}
prev_char = ' ';
}
prev.pop_front();
prev.push_back(c);
},
}
} else {
if prev.len() == 5 {
prev.pop_front();
}
prev.push_back(c);
}
match c {
'\n' => {
line += 1;
col = 0;
}
_ => col += 1,
};
pos += 1;
}
error
}
pub fn find_locs_file(path: &Path,
locs: &mut HashMap<ArtName, Loc>)
-> bool {
debug!("resolving locs at: {:?}", path);
let mut text = String::new();
match fs::File::open(path) {
Ok(mut f) => match f.read_to_string(&mut text) {
Ok(_) => {},
Err(e) => {
if e.kind() == io::ErrorKind::InvalidData {
warn!("while reading from <{}>: {}", path.display(), e);
} else {
error!("while reading from <{}>: {}", path.display(), e);
return true;
}
}
},
Err(e) => {
error!("while loading from <{}>: {}", path.display(), e);
return true;
},
}
find_locs_text(path, &text, locs)
}
fn find_locs_dir(path: &PathBuf, loaded_dirs: &mut HashSet<PathBuf>,
locs: &mut HashMap<ArtName, Loc>)
-> bool {
loaded_dirs.insert(path.to_path_buf());
let read_dir = match fs::read_dir(path) {
Ok(d) => d,
Err(err) => {
error!("while loading from dir <{}>: {}", path.display(), err);
return true;
}
};
let mut error = false;
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 = match entry.file_type() {
Ok(f) => f,
Err(err) => {
error!("while loading from <{}>: {}", fpath.display(), err);
error = true;
continue;
}
};
if ftype.is_dir() {
dirs_to_load.push(fpath.clone());
} else if ftype.is_file() && find_locs_file(&fpath, locs) {
error = true
}
};
for d in dirs_to_load {
if !loaded_dirs.contains(&d) && find_locs_dir(&d, loaded_dirs, locs) {
error = true
}
}
error
}
pub fn find_locs(settings: &mut Settings) -> LoadResult<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()));
for d in &loaded_dirs {
if !d.exists() {
let mut msg = String::new();
write!(msg, "excluded path {} does not exist!", d.display()).unwrap();
return Err(LoadError::new(msg));
}
}
debug!("initial excluded code paths: {:?}", loaded_dirs);
while !settings.code_paths.is_empty() {
let dir = settings.code_paths.pop_front().unwrap(); if loaded_dirs.contains(&dir) {
continue
}
debug!("Loading from code: {:?}", dir);
if find_locs_dir(&dir, &mut loaded_dirs, &mut locs) {
return Err(LoadError::new("encountered errors while finding locations".to_string()))
}
}
Ok(locs)
}
pub fn attach_locs(artifacts: &mut Artifacts, mut locs: HashMap<ArtName, Loc>)
-> 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;
},
};
artifact.loc = Some(loc);
}
dne
}