git_together_ssh/
git.rs

1use std::collections::HashMap;
2use std::env;
3
4use crate::config;
5use crate::errors::*;
6use crate::ConfigScope;
7
8pub struct Repo {
9    repo: git2::Repository,
10}
11
12impl Repo {
13    pub fn new() -> Result<Self> {
14        let repo = env::current_dir()
15            .chain_err(|| "")
16            .and_then(|current_dir| git2::Repository::discover(current_dir).chain_err(|| ""))?;
17        Ok(Repo { repo })
18    }
19
20    pub fn config(&self) -> Result<Config> {
21        self.repo
22            .config()
23            .map(|config| Config { config })
24            .chain_err(|| "")
25    }
26
27    pub fn auto_include(&self, filename: &str) -> Result<()> {
28        let include_path = format!("../{}", filename);
29
30        let workdir = match self.repo.workdir() {
31            Some(dir) => dir,
32            _ => {
33                return Ok(());
34            }
35        };
36
37        let mut path_buf = workdir.to_path_buf();
38        path_buf.push(filename);
39        if !path_buf.exists() {
40            return Ok(());
41        }
42
43        let include_paths = self.include_paths()?;
44        if include_paths.contains(&include_path) {
45            return Ok(());
46        }
47
48        let mut config = self.local_config()?;
49        config
50            .set_multivar("include.path", "^$", &include_path)
51            .and(Ok(()))
52            .chain_err(|| "")
53    }
54
55    fn include_paths(&self) -> Result<Vec<String>> {
56        let config = self.local_config()?;
57        let mut include_paths: Vec<String> = Vec::new();
58        config
59            .entries(Some("include.path"))
60            .chain_err(|| "")?
61            .for_each(|entry| {
62                let value = entry.value().unwrap_or("").to_string();
63                include_paths.push(value)
64            }).chain_err(|| "")?;
65        Ok(include_paths)
66    }
67
68    fn local_config(&self) -> Result<git2::Config> {
69        let config = self.repo.config().chain_err(|| "")?;
70        config.open_level(git2::ConfigLevel::Local).chain_err(|| "")
71    }
72}
73
74pub struct Config {
75    config: git2::Config,
76}
77
78impl Config {
79    pub fn new(scope: ConfigScope) -> Result<Self> {
80        let config = match scope {
81            ConfigScope::Local => git2::Config::open_default(),
82            ConfigScope::Global => git2::Config::open_default().and_then(|mut r| r.open_global()),
83        };
84
85        config.map(|config| Config { config }).chain_err(|| "")
86    }
87}
88
89impl config::Config for Config {
90    fn get(&self, name: &str) -> Result<String> {
91        self.config
92            .get_string(name)
93            .chain_err(|| format!("error getting git config for '{}'", name))
94    }
95
96    fn get_all(&self, glob: &str) -> Result<HashMap<String, String>> {
97        let mut result = HashMap::new();
98        let entries = self
99            .config
100            .entries(Some(glob))
101            .chain_err(|| "error getting git config entries")?;
102        entries.for_each(|entry| {
103            if let (Some(name), Some(value)) = (entry.name(), entry.value()) {
104                result.insert(name.into(), value.into());
105            }
106        }).chain_err(|| "")?;
107        Ok(result)
108    }
109
110    fn add(&mut self, name: &str, value: &str) -> Result<()> {
111        self.config
112            .set_multivar(name, "^$", value)
113            .chain_err(|| format!("error adding git config '{}': '{}'", name, value))
114    }
115
116    fn set(&mut self, name: &str, value: &str) -> Result<()> {
117        self.config
118            .set_str(name, value)
119            .chain_err(|| format!("error setting git config '{}': '{}'", name, value))
120    }
121
122    fn clear(&mut self, name: &str) -> Result<()> {
123        self.config
124            .remove(name)
125            .chain_err(|| format!("error removing git config '{}'", name))
126    }
127}