michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this, michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: from __future__ import unicode_literals michael@0: michael@0: from configobj import ConfigObj michael@0: import re michael@0: import os michael@0: michael@0: michael@0: HOST_FINGERPRINTS = { michael@0: 'bitbucket.org': '45:ad:ae:1a:cf:0e:73:47:06:07:e0:88:f5:cc:10:e5:fa:1c:f7:99', michael@0: 'bugzilla.mozilla.org': '47:13:a2:14:0c:46:45:53:12:0d:e5:36:16:a5:60:26:3e:da:3a:60', michael@0: 'hg.mozilla.org': 'af:27:b9:34:47:4e:e5:98:01:f6:83:2b:51:c9:aa:d8:df:fb:1a:27', michael@0: } michael@0: michael@0: michael@0: class MercurialConfig(object): michael@0: """Interface for manipulating a Mercurial config file.""" michael@0: michael@0: def __init__(self, infiles=None): michael@0: """Create a new instance, optionally from an existing hgrc file.""" michael@0: michael@0: if infiles: michael@0: # If multiple files were specified, figure out which file we're using: michael@0: if len(infiles) > 1: michael@0: picky_infiles = filter(os.path.isfile, infiles) michael@0: if picky_infiles: michael@0: picky_infiles = [(os.path.getsize(path), path) for path in picky_infiles] michael@0: infiles = [max(picky_infiles)[1]] michael@0: michael@0: infile = infiles[0] michael@0: self.config_path = infile michael@0: else: michael@0: infile = None michael@0: michael@0: # write_empty_values is necessary to prevent built-in extensions (which michael@0: # have no value) from being dropped on write. michael@0: # list_values aren't needed by Mercurial and disabling them prevents michael@0: # quotes from being added. michael@0: self._c = ConfigObj(infile=infile, encoding='utf-8', michael@0: write_empty_values=True, list_values=False) michael@0: michael@0: @property michael@0: def config(self): michael@0: return self._c michael@0: michael@0: @property michael@0: def extensions(self): michael@0: """Returns the set of currently enabled extensions (by name).""" michael@0: return set(self._c.get('extensions', {}).keys()) michael@0: michael@0: def write(self, fh): michael@0: return self._c.write(fh) michael@0: michael@0: def have_valid_username(self): michael@0: if 'ui' not in self._c: michael@0: return False michael@0: michael@0: if 'username' not in self._c['ui']: michael@0: return False michael@0: michael@0: # TODO perform actual validation here. michael@0: michael@0: return True michael@0: michael@0: def add_mozilla_host_fingerprints(self): michael@0: """Add host fingerprints so SSL connections don't warn.""" michael@0: if 'hostfingerprints' not in self._c: michael@0: self._c['hostfingerprints'] = {} michael@0: michael@0: for k, v in HOST_FINGERPRINTS.items(): michael@0: self._c['hostfingerprints'][k] = v michael@0: michael@0: def set_username(self, name, email): michael@0: """Set the username to use for commits. michael@0: michael@0: The username consists of a name (typically ) and michael@0: a well-formed e-mail address. michael@0: """ michael@0: if 'ui' not in self._c: michael@0: self._c['ui'] = {} michael@0: michael@0: username = '%s <%s>' % (name, email) michael@0: michael@0: self._c['ui']['username'] = username.strip() michael@0: michael@0: def activate_extension(self, name, path=None): michael@0: """Activate an extension. michael@0: michael@0: An extension is defined by its name (in the config) and a filesystem michael@0: path). For built-in extensions, an empty path is specified. michael@0: """ michael@0: if not path: michael@0: path = '' michael@0: michael@0: if 'extensions' not in self._c: michael@0: self._c['extensions'] = {} michael@0: michael@0: self._c['extensions'][name] = path michael@0: michael@0: def have_recommended_diff_settings(self): michael@0: if 'diff' not in self._c: michael@0: return False michael@0: michael@0: old = dict(self._c['diff']) michael@0: try: michael@0: self.ensure_recommended_diff_settings() michael@0: finally: michael@0: self._c['diff'].update(old) michael@0: michael@0: return self._c['diff'] == old michael@0: michael@0: def ensure_recommended_diff_settings(self): michael@0: if 'diff' not in self._c: michael@0: self._c['diff'] = {} michael@0: michael@0: d = self._c['diff'] michael@0: d['git'] = 1 michael@0: d['showfunc'] = 1 michael@0: d['unified'] = 8 michael@0: michael@0: def have_mqext_autocommit_mq(self): michael@0: if 'mqext' not in self._c: michael@0: return False michael@0: v = self._c['mqext'].get('mqcommit') michael@0: return v == 'auto' or v == 'yes' michael@0: michael@0: def ensure_mqext_autocommit_mq(self): michael@0: if self.have_mqext_autocommit_mq(): michael@0: return michael@0: if 'mqext' not in self._c: michael@0: self._c['mqext'] = {} michael@0: self._c['mqext']['mqcommit'] = 'auto' michael@0: michael@0: def have_qnew_currentuser_default(self): michael@0: if 'defaults' not in self._c: michael@0: return False michael@0: d = self._c['defaults'] michael@0: if 'qnew' not in d: michael@0: return False michael@0: argv = d['qnew'].split(' ') michael@0: for arg in argv: michael@0: if arg == '--currentuser' or re.match("-[^-]*U.*", arg): michael@0: return True michael@0: return False michael@0: michael@0: def ensure_qnew_currentuser_default(self): michael@0: if self.have_qnew_currentuser_default(): michael@0: return michael@0: if 'defaults' not in self._c: michael@0: self._c['defaults'] = {} michael@0: michael@0: d = self._c['defaults'] michael@0: if 'qnew' not in d: michael@0: d['qnew'] = '-U' michael@0: else: michael@0: d['qnew'] = '-U ' + d['qnew']