stg import now extracts Message-ID header
[stgit.git] / stgit / config.py
blob226698a26e7e61cf77840d4a0d6d430aba721247
1 """Handles the StGit 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.namelength', ['30']),
35 ('stgit.pager', ['less']),
36 ('stgit.pick.expose-format', ['format:%B%n(imported from commit %H)']),
37 ('stgit.pull-policy', ['pull']),
38 ('stgit.pullcmd', ['git pull']),
39 ('stgit.refreshsubmodules', ['no']),
40 ('stgit.shortnr', ['5']),
41 ('stgit.series.description', ['no']),
42 ('stgit.smtpdelay', ['5']),
43 ('stgit.smtpserver', ['localhost:25']),
47 class GitConfigException(StgException):
48 pass
51 class GitConfig:
53 _cache = None
55 def load(self):
56 """Load the configuration in _cache unless it has been done already."""
57 if self._cache is not None:
58 return
59 self._cache = dict(DEFAULTS)
60 lines = (
61 Run('git', 'config', '--null', '--list')
62 .discard_exitcode()
63 .output_lines('\0')
65 for line in lines:
66 try:
67 key, value = line.split('\n', 1)
68 except ValueError:
69 key = line
70 value = None
71 self._cache.setdefault(key, []).append(value)
73 def get(self, name):
74 self.load()
75 try:
76 return self._cache[name][-1]
77 except KeyError:
78 return None
80 def getint(self, name):
81 value = self.get(name)
82 if value is None:
83 return None
84 try:
85 return int(value)
86 except ValueError:
87 raise GitConfigException(
88 'Value for "%s" is not an integer: "%s"' % (name, value)
91 def getbool(self, name):
92 """Report the canonicalized boolean value for a given key."""
93 # We cannot directly call get() because we need to use the KeyError in
94 # order to distinguish between the case of a key with an undefined
95 # value, and a completely undefined key. Git expects the former to be
96 # reported as "true".
97 self.load()
98 try:
99 value = self._cache[name][-1]
100 except KeyError:
101 return None
103 if value is None:
104 # The key is defined, but the value is not, so treat it as true.
105 return True
106 elif value in ['yes', 'on', 'true']:
107 return True
108 elif value in ['no', 'off', 'false', '']:
109 return False
110 elif value.isdigit():
111 return bool(value)
112 else:
113 raise GitConfigException(
114 'Value for "%s" is not a boolean: "%s"' % (name, value)
117 def getstartswith(self, name):
118 self.load()
119 return ((n, v[-1]) for (n, v) in self._cache.items() if n.startswith(name))
121 def rename_section(self, from_name, to_name):
122 """Rename a section in the config file. Silently do nothing if
123 the section doesn't exist."""
124 Run('git', 'config', '--rename-section', from_name, to_name).returns(
125 [0, 1, 128]
126 ).run()
127 self._cache.clear()
129 def remove_section(self, name):
130 """Remove a section in the config file. Silently do nothing if
131 the section doesn't exist."""
132 Run('git', 'config', '--remove-section', name).returns(
133 [0, 1, 128]
134 ).discard_stderr().discard_output()
135 self._cache.clear()
137 def set(self, name, value):
138 Run('git', 'config', name, value).run()
139 self._cache[name] = value
141 def unset(self, name):
142 Run('git', 'config', '--unset', name).run()
143 self._cache[name] = [None]
145 def get_colorbool(self, name, stdout_is_tty):
146 """Invoke 'git config --get-colorbool' and return the result."""
147 return Run(
148 'git', 'config', '--get-colorbool', name, stdout_is_tty
149 ).output_one_line()
152 config = GitConfig()
155 def config_setup():
156 global config
158 os.environ.setdefault('PAGER', config.get('stgit.pager'))
159 os.environ.setdefault('LESS', '-FRSX')
160 # FIXME: handle EDITOR the same way ?