gitcfg: Fix git-config usage for git 1.6.2
[git-cola.git] / cola / gitcfg.py
blob34f7a5853034e1e0aeca540b13e87845a10552bd
1 import os
2 import sys
3 import copy
5 from cola import core
6 from cola import gitcmd
7 from cola import utils
10 _config = None
11 def instance():
12 """Return a static GitConfig instance."""
13 global _config
14 if not _config:
15 _config = GitConfig()
16 return _config
19 def _find_in_path(app):
20 """Find a program in $PATH."""
21 is_win32 = sys.platform == 'win32'
22 for path in os.environ.get('PATH', '').split(os.pathsep):
23 candidate = os.path.join(path, app)
24 if os.path.exists(candidate):
25 return candidate
26 if is_win32:
27 candidate = os.path.join(path, app + '.exe')
28 if os.path.exists(candidate):
29 return candidate
30 return None
33 class GitConfig(object):
34 """Encapsulate access to git-config values."""
36 def __init__(self):
37 self.git = gitcmd.instance()
38 self._system = {}
39 self._user = {}
40 self._repo = {}
41 self._cache_key = None
42 self._configs = []
43 self._config_files = {}
44 self._find_config_files()
46 def reset(self):
47 self._system = {}
48 self._user = {}
49 self._repo = {}
50 self._configs = []
51 self._config_files = {}
52 self._find_config_files()
54 def user(self):
55 return copy.deepcopy(self._user)
57 def repo(self):
58 return copy.deepcopy(self._repo)
60 def _find_config_files(self):
61 """
62 Classify git config files into 'system', 'user', and 'repo'.
64 Populates self._configs with a list of the files in
65 reverse-precedence order. self._config_files is populated with
66 {category: path} where category is one of 'system', 'user', or 'repo'.
68 """
69 # Try the git config in git's installation prefix
70 git_path = _find_in_path('git')
71 if git_path:
72 bin_dir = os.path.dirname(git_path)
73 prefix = os.path.dirname(bin_dir)
74 system_config = os.path.join(prefix, 'etc', 'gitconfig')
75 if os.path.exists(system_config):
76 self._config_files['system'] = system_config
77 self._configs.append(system_config)
79 # Try /etc/gitconfig as a fallback for the system config
80 if 'system' not in self._config_files:
81 system_config = '/etc/gitconfig'
82 if os.path.exists(system_config):
83 self._config_files['system'] = system_config
84 self._configs.append(system_config)
86 # Check for the user config
87 user_config = os.path.expanduser('~/.gitconfig')
88 if os.path.exists(user_config):
89 self._config_files['user'] = user_config
90 self._configs.append(user_config)
92 # Check for the repo config
93 repo_config = self.git.git_path('config')
94 if os.path.exists(repo_config):
95 self._config_files['repo'] = repo_config
96 self._configs.append(repo_config)
98 def update(self):
99 """Read config values from git."""
100 if self._cached():
101 return
102 self._read_configs()
104 def _cached(self):
106 Return True when the cache matches.
108 Updates the cache and returns False when the cache does not match.
111 cache_key = map(utils.slurp, self._configs)
112 if not self._cache_key or cache_key != self._cache_key:
113 self._cache_key = cache_key
114 return False
115 return True
117 def _read_configs(self):
118 """Read git config value into the system, user and repo dicts."""
119 self._system = {}
120 self._user = {}
121 self._repo = {}
123 if 'system' in self._config_files:
124 self._system = self.read_config(self._config_files['system'])
126 if 'user' in self._config_files:
127 self._user = self.read_config(self._config_files['user'])
129 if 'repo' in self._config_files:
130 self._repo = self.read_config(self._config_files['repo'])
132 def read_config(self, path):
133 """Return git config data from a path as a dictionary."""
134 dest = {}
135 args = ('--null', '--file', path, '--list')
136 config_lines = self.git.config(*args).split('\0')
137 for line in config_lines:
138 try:
139 k, v = line.split('\n')
140 except:
141 # the user has an invalid entry in their git config
142 continue
143 v = core.decode(v)
144 if v == 'true' or v == 'false':
145 v = bool(eval(v.title()))
146 try:
147 v = int(eval(v))
148 except:
149 pass
150 dest[k] = v
151 return dest
153 def get(self, key, default=None):
154 """Return the string value for a config key."""
155 self.update()
156 for dct in (self._repo, self._user, self._system):
157 if key in dct:
158 return dct[key]
159 return default