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}