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;
        }
        //println!("{}", &entry.path().display());
    }
    found
}

pub fn render(ctx: &Ctx, tmpl: &str, value: &GitRepo) -> String {
    //TODO remove the clone() and provide Value for &GitRepo
    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()
    }
}