|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this, |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 from __future__ import unicode_literals |
|
6 |
|
7 from configobj import ConfigObj |
|
8 import re |
|
9 import os |
|
10 |
|
11 |
|
12 HOST_FINGERPRINTS = { |
|
13 'bitbucket.org': '45:ad:ae:1a:cf:0e:73:47:06:07:e0:88:f5:cc:10:e5:fa:1c:f7:99', |
|
14 'bugzilla.mozilla.org': '47:13:a2:14:0c:46:45:53:12:0d:e5:36:16:a5:60:26:3e:da:3a:60', |
|
15 'hg.mozilla.org': 'af:27:b9:34:47:4e:e5:98:01:f6:83:2b:51:c9:aa:d8:df:fb:1a:27', |
|
16 } |
|
17 |
|
18 |
|
19 class MercurialConfig(object): |
|
20 """Interface for manipulating a Mercurial config file.""" |
|
21 |
|
22 def __init__(self, infiles=None): |
|
23 """Create a new instance, optionally from an existing hgrc file.""" |
|
24 |
|
25 if infiles: |
|
26 # If multiple files were specified, figure out which file we're using: |
|
27 if len(infiles) > 1: |
|
28 picky_infiles = filter(os.path.isfile, infiles) |
|
29 if picky_infiles: |
|
30 picky_infiles = [(os.path.getsize(path), path) for path in picky_infiles] |
|
31 infiles = [max(picky_infiles)[1]] |
|
32 |
|
33 infile = infiles[0] |
|
34 self.config_path = infile |
|
35 else: |
|
36 infile = None |
|
37 |
|
38 # write_empty_values is necessary to prevent built-in extensions (which |
|
39 # have no value) from being dropped on write. |
|
40 # list_values aren't needed by Mercurial and disabling them prevents |
|
41 # quotes from being added. |
|
42 self._c = ConfigObj(infile=infile, encoding='utf-8', |
|
43 write_empty_values=True, list_values=False) |
|
44 |
|
45 @property |
|
46 def config(self): |
|
47 return self._c |
|
48 |
|
49 @property |
|
50 def extensions(self): |
|
51 """Returns the set of currently enabled extensions (by name).""" |
|
52 return set(self._c.get('extensions', {}).keys()) |
|
53 |
|
54 def write(self, fh): |
|
55 return self._c.write(fh) |
|
56 |
|
57 def have_valid_username(self): |
|
58 if 'ui' not in self._c: |
|
59 return False |
|
60 |
|
61 if 'username' not in self._c['ui']: |
|
62 return False |
|
63 |
|
64 # TODO perform actual validation here. |
|
65 |
|
66 return True |
|
67 |
|
68 def add_mozilla_host_fingerprints(self): |
|
69 """Add host fingerprints so SSL connections don't warn.""" |
|
70 if 'hostfingerprints' not in self._c: |
|
71 self._c['hostfingerprints'] = {} |
|
72 |
|
73 for k, v in HOST_FINGERPRINTS.items(): |
|
74 self._c['hostfingerprints'][k] = v |
|
75 |
|
76 def set_username(self, name, email): |
|
77 """Set the username to use for commits. |
|
78 |
|
79 The username consists of a name (typically <firstname> <lastname>) and |
|
80 a well-formed e-mail address. |
|
81 """ |
|
82 if 'ui' not in self._c: |
|
83 self._c['ui'] = {} |
|
84 |
|
85 username = '%s <%s>' % (name, email) |
|
86 |
|
87 self._c['ui']['username'] = username.strip() |
|
88 |
|
89 def activate_extension(self, name, path=None): |
|
90 """Activate an extension. |
|
91 |
|
92 An extension is defined by its name (in the config) and a filesystem |
|
93 path). For built-in extensions, an empty path is specified. |
|
94 """ |
|
95 if not path: |
|
96 path = '' |
|
97 |
|
98 if 'extensions' not in self._c: |
|
99 self._c['extensions'] = {} |
|
100 |
|
101 self._c['extensions'][name] = path |
|
102 |
|
103 def have_recommended_diff_settings(self): |
|
104 if 'diff' not in self._c: |
|
105 return False |
|
106 |
|
107 old = dict(self._c['diff']) |
|
108 try: |
|
109 self.ensure_recommended_diff_settings() |
|
110 finally: |
|
111 self._c['diff'].update(old) |
|
112 |
|
113 return self._c['diff'] == old |
|
114 |
|
115 def ensure_recommended_diff_settings(self): |
|
116 if 'diff' not in self._c: |
|
117 self._c['diff'] = {} |
|
118 |
|
119 d = self._c['diff'] |
|
120 d['git'] = 1 |
|
121 d['showfunc'] = 1 |
|
122 d['unified'] = 8 |
|
123 |
|
124 def have_mqext_autocommit_mq(self): |
|
125 if 'mqext' not in self._c: |
|
126 return False |
|
127 v = self._c['mqext'].get('mqcommit') |
|
128 return v == 'auto' or v == 'yes' |
|
129 |
|
130 def ensure_mqext_autocommit_mq(self): |
|
131 if self.have_mqext_autocommit_mq(): |
|
132 return |
|
133 if 'mqext' not in self._c: |
|
134 self._c['mqext'] = {} |
|
135 self._c['mqext']['mqcommit'] = 'auto' |
|
136 |
|
137 def have_qnew_currentuser_default(self): |
|
138 if 'defaults' not in self._c: |
|
139 return False |
|
140 d = self._c['defaults'] |
|
141 if 'qnew' not in d: |
|
142 return False |
|
143 argv = d['qnew'].split(' ') |
|
144 for arg in argv: |
|
145 if arg == '--currentuser' or re.match("-[^-]*U.*", arg): |
|
146 return True |
|
147 return False |
|
148 |
|
149 def ensure_qnew_currentuser_default(self): |
|
150 if self.have_qnew_currentuser_default(): |
|
151 return |
|
152 if 'defaults' not in self._c: |
|
153 self._c['defaults'] = {} |
|
154 |
|
155 d = self._c['defaults'] |
|
156 if 'qnew' not in d: |
|
157 d['qnew'] = '-U' |
|
158 else: |
|
159 d['qnew'] = '-U ' + d['qnew'] |