Repair `stg log` with patches from subdir
[stgit.git] / stgit / config.py
blob46a64fbccd2db7c1e1ec8e32f2dbc81494d5184d
1 """Handles the Stacked GIT configuration files"""
3 import os
5 from stgit.exception import StgException
6 from stgit.run import Run
8 __copyright__ = """
9 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License version 2 as
13 published by the Free Software Foundation.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see http://www.gnu.org/licenses/.
22 """
24 DEFAULTS = [
25 ('i18n.commitencoding', ['UTF-8']),
26 ('stgit.alias.add', ['git add']),
27 ('stgit.alias.mv', ['git mv']),
28 ('stgit.alias.resolved', ['git add']),
29 ('stgit.alias.rm', ['git rm']),
30 ('stgit.alias.status', ['git status -s']),
31 ('stgit.autoimerge', ['no']),
32 ('stgit.fetchcmd', ['git fetch']),
33 ('stgit.keepoptimized', ['no']),
34 ('stgit.pager', ['less']),
35 ('stgit.pick.expose-format', ['format:%B%n(imported from commit %H)']),
36 ('stgit.pull-policy', ['pull']),
37 ('stgit.pullcmd', ['git pull']),
38 ('stgit.refreshsubmodules', ['no']),
39 ('stgit.shortnr', ['5']),
40 ('stgit.series.description', ['no']),
41 ('stgit.smtpdelay', ['5']),
42 ('stgit.smtpserver', ['localhost:25']),
46 class GitConfigException(StgException):
47 pass
50 class GitConfig:
52 _cache = None
54 def load(self):
55 """Load the configuration in _cache unless it has been done already."""
56 if self._cache is not None:
57 return
58 self._cache = dict(DEFAULTS)
59 lines = (
60 Run('git', 'config', '--null', '--list')
61 .discard_exitcode()
62 .output_lines('\0')
64 for line in lines:
65 try:
66 key, value = line.split('\n', 1)
67 except ValueError:
68 key = line
69 value = None
70 self._cache.setdefault(key, []).append(value)
72 def get(self, name):
73 self.load()
74 try:
75 return self._cache[name][-1]
76 except KeyError:
77 return None
79 def getint(self, name):
80 value = self.get(name)
81 if value is None:
82 return None
83 try:
84 return int(value)
85 except ValueError:
86 raise GitConfigException(
87 'Value for "%s" is not an integer: "%s"' % (name, value)
90 def getbool(self, name):
91 """Report the canonicalized boolean value for a given key."""
92 # We cannot directly call get() because we need to use the KeyError in
93 # order to distinguish between the case of a key with an undefined
94 # value, and a completely undefined key. Git expects the former to be
95 # reported as "true".
96 self.load()
97 try:
98 value = self._cache[name][-1]
99 except KeyError:
100 return None
102 if value is None:
103 # The key is defined, but the value is not, so treat it as true.
104 return True
105 elif value in ['yes', 'on', 'true']:
106 return True
107 elif value in ['no', 'off', 'false', '']:
108 return False
109 elif value.isdigit():
110 return bool(value)
111 else:
112 raise GitConfigException(
113 'Value for "%s" is not a boolean: "%s"' % (name, value)
116 def getstartswith(self, name):
117 self.load()
118 return ((n, v[-1]) for (n, v) in self._cache.items() if n.startswith(name))
120 def rename_section(self, from_name, to_name):
121 """Rename a section in the config file. Silently do nothing if
122 the section doesn't exist."""
123 Run('git', 'config', '--rename-section', from_name, to_name).returns(
124 [0, 1, 128]
125 ).run()
126 self._cache.clear()
128 def remove_section(self, name):
129 """Remove a section in the config file. Silently do nothing if
130 the section doesn't exist."""
131 Run('git', 'config', '--remove-section', name).returns(
132 [0, 1, 128]
133 ).discard_stderr().discard_output()
134 self._cache.clear()
136 def set(self, name, value):
137 Run('git', 'config', name, value).run()
138 self._cache[name] = value
140 def unset(self, name):
141 Run('git', 'config', '--unset', name).run()
142 self._cache[name] = [None]
144 def get_colorbool(self, name, stdout_is_tty):
145 """Invoke 'git config --get-colorbool' and return the result."""
146 return Run(
147 'git', 'config', '--get-colorbool', name, stdout_is_tty
148 ).output_one_line()
151 config = GitConfig()
154 def config_setup():
155 global config
157 os.environ.setdefault('PAGER', config.get('stgit.pager'))
158 os.environ.setdefault('LESS', '-FRSX')
159 # FIXME: handle EDITOR the same way ?