chiark / gitweb /
Refactor output handling to break circular dependency
[stgit] / stgit / config.py
1 """Handles the Stacked GIT configuration files
2 """
3
4 __copyright__ = """
5 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 """
20
21 import os, re
22 from stgit import basedir
23
24 class GitConfigException(Exception):
25     pass
26
27 class GitConfig:
28     __defaults={
29         'stgit.autoresolved':   'no',
30         'stgit.smtpserver':     'localhost:25',
31         'stgit.smtpdelay':      '5',
32         'stgit.pullcmd':        'git-pull',
33         'stgit.fetchcmd':       'git-fetch',
34         'stgit.pull-policy':    'pull',
35         'stgit.merger':         'diff3 -L current -L ancestor -L patched -m -E ' \
36                                 '"%(branch1)s" "%(ancestor)s" "%(branch2)s" > "%(output)s"',
37         'stgit.autoimerge':     'no',
38         'stgit.keeporig':       'yes',
39         'stgit.keepoptimized':  'no',
40         'stgit.extensions':     '.ancestor .current .patched',
41         'stgit.shortnr':         '5'
42         }
43
44     __cache={}
45
46     def __run(self, cmd, args=None):
47         """__run: runs cmd using spawnvp.
48     
49         Runs cmd using spawnvp.  The shell is avoided so it won't mess up
50         our arguments.  If args is very large, the command is run multiple
51         times; args is split xargs style: cmd is passed on each
52         invocation.  Unlike xargs, returns immediately if any non-zero
53         return code is received.  
54         """
55         
56         args_l=cmd.split()
57         if args is None:
58             args = []
59         for i in range(0, len(args)+1, 100):
60             r=os.spawnvp(os.P_WAIT, args_l[0], args_l + args[i:min(i+100, len(args))])
61         if r:
62             return r
63         return 0
64     
65     def get(self, name):
66         if self.__cache.has_key(name):
67             return self.__cache[name]
68
69         stream = os.popen('git repo-config --get %s' % name, 'r')
70         value = stream.readline().strip()
71         stream.close()
72         if len(value) > 0:
73             pass
74         elif (self.__defaults.has_key(name)):
75             value = self.__defaults[name]
76         else:
77             value = None
78
79         self.__cache[name] = value
80         return value
81
82     def getall(self, name):
83         if self.__cache.has_key(name):
84             return self.__cache[name]
85
86         stream = os.popen('git repo-config --get-all %s' % name, 'r')
87         values = [line.strip() for line in stream]
88         stream.close()
89
90         self.__cache[name] = values
91         return values
92
93     def getint(self, name):
94         value = self.get(name)
95         if value.isdigit():
96             return int(value)
97         else:
98             raise GitConfigException, 'Value for "%s" is not an integer: "%s"' % (name, value)
99
100     def rename_section(self, from_name, to_name):
101         self.__run('git-repo-config --rename-section', [from_name, to_name])
102         self.__cache.clear()
103
104     def set(self, name, value):
105         self.__run('git-repo-config', [name, value])
106         self.__cache[name] = value
107
108     def unset(self, name):
109         self.__run('git-repo-config --unset', [name])
110         self.__cache[name] = None
111
112     def sections_matching(self, regexp):
113         """Takes a regexp with a single group, matches it against all
114         config variables, and returns a list whose members are the
115         group contents, for all variable names matching the regexp.
116         """
117         result = []
118         stream = os.popen('git repo-config --get-regexp "^%s$"' % regexp, 'r')
119         for line in stream:
120             m = re.match('^%s ' % regexp, line)
121             if m:
122                 result.append(m.group(1))
123         stream.close()
124         return result
125         
126 config=GitConfig()
127
128 def config_setup():
129     global config
130
131     # Set the PAGER environment to the config value (if any)
132     pager = config.get('stgit.pager')
133     if pager:
134         os.environ['PAGER'] = pager
135     # FIXME: handle EDITOR the same way ?
136
137 class ConfigOption:
138     """Delayed cached reading of a configuration option.
139     """
140     def __init__(self, section, option):
141         self.__section = section
142         self.__option = option
143         self.__value = None
144
145     def __str__(self):
146         if not self.__value:
147             self.__value = config.get(self.__section + '.' + self.__option)
148         return self.__value
149
150
151 # cached extensions
152 __extensions = None
153
154 def file_extensions():
155     """Returns a dictionary with the conflict file extensions
156     """
157     global __extensions
158
159     if not __extensions:
160         cfg_ext = config.get('stgit.extensions').split()
161         if len(cfg_ext) != 3:
162             raise CmdException, '"extensions" configuration error'
163
164         __extensions = { 'ancestor': cfg_ext[0],
165                          'current':  cfg_ext[1],
166                          'patched':  cfg_ext[2] }
167
168     return __extensions