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
#[macro_use]
pub extern crate slog;
extern crate gtmpl;
#[macro_use]
extern crate gtmpl_derive;
extern crate gtmpl_value;
extern crate walkdir;
use std::path::Path;
use walkdir::DirEntry;
use walkdir::WalkDir;
pub struct Ctx {
pub logger: slog::Logger,
}
#[derive(Debug, Clone, Gtmpl)]
pub struct GitRepo {
path: Location,
}
#[derive(Debug, Clone, Gtmpl)]
pub struct Location {
full: String,
file_name: String,
}
pub fn find_repos(ctx: &Ctx, root: &Path) -> Vec<GitRepo> {
info!(ctx.logger, "find repositories"; "root" => &root.to_str());
let mut found = vec![];
let mut it = WalkDir::new(root).into_iter();
loop {
let entry = match it.next() {
None => break,
Some(Err(err)) => {
warn!(ctx.logger, "fail to access"; "err" => format!("{:?}", err));
continue;
}
Some(Ok(entry)) => entry,
};
if is_hidden(&entry) {
if entry.file_type().is_dir() {
it.skip_current_dir();
}
continue;
}
if is_gitrepo(&entry) {
found.push(GitRepo {
path: Location {
full: entry.path().to_str().map(|x| x.to_owned()).unwrap(),
file_name: entry.file_name().to_str().map(|x| x.to_owned()).unwrap(),
},
});
it.skip_current_dir();
continue;
}
}
found
}
pub fn render(ctx: &Ctx, tmpl: &str, value: &GitRepo) -> String {
gtmpl::template(tmpl, value.clone()).expect("template")
}
fn is_hidden(entry: &DirEntry) -> bool {
entry
.file_name()
.to_str()
.map(|s| s.starts_with("."))
.unwrap_or(false)
}
fn is_gitrepo(entry: &DirEntry) -> bool {
entry.path().is_dir() && {
let p = entry.path().join(".git");
p.exists() && p.is_dir()
}
}