7 from cola
import observable
8 from cola
.decorators
import memoize
13 """Return a static GitConfig instance."""
18 # Try /etc/gitconfig as a fallback for the system config
19 userconfig
= os
.path
.expanduser(os
.path
.join('~', '.gitconfig'))
20 paths
= (('system', '/etc/gitconfig'),
21 ('user', core
.decode(userconfig
)),
22 ('repo', core
.decode(git
.instance().git_path('config'))))
24 for category
, path
in paths
:
26 statinfo
.append((category
, path
, os
.stat(path
).st_mtime
))
33 # Try /etc/gitconfig as a fallback for the system config
34 userconfig
= os
.path
.expanduser(os
.path
.join('~', '.gitconfig'))
35 paths
= ('/etc/gitconfig',
37 git
.instance().git_path('config'))
41 mtimes
.append(os
.stat(path
).st_mtime
)
47 class GitConfig(observable
.Observable
):
48 """Encapsulate access to git-config values."""
50 message_user_config_changed
= 'user_config_changed'
51 message_repo_config_changed
= 'repo_config_changed'
54 observable
.Observable
.__init
__(self
)
55 self
.git
= git
.instance()
60 self
._cache
_key
= None
62 self
._config
_files
= {}
63 self
._find
_config
_files
()
70 self
._cache
_key
= None
72 self
._config
_files
= {}
73 self
._find
_config
_files
()
76 return copy
.deepcopy(self
._user
)
79 return copy
.deepcopy(self
._repo
)
82 return copy
.deepcopy(self
._all
)
84 def _find_config_files(self
):
86 Classify git config files into 'system', 'user', and 'repo'.
88 Populates self._configs with a list of the files in
89 reverse-precedence order. self._config_files is populated with
90 {category: path} where category is one of 'system', 'user', or 'repo'.
93 # Try the git config in git's installation prefix
94 statinfo
= _stat_info()
95 self
._configs
= map(lambda x
: x
[1], statinfo
)
96 self
._config
_files
= {}
97 for (cat
, path
, mtime
) in statinfo
:
98 self
._config
_files
[cat
] = path
101 """Read config values from git."""
108 Return True when the cache matches.
110 Updates the cache and returns False when the cache does not match.
113 cache_key
= _cache_key()
114 if not self
._cache
_key
or cache_key
!= self
._cache
_key
:
115 self
._cache
_key
= cache_key
119 def _read_configs(self
):
120 """Read git config value into the system, user and repo dicts."""
126 if 'system' in self
._config
_files
:
127 self
._system
= self
.read_config(self
._config
_files
['system'])
129 if 'user' in self
._config
_files
:
130 self
._user
= self
.read_config(self
._config
_files
['user'])
132 if 'repo' in self
._config
_files
:
133 self
._repo
= self
.read_config(self
._config
_files
['repo'])
136 for dct
in (self
._system
, self
._user
, self
._repo
):
137 self
._all
.update(dct
)
139 def read_config(self
, path
):
140 """Return git config data from a path as a dictionary."""
142 args
= ('--null', '--file', path
, '--list')
143 config_lines
= self
.git
.config(*args
).split('\0')
144 for line
in config_lines
:
146 k
, v
= line
.split('\n', 1)
148 # the user has an invalid entry in their git config
155 if v
in ('true', 'yes'):
157 elif v
in ('false', 'no'):
167 def get(self
, key
, default
=None, source
=None):
168 """Return the string value for a config key."""
170 return self
._all
.get(key
, default
)
172 def get_user(self
, key
, default
=None):
174 return self
._user
.get(key
, default
)
176 def get_repo(self
, key
, default
=None):
178 return self
._repo
.get(key
, default
)
180 def python_to_git(self
, value
):
181 if type(value
) is bool:
186 if type(value
) is int:
187 return unicode(value
)
190 def set_user(self
, key
, value
):
191 msg
= self
.message_user_config_changed
192 self
.git
.config('--global', key
, self
.python_to_git(value
))
194 self
.notify_message_observers(msg
, key
, value
)
196 def set_repo(self
, key
, value
):
197 msg
= self
.message_repo_config_changed
198 self
.git
.config(key
, self
.python_to_git(value
))
200 self
.notify_message_observers(msg
, key
, value
)
204 for key
, val
in self
._all
.items():
205 if fnmatch
.fnmatch(key
, pat
):
209 def get_encoding(self
, default
='utf-8'):
210 return self
.get('gui.encoding', default
=default
)
212 guitool_opts
= ('cmd', 'needsfile', 'noconsole', 'norescan', 'confirm',
213 'argprompt', 'revprompt', 'revunmerged', 'title', 'prompt')
215 def get_guitool_opts(self
, name
):
216 """Return the guitool.<name> namespace as a dict"""
217 keyprefix
= 'guitool.' + name
+ '.'
219 for cfg
in self
.guitool_opts
:
220 value
= self
.get(keyprefix
+ cfg
)
226 def get_guitool_names(self
):
228 guitools
= self
.find('guitool.*.cmd')
229 for name
, cmd
in guitools
.items():
230 name
= name
[len('guitool.'):-len('.cmd')]