51
51
NB: This option is planned, but not implemented yet.
54
from ConfigParser import ConfigParser
56
58
from fnmatch import fnmatch
61
62
import bzrlib.errors as errors
63
import bzrlib.util.configobj.configobj as configobj
64
from StringIO import StringIO
64
66
CHECK_IF_POSSIBLE=0
71
class ConfigObj(configobj.ConfigObj):
73
def get_bool(self, section, key):
74
val = self[section][key].lower()
75
if val in ('1', 'yes', 'true', 'on'):
77
elif val in ('0', 'no', 'false', 'off'):
80
raise ValueError("Value %r is not boolean" % val)
82
def get_value(self, section, name):
83
# Try [] for the old DEFAULT section.
84
if section == "DEFAULT":
89
return self[section][name]
69
92
class Config(object):
70
93
"""A configuration policy - what username, editor, gpg needs etc."""
76
99
def _get_signature_checking(self):
77
100
"""Template method to override signature checking policy."""
102
def _get_user_option(self, option_name):
103
"""Template method to provide a user option."""
106
def get_user_option(self, option_name):
107
"""Get a generic option - no special process, no default."""
108
return self._get_user_option(option_name)
79
110
def gpg_signing_command(self):
80
111
"""What program should be used to sign signatures?"""
81
112
result = self._gpg_signing_command()
90
121
def __init__(self):
91
122
super(Config, self).__init__()
124
def post_commit(self):
125
"""An ordered list of python functions to call.
127
Each function takes branch, rev_id as parameters.
129
return self._post_commit()
131
def _post_commit(self):
132
"""See Config.post_commit."""
93
135
def user_email(self):
94
136
"""Return just the email component of a username."""
96
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
98
raise BzrError("%r doesn't seem to contain "
99
"a reasonable email address" % e)
137
return extract_email_address(self.username())
102
139
def username(self):
103
140
"""Return email-style username.
107
144
$BZREMAIL can be set to override this, then
108
145
the concrete policy type is checked, and finally
110
but if none is found, a reasonable default is (hopefully)
147
If none is found, a reasonable default is (hopefully)
113
150
TODO: Check it's reasonably well-formed.
151
188
def _get_parser(self, file=None):
152
189
if self._parser is not None:
153
190
return self._parser
154
parser = ConfigParser()
192
input = self._get_filename()
158
parser.read([self._get_filename()])
159
self._parser = parser
196
self._parser = ConfigObj(input)
197
except configobj.ConfigObjError, e:
198
raise errors.ParseConfigError(e.errors, e.config.filename)
162
201
def _get_section(self):
163
202
"""Override this to define the section used by the config."""
166
205
def _get_signature_checking(self):
167
206
"""See Config._get_signature_checking."""
168
section = self._get_section()
171
if self._get_parser().has_option(section, 'check_signatures'):
172
return self._string_to_signature_policy(
173
self._get_parser().get(section, 'check_signatures'))
207
policy = self._get_user_option('check_signatures')
209
return self._string_to_signature_policy(policy)
175
211
def _get_user_id(self):
176
212
"""Get the user id from the 'email' key in the current section."""
177
section = self._get_section()
178
if section is not None:
179
if self._get_parser().has_option(section, 'email'):
180
return self._get_parser().get(section, 'email')
213
return self._get_user_option('email')
215
def _get_user_option(self, option_name):
216
"""See Config._get_user_option."""
218
return self._get_parser().get_value(self._get_section(),
182
223
def _gpg_signing_command(self):
183
224
"""See Config.gpg_signing_command."""
184
section = self._get_section()
185
if section is not None:
186
if self._get_parser().has_option(section, 'gpg_signing_command'):
187
return self._get_parser().get(section, 'gpg_signing_command')
225
return self._get_user_option('gpg_signing_command')
189
227
def __init__(self, get_filename):
190
228
super(IniBasedConfig, self).__init__()
191
229
self._get_filename = get_filename
192
230
self._parser = None
232
def _post_commit(self):
233
"""See Config.post_commit."""
234
return self._get_user_option('post_commit')
194
236
def _string_to_signature_policy(self, signature_string):
195
237
"""Convert a string to a signing policy."""
207
249
"""The configuration that should be used for a specific location."""
209
251
def get_editor(self):
210
if self._get_parser().has_option(self._get_section(), 'editor'):
211
return self._get_parser().get(self._get_section(), 'editor')
252
return self._get_user_option('editor')
213
254
def __init__(self):
214
255
super(GlobalConfig, self).__init__(config_filename)
234
275
TODO: perhaps return a NullSection that thunks through to the
237
sections = self._get_parser().sections()
278
sections = self._get_parser()
238
279
location_names = self.location.split('/')
239
280
if self.location.endswith('/'):
240
281
del location_names[-1]
258
299
# if path is longer, and recurse is not true, no match
259
300
if len(section_names) < len(location_names):
260
if (self._get_parser().has_option(section, 'recurse')
261
and not self._get_parser().getboolean(section, 'recurse')):
302
if not self._get_parser().get_bool(section, 'recurse'):
263
306
matches.append((len(section_names), section))
264
307
if not len(matches):
280
323
return self._get_global_config()._get_user_id()
325
def _get_user_option(self, option_name):
326
"""See Config._get_user_option."""
327
option_value = super(LocationConfig,
328
self)._get_user_option(option_name)
329
if option_value is not None:
331
return self._get_global_config()._get_user_option(option_name)
282
333
def _get_signature_checking(self):
283
334
"""See Config._get_signature_checking."""
284
335
check = super(LocationConfig, self)._get_signature_checking()
287
338
return self._get_global_config()._get_signature_checking()
340
def _post_commit(self):
341
"""See Config.post_commit."""
342
hook = self._get_user_option('post_commit')
345
return self._get_global_config()._post_commit()
347
def set_user_option(self, option, value):
348
"""Save option and its value in the configuration."""
349
# FIXME: RBC 20051029 This should refresh the parser and also take a
350
# file lock on branches.conf.
351
if not os.path.isdir(os.path.dirname(self._get_filename())):
352
os.mkdir(os.path.dirname(self._get_filename()))
353
location = self.location
354
if location.endswith('/'):
355
location = location[:-1]
356
if (not location in self._get_parser() and
357
not location + '/' in self._get_parser()):
358
self._get_parser()[location]={}
359
elif location + '/' in self._get_parser():
360
location = location + '/'
361
self._get_parser()[location][option]=value
362
self._get_parser().write()
290
365
class BranchConfig(Config):
291
366
"""A configuration object giving the policy for a branch."""
315
390
"""See Config._get_signature_checking."""
316
391
return self._get_location_config()._get_signature_checking()
393
def _get_user_option(self, option_name):
394
"""See Config._get_user_option."""
395
return self._get_location_config()._get_user_option(option_name)
318
397
def _gpg_signing_command(self):
319
398
"""See Config.gpg_signing_command."""
320
399
return self._get_location_config()._gpg_signing_command()
333
416
TODO: Global option --config-dir to override this.
335
return os.path.join(os.path.expanduser("~"), ".bazaar")
418
base = os.environ.get('BZR_HOME', None)
419
if sys.platform == 'win32':
421
base = os.environ.get('APPDATA', None)
423
base = os.environ.get('HOME', None)
425
raise BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
426
return os.path.join(base, 'bazaar', '2.0')
428
# cygwin, linux, and darwin all have a $HOME directory
430
base = os.path.expanduser("~")
431
return os.path.join(base, ".bazaar")
338
434
def config_filename():
394
490
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
396
raise BzrError("%r doesn't seem to contain "
397
"a reasonable email address" % e)
492
raise errors.BzrError("%r doesn't seem to contain "
493
"a reasonable email address" % e)
398
494
return m.group(0)
496
class TreeConfig(object):
497
"""Branch configuration data associated with its contents, not location"""
498
def __init__(self, branch):
501
def _get_config(self):
503
obj = ConfigObj(self.branch.controlfile('branch.conf',
506
except errors.NoSuchFile:
510
def get_option(self, name, section=None, default=None):
511
self.branch.lock_read()
513
obj = self._get_config()
515
if section is not None:
524
def set_option(self, value, name, section=None):
525
"""Set a per-branch configuration option"""
526
self.branch.lock_write()
528
cfg_obj = self._get_config()
533
obj = cfg_obj[section]
535
cfg_obj[section] = {}
536
obj = cfg_obj[section]
538
cfg_obj.encode('UTF-8')
539
out_file = StringIO(''.join([l+'\n' for l in cfg_obj.write()]))
541
self.branch.put_controlfile('branch.conf', out_file, encode=False)