hotspots_discovery/
lib.rs1#![warn(missing_docs)]
3use log::debug;
4use rayon::prelude::*;
5use std::{ops::Not, path::Path, result, time::Instant};
6use walkdir::{DirEntry, WalkDir};
7
8#[derive(Debug, Eq, PartialEq)]
11pub enum Lang {
12 Rust,
14 Go,
16 Lua,
18 Undefined,
20}
21
22impl From<&str> for Lang {
23 fn from(value: &str) -> Self {
25 match value {
26 "go" => Lang::Go,
27 "rust" => Lang::Rust,
28 "lua" => Lang::Lua,
29 _ => Lang::Undefined,
30 }
31 }
32}
33
34#[derive(Debug, Eq, PartialEq)]
36pub struct File {
37 pub path: String,
39 pub lang: Lang,
41}
42
43#[derive(Default)]
46pub struct Discovery {
47 prefixes: Vec<String>,
48 not_contains: Vec<String>,
49}
50
51impl Discovery {
52 pub fn with_prefix(&mut self, p: String) {
54 self.prefixes.push(p);
55 }
56 pub fn not_contains(&mut self, p: String) {
58 self.not_contains.push(p);
59 }
60
61 pub fn discover<P: AsRef<Path>>(&self, path: P) -> Option<Vec<File>> {
64 let start = Instant::now();
65 let res: Vec<File> = WalkDir::new(&path)
66 .into_iter()
67 .par_bridge()
68 .filter_map(result::Result::ok)
69 .filter(|p| {
70 if self.prefixes.is_empty() {
71 true
72 } else {
73 self.prefixes
74 .iter()
75 .any(|prefix| p.path().starts_with(prefix))
76 }
77 })
78 .filter(|p| {
79 if self.not_contains.is_empty() {
80 true
81 } else {
82 self.not_contains
83 .iter()
84 .any(|prefix| p.path().to_str().unwrap_or("").contains(prefix))
85 .not()
86 }
87 })
88 .filter(is_project_file)
89 .filter_map(|p| {
90 let lang = match detect_lang::from_path(p.path()) {
91 Some(lang) => lang.id().into(),
92 None => Lang::Undefined,
93 };
94 let p = p.path().to_str();
95
96 p.map(|path| File {
97 path: path.to_owned(),
98 lang,
99 })
100 })
101 .collect();
102
103 debug!("Discovery took {:?}", start.elapsed());
104
105 if res.is_empty() {
106 None
107 } else {
108 Some(res)
109 }
110 }
111}
112
113fn is_project_file(entry: &DirEntry) -> bool {
115 if entry.file_type().is_dir() {
116 return false;
117 }
118 entry
119 .file_name()
120 .to_str()
121 .map(|s| !s.starts_with('.'))
122 .unwrap_or(false)
123}
124
125#[cfg(test)]
126mod tests;