##// END OF EJS Templates
ui: make readsections() abort when configuration cannot be read.
Patrick Mezard -
r4517:5371a213 default
parent child Browse files
Show More
@@ -1,450 +1,458
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, re, socket, sys, tempfile
9 import errno, getpass, os, re, socket, sys, tempfile
10 import ConfigParser, traceback, util
10 import ConfigParser, traceback, util
11
11
12 def dupconfig(orig):
12 def dupconfig(orig):
13 new = util.configparser(orig.defaults())
13 new = util.configparser(orig.defaults())
14 updateconfig(orig, new)
14 updateconfig(orig, new)
15 return new
15 return new
16
16
17 def updateconfig(source, dest, sections=None):
17 def updateconfig(source, dest, sections=None):
18 if not sections:
18 if not sections:
19 sections = source.sections()
19 sections = source.sections()
20 for section in sections:
20 for section in sections:
21 if not dest.has_section(section):
21 if not dest.has_section(section):
22 dest.add_section(section)
22 dest.add_section(section)
23 for name, value in source.items(section, raw=True):
23 for name, value in source.items(section, raw=True):
24 dest.set(section, name, value)
24 dest.set(section, name, value)
25
25
26 class ui(object):
26 class ui(object):
27 def __init__(self, verbose=False, debug=False, quiet=False,
27 def __init__(self, verbose=False, debug=False, quiet=False,
28 interactive=True, traceback=False, report_untrusted=True,
28 interactive=True, traceback=False, report_untrusted=True,
29 parentui=None):
29 parentui=None):
30 self.overlay = None
30 self.overlay = None
31 self.buffers = []
31 self.buffers = []
32 if parentui is None:
32 if parentui is None:
33 # this is the parent of all ui children
33 # this is the parent of all ui children
34 self.parentui = None
34 self.parentui = None
35 self.readhooks = []
35 self.readhooks = []
36 self.quiet = quiet
36 self.quiet = quiet
37 self.verbose = verbose
37 self.verbose = verbose
38 self.debugflag = debug
38 self.debugflag = debug
39 self.interactive = interactive
39 self.interactive = interactive
40 self.traceback = traceback
40 self.traceback = traceback
41 self.report_untrusted = report_untrusted
41 self.report_untrusted = report_untrusted
42 self.trusted_users = {}
42 self.trusted_users = {}
43 self.trusted_groups = {}
43 self.trusted_groups = {}
44 # if ucdata is not None, its keys must be a superset of cdata's
44 # if ucdata is not None, its keys must be a superset of cdata's
45 self.cdata = util.configparser()
45 self.cdata = util.configparser()
46 self.ucdata = None
46 self.ucdata = None
47 # we always trust global config files
47 # we always trust global config files
48 self.check_trusted = False
48 self.check_trusted = False
49 self.readconfig(util.rcpath())
49 self.readconfig(util.rcpath())
50 self.check_trusted = True
50 self.check_trusted = True
51 self.updateopts(verbose, debug, quiet, interactive)
51 self.updateopts(verbose, debug, quiet, interactive)
52 else:
52 else:
53 # parentui may point to an ui object which is already a child
53 # parentui may point to an ui object which is already a child
54 self.parentui = parentui.parentui or parentui
54 self.parentui = parentui.parentui or parentui
55 self.readhooks = self.parentui.readhooks[:]
55 self.readhooks = self.parentui.readhooks[:]
56 self.trusted_users = parentui.trusted_users.copy()
56 self.trusted_users = parentui.trusted_users.copy()
57 self.trusted_groups = parentui.trusted_groups.copy()
57 self.trusted_groups = parentui.trusted_groups.copy()
58 self.cdata = dupconfig(self.parentui.cdata)
58 self.cdata = dupconfig(self.parentui.cdata)
59 if self.parentui.ucdata:
59 if self.parentui.ucdata:
60 self.ucdata = dupconfig(self.parentui.ucdata)
60 self.ucdata = dupconfig(self.parentui.ucdata)
61 if self.parentui.overlay:
61 if self.parentui.overlay:
62 self.overlay = dupconfig(self.parentui.overlay)
62 self.overlay = dupconfig(self.parentui.overlay)
63
63
64 def __getattr__(self, key):
64 def __getattr__(self, key):
65 return getattr(self.parentui, key)
65 return getattr(self.parentui, key)
66
66
67 def updateopts(self, verbose=False, debug=False, quiet=False,
67 def updateopts(self, verbose=False, debug=False, quiet=False,
68 interactive=True, traceback=False, config=[]):
68 interactive=True, traceback=False, config=[]):
69 for section, name, value in config:
69 for section, name, value in config:
70 self.setconfig(section, name, value)
70 self.setconfig(section, name, value)
71
71
72 if quiet or verbose or debug:
72 if quiet or verbose or debug:
73 self.setconfig('ui', 'quiet', str(bool(quiet)))
73 self.setconfig('ui', 'quiet', str(bool(quiet)))
74 self.setconfig('ui', 'verbose', str(bool(verbose)))
74 self.setconfig('ui', 'verbose', str(bool(verbose)))
75 self.setconfig('ui', 'debug', str(bool(debug)))
75 self.setconfig('ui', 'debug', str(bool(debug)))
76
76
77 self.verbosity_constraints()
77 self.verbosity_constraints()
78
78
79 if not interactive:
79 if not interactive:
80 self.setconfig('ui', 'interactive', 'False')
80 self.setconfig('ui', 'interactive', 'False')
81 self.interactive = False
81 self.interactive = False
82
82
83 self.traceback = self.traceback or traceback
83 self.traceback = self.traceback or traceback
84
84
85 def verbosity_constraints(self):
85 def verbosity_constraints(self):
86 self.quiet = self.configbool('ui', 'quiet')
86 self.quiet = self.configbool('ui', 'quiet')
87 self.verbose = self.configbool('ui', 'verbose')
87 self.verbose = self.configbool('ui', 'verbose')
88 self.debugflag = self.configbool('ui', 'debug')
88 self.debugflag = self.configbool('ui', 'debug')
89
89
90 if self.debugflag:
90 if self.debugflag:
91 self.verbose = True
91 self.verbose = True
92 self.quiet = False
92 self.quiet = False
93 elif self.verbose and self.quiet:
93 elif self.verbose and self.quiet:
94 self.quiet = self.verbose = False
94 self.quiet = self.verbose = False
95
95
96 def _is_trusted(self, fp, f, warn=True):
96 def _is_trusted(self, fp, f, warn=True):
97 if not self.check_trusted:
97 if not self.check_trusted:
98 return True
98 return True
99 st = util.fstat(fp)
99 st = util.fstat(fp)
100 if util.isowner(fp, st):
100 if util.isowner(fp, st):
101 return True
101 return True
102 tusers = self.trusted_users
102 tusers = self.trusted_users
103 tgroups = self.trusted_groups
103 tgroups = self.trusted_groups
104 if not tusers:
104 if not tusers:
105 user = util.username()
105 user = util.username()
106 if user is not None:
106 if user is not None:
107 self.trusted_users[user] = 1
107 self.trusted_users[user] = 1
108 self.fixconfig(section='trusted')
108 self.fixconfig(section='trusted')
109 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
109 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
110 user = util.username(st.st_uid)
110 user = util.username(st.st_uid)
111 group = util.groupname(st.st_gid)
111 group = util.groupname(st.st_gid)
112 if user not in tusers and group not in tgroups:
112 if user not in tusers and group not in tgroups:
113 if warn and self.report_untrusted:
113 if warn and self.report_untrusted:
114 self.warn(_('Not trusting file %s from untrusted '
114 self.warn(_('Not trusting file %s from untrusted '
115 'user %s, group %s\n') % (f, user, group))
115 'user %s, group %s\n') % (f, user, group))
116 return False
116 return False
117 return True
117 return True
118
118
119 def readconfig(self, fn, root=None):
119 def readconfig(self, fn, root=None):
120 if isinstance(fn, basestring):
120 if isinstance(fn, basestring):
121 fn = [fn]
121 fn = [fn]
122 for f in fn:
122 for f in fn:
123 try:
123 try:
124 fp = open(f)
124 fp = open(f)
125 except IOError:
125 except IOError:
126 continue
126 continue
127 cdata = self.cdata
127 cdata = self.cdata
128 trusted = self._is_trusted(fp, f)
128 trusted = self._is_trusted(fp, f)
129 if not trusted:
129 if not trusted:
130 if self.ucdata is None:
130 if self.ucdata is None:
131 self.ucdata = dupconfig(self.cdata)
131 self.ucdata = dupconfig(self.cdata)
132 cdata = self.ucdata
132 cdata = self.ucdata
133 elif self.ucdata is not None:
133 elif self.ucdata is not None:
134 # use a separate configparser, so that we don't accidentally
134 # use a separate configparser, so that we don't accidentally
135 # override ucdata settings later on.
135 # override ucdata settings later on.
136 cdata = util.configparser()
136 cdata = util.configparser()
137
137
138 try:
138 try:
139 cdata.readfp(fp, f)
139 cdata.readfp(fp, f)
140 except ConfigParser.ParsingError, inst:
140 except ConfigParser.ParsingError, inst:
141 msg = _("Failed to parse %s\n%s") % (f, inst)
141 msg = _("Failed to parse %s\n%s") % (f, inst)
142 if trusted:
142 if trusted:
143 raise util.Abort(msg)
143 raise util.Abort(msg)
144 self.warn(_("Ignored: %s\n") % msg)
144 self.warn(_("Ignored: %s\n") % msg)
145
145
146 if trusted:
146 if trusted:
147 if cdata != self.cdata:
147 if cdata != self.cdata:
148 updateconfig(cdata, self.cdata)
148 updateconfig(cdata, self.cdata)
149 if self.ucdata is not None:
149 if self.ucdata is not None:
150 updateconfig(cdata, self.ucdata)
150 updateconfig(cdata, self.ucdata)
151 # override data from config files with data set with ui.setconfig
151 # override data from config files with data set with ui.setconfig
152 if self.overlay:
152 if self.overlay:
153 updateconfig(self.overlay, self.cdata)
153 updateconfig(self.overlay, self.cdata)
154 if root is None:
154 if root is None:
155 root = os.path.expanduser('~')
155 root = os.path.expanduser('~')
156 self.fixconfig(root=root)
156 self.fixconfig(root=root)
157 for hook in self.readhooks:
157 for hook in self.readhooks:
158 hook(self)
158 hook(self)
159
159
160 def addreadhook(self, hook):
160 def addreadhook(self, hook):
161 self.readhooks.append(hook)
161 self.readhooks.append(hook)
162
162
163 def readsections(self, filename, *sections):
163 def readsections(self, filename, *sections):
164 """Read filename and add only the specified sections to the config data
164 """Read filename and add only the specified sections to the config data
165
165
166 The settings are added to the trusted config data.
166 The settings are added to the trusted config data.
167 """
167 """
168 if not sections:
168 if not sections:
169 return
169 return
170
170
171 cdata = util.configparser()
171 cdata = util.configparser()
172 try:
172 try:
173 cdata.read(filename)
173 try:
174 fp = open(filename)
175 except IOError, inst:
176 raise util.Abort(_("unable to open %s: %s") % (filename,
177 getattr(inst, "strerror", inst)))
178 try:
179 cdata.readfp(fp, filename)
180 finally:
181 fp.close()
174 except ConfigParser.ParsingError, inst:
182 except ConfigParser.ParsingError, inst:
175 raise util.Abort(_("failed to parse %s\n%s") % (filename,
183 raise util.Abort(_("failed to parse %s\n%s") % (filename,
176 inst))
184 inst))
177
185
178 for section in sections:
186 for section in sections:
179 if not cdata.has_section(section):
187 if not cdata.has_section(section):
180 cdata.add_section(section)
188 cdata.add_section(section)
181
189
182 updateconfig(cdata, self.cdata, sections)
190 updateconfig(cdata, self.cdata, sections)
183 if self.ucdata:
191 if self.ucdata:
184 updateconfig(cdata, self.ucdata, sections)
192 updateconfig(cdata, self.ucdata, sections)
185
193
186 def fixconfig(self, section=None, name=None, value=None, root=None):
194 def fixconfig(self, section=None, name=None, value=None, root=None):
187 # translate paths relative to root (or home) into absolute paths
195 # translate paths relative to root (or home) into absolute paths
188 if section is None or section == 'paths':
196 if section is None or section == 'paths':
189 if root is None:
197 if root is None:
190 root = os.getcwd()
198 root = os.getcwd()
191 items = section and [(name, value)] or []
199 items = section and [(name, value)] or []
192 for cdata in self.cdata, self.ucdata, self.overlay:
200 for cdata in self.cdata, self.ucdata, self.overlay:
193 if not cdata: continue
201 if not cdata: continue
194 if not items and cdata.has_section('paths'):
202 if not items and cdata.has_section('paths'):
195 pathsitems = cdata.items('paths')
203 pathsitems = cdata.items('paths')
196 else:
204 else:
197 pathsitems = items
205 pathsitems = items
198 for n, path in pathsitems:
206 for n, path in pathsitems:
199 if path and "://" not in path and not os.path.isabs(path):
207 if path and "://" not in path and not os.path.isabs(path):
200 cdata.set("paths", n, os.path.join(root, path))
208 cdata.set("paths", n, os.path.join(root, path))
201
209
202 # update quiet/verbose/debug and interactive status
210 # update quiet/verbose/debug and interactive status
203 if section is None or section == 'ui':
211 if section is None or section == 'ui':
204 if name is None or name in ('quiet', 'verbose', 'debug'):
212 if name is None or name in ('quiet', 'verbose', 'debug'):
205 self.verbosity_constraints()
213 self.verbosity_constraints()
206
214
207 if name is None or name == 'interactive':
215 if name is None or name == 'interactive':
208 self.interactive = self.configbool("ui", "interactive", True)
216 self.interactive = self.configbool("ui", "interactive", True)
209
217
210 # update trust information
218 # update trust information
211 if (section is None or section == 'trusted') and self.trusted_users:
219 if (section is None or section == 'trusted') and self.trusted_users:
212 for user in self.configlist('trusted', 'users'):
220 for user in self.configlist('trusted', 'users'):
213 self.trusted_users[user] = 1
221 self.trusted_users[user] = 1
214 for group in self.configlist('trusted', 'groups'):
222 for group in self.configlist('trusted', 'groups'):
215 self.trusted_groups[group] = 1
223 self.trusted_groups[group] = 1
216
224
217 def setconfig(self, section, name, value):
225 def setconfig(self, section, name, value):
218 if not self.overlay:
226 if not self.overlay:
219 self.overlay = util.configparser()
227 self.overlay = util.configparser()
220 for cdata in (self.overlay, self.cdata, self.ucdata):
228 for cdata in (self.overlay, self.cdata, self.ucdata):
221 if not cdata: continue
229 if not cdata: continue
222 if not cdata.has_section(section):
230 if not cdata.has_section(section):
223 cdata.add_section(section)
231 cdata.add_section(section)
224 cdata.set(section, name, value)
232 cdata.set(section, name, value)
225 self.fixconfig(section, name, value)
233 self.fixconfig(section, name, value)
226
234
227 def _get_cdata(self, untrusted):
235 def _get_cdata(self, untrusted):
228 if untrusted and self.ucdata:
236 if untrusted and self.ucdata:
229 return self.ucdata
237 return self.ucdata
230 return self.cdata
238 return self.cdata
231
239
232 def _config(self, section, name, default, funcname, untrusted, abort):
240 def _config(self, section, name, default, funcname, untrusted, abort):
233 cdata = self._get_cdata(untrusted)
241 cdata = self._get_cdata(untrusted)
234 if cdata.has_option(section, name):
242 if cdata.has_option(section, name):
235 try:
243 try:
236 func = getattr(cdata, funcname)
244 func = getattr(cdata, funcname)
237 return func(section, name)
245 return func(section, name)
238 except ConfigParser.InterpolationError, inst:
246 except ConfigParser.InterpolationError, inst:
239 msg = _("Error in configuration section [%s] "
247 msg = _("Error in configuration section [%s] "
240 "parameter '%s':\n%s") % (section, name, inst)
248 "parameter '%s':\n%s") % (section, name, inst)
241 if abort:
249 if abort:
242 raise util.Abort(msg)
250 raise util.Abort(msg)
243 self.warn(_("Ignored: %s\n") % msg)
251 self.warn(_("Ignored: %s\n") % msg)
244 return default
252 return default
245
253
246 def _configcommon(self, section, name, default, funcname, untrusted):
254 def _configcommon(self, section, name, default, funcname, untrusted):
247 value = self._config(section, name, default, funcname,
255 value = self._config(section, name, default, funcname,
248 untrusted, abort=True)
256 untrusted, abort=True)
249 if self.debugflag and not untrusted and self.ucdata:
257 if self.debugflag and not untrusted and self.ucdata:
250 uvalue = self._config(section, name, None, funcname,
258 uvalue = self._config(section, name, None, funcname,
251 untrusted=True, abort=False)
259 untrusted=True, abort=False)
252 if uvalue is not None and uvalue != value:
260 if uvalue is not None and uvalue != value:
253 self.warn(_("Ignoring untrusted configuration option "
261 self.warn(_("Ignoring untrusted configuration option "
254 "%s.%s = %s\n") % (section, name, uvalue))
262 "%s.%s = %s\n") % (section, name, uvalue))
255 return value
263 return value
256
264
257 def config(self, section, name, default=None, untrusted=False):
265 def config(self, section, name, default=None, untrusted=False):
258 return self._configcommon(section, name, default, 'get', untrusted)
266 return self._configcommon(section, name, default, 'get', untrusted)
259
267
260 def configbool(self, section, name, default=False, untrusted=False):
268 def configbool(self, section, name, default=False, untrusted=False):
261 return self._configcommon(section, name, default, 'getboolean',
269 return self._configcommon(section, name, default, 'getboolean',
262 untrusted)
270 untrusted)
263
271
264 def configlist(self, section, name, default=None, untrusted=False):
272 def configlist(self, section, name, default=None, untrusted=False):
265 """Return a list of comma/space separated strings"""
273 """Return a list of comma/space separated strings"""
266 result = self.config(section, name, untrusted=untrusted)
274 result = self.config(section, name, untrusted=untrusted)
267 if result is None:
275 if result is None:
268 result = default or []
276 result = default or []
269 if isinstance(result, basestring):
277 if isinstance(result, basestring):
270 result = result.replace(",", " ").split()
278 result = result.replace(",", " ").split()
271 return result
279 return result
272
280
273 def has_section(self, section, untrusted=False):
281 def has_section(self, section, untrusted=False):
274 '''tell whether section exists in config.'''
282 '''tell whether section exists in config.'''
275 cdata = self._get_cdata(untrusted)
283 cdata = self._get_cdata(untrusted)
276 return cdata.has_section(section)
284 return cdata.has_section(section)
277
285
278 def _configitems(self, section, untrusted, abort):
286 def _configitems(self, section, untrusted, abort):
279 items = {}
287 items = {}
280 cdata = self._get_cdata(untrusted)
288 cdata = self._get_cdata(untrusted)
281 if cdata.has_section(section):
289 if cdata.has_section(section):
282 try:
290 try:
283 items.update(dict(cdata.items(section)))
291 items.update(dict(cdata.items(section)))
284 except ConfigParser.InterpolationError, inst:
292 except ConfigParser.InterpolationError, inst:
285 msg = _("Error in configuration section [%s]:\n"
293 msg = _("Error in configuration section [%s]:\n"
286 "%s") % (section, inst)
294 "%s") % (section, inst)
287 if abort:
295 if abort:
288 raise util.Abort(msg)
296 raise util.Abort(msg)
289 self.warn(_("Ignored: %s\n") % msg)
297 self.warn(_("Ignored: %s\n") % msg)
290 return items
298 return items
291
299
292 def configitems(self, section, untrusted=False):
300 def configitems(self, section, untrusted=False):
293 items = self._configitems(section, untrusted=untrusted, abort=True)
301 items = self._configitems(section, untrusted=untrusted, abort=True)
294 if self.debugflag and not untrusted and self.ucdata:
302 if self.debugflag and not untrusted and self.ucdata:
295 uitems = self._configitems(section, untrusted=True, abort=False)
303 uitems = self._configitems(section, untrusted=True, abort=False)
296 keys = uitems.keys()
304 keys = uitems.keys()
297 keys.sort()
305 keys.sort()
298 for k in keys:
306 for k in keys:
299 if uitems[k] != items.get(k):
307 if uitems[k] != items.get(k):
300 self.warn(_("Ignoring untrusted configuration option "
308 self.warn(_("Ignoring untrusted configuration option "
301 "%s.%s = %s\n") % (section, k, uitems[k]))
309 "%s.%s = %s\n") % (section, k, uitems[k]))
302 x = items.items()
310 x = items.items()
303 x.sort()
311 x.sort()
304 return x
312 return x
305
313
306 def walkconfig(self, untrusted=False):
314 def walkconfig(self, untrusted=False):
307 cdata = self._get_cdata(untrusted)
315 cdata = self._get_cdata(untrusted)
308 sections = cdata.sections()
316 sections = cdata.sections()
309 sections.sort()
317 sections.sort()
310 for section in sections:
318 for section in sections:
311 for name, value in self.configitems(section, untrusted):
319 for name, value in self.configitems(section, untrusted):
312 yield section, name, str(value).replace('\n', '\\n')
320 yield section, name, str(value).replace('\n', '\\n')
313
321
314 def extensions(self):
322 def extensions(self):
315 result = self.configitems("extensions")
323 result = self.configitems("extensions")
316 for i, (key, value) in enumerate(result):
324 for i, (key, value) in enumerate(result):
317 if value:
325 if value:
318 result[i] = (key, os.path.expanduser(value))
326 result[i] = (key, os.path.expanduser(value))
319 return result
327 return result
320
328
321 def hgignorefiles(self):
329 def hgignorefiles(self):
322 result = []
330 result = []
323 for key, value in self.configitems("ui"):
331 for key, value in self.configitems("ui"):
324 if key == 'ignore' or key.startswith('ignore.'):
332 if key == 'ignore' or key.startswith('ignore.'):
325 result.append(os.path.expanduser(value))
333 result.append(os.path.expanduser(value))
326 return result
334 return result
327
335
328 def username(self):
336 def username(self):
329 """Return default username to be used in commits.
337 """Return default username to be used in commits.
330
338
331 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
339 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
332 and stop searching if one of these is set.
340 and stop searching if one of these is set.
333 If not found, use ($LOGNAME or $USER or $LNAME or
341 If not found, use ($LOGNAME or $USER or $LNAME or
334 $USERNAME) +"@full.hostname".
342 $USERNAME) +"@full.hostname".
335 """
343 """
336 user = os.environ.get("HGUSER")
344 user = os.environ.get("HGUSER")
337 if user is None:
345 if user is None:
338 user = self.config("ui", "username")
346 user = self.config("ui", "username")
339 if user is None:
347 if user is None:
340 user = os.environ.get("EMAIL")
348 user = os.environ.get("EMAIL")
341 if user is None:
349 if user is None:
342 try:
350 try:
343 user = '%s@%s' % (util.getuser(), socket.getfqdn())
351 user = '%s@%s' % (util.getuser(), socket.getfqdn())
344 self.warn(_("No username found, using '%s' instead\n") % user)
352 self.warn(_("No username found, using '%s' instead\n") % user)
345 except KeyError:
353 except KeyError:
346 pass
354 pass
347 if not user:
355 if not user:
348 raise util.Abort(_("Please specify a username."))
356 raise util.Abort(_("Please specify a username."))
349 return user
357 return user
350
358
351 def shortuser(self, user):
359 def shortuser(self, user):
352 """Return a short representation of a user name or email address."""
360 """Return a short representation of a user name or email address."""
353 if not self.verbose: user = util.shortuser(user)
361 if not self.verbose: user = util.shortuser(user)
354 return user
362 return user
355
363
356 def expandpath(self, loc, default=None):
364 def expandpath(self, loc, default=None):
357 """Return repository location relative to cwd or from [paths]"""
365 """Return repository location relative to cwd or from [paths]"""
358 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
366 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
359 return loc
367 return loc
360
368
361 path = self.config("paths", loc)
369 path = self.config("paths", loc)
362 if not path and default is not None:
370 if not path and default is not None:
363 path = self.config("paths", default)
371 path = self.config("paths", default)
364 return path or loc
372 return path or loc
365
373
366 def pushbuffer(self):
374 def pushbuffer(self):
367 self.buffers.append([])
375 self.buffers.append([])
368
376
369 def popbuffer(self):
377 def popbuffer(self):
370 return "".join(self.buffers.pop())
378 return "".join(self.buffers.pop())
371
379
372 def write(self, *args):
380 def write(self, *args):
373 if self.buffers:
381 if self.buffers:
374 self.buffers[-1].extend([str(a) for a in args])
382 self.buffers[-1].extend([str(a) for a in args])
375 else:
383 else:
376 for a in args:
384 for a in args:
377 sys.stdout.write(str(a))
385 sys.stdout.write(str(a))
378
386
379 def write_err(self, *args):
387 def write_err(self, *args):
380 try:
388 try:
381 if not sys.stdout.closed: sys.stdout.flush()
389 if not sys.stdout.closed: sys.stdout.flush()
382 for a in args:
390 for a in args:
383 sys.stderr.write(str(a))
391 sys.stderr.write(str(a))
384 # stderr may be buffered under win32 when redirected to files,
392 # stderr may be buffered under win32 when redirected to files,
385 # including stdout.
393 # including stdout.
386 if not sys.stderr.closed: sys.stderr.flush()
394 if not sys.stderr.closed: sys.stderr.flush()
387 except IOError, inst:
395 except IOError, inst:
388 if inst.errno != errno.EPIPE:
396 if inst.errno != errno.EPIPE:
389 raise
397 raise
390
398
391 def flush(self):
399 def flush(self):
392 try: sys.stdout.flush()
400 try: sys.stdout.flush()
393 except: pass
401 except: pass
394 try: sys.stderr.flush()
402 try: sys.stderr.flush()
395 except: pass
403 except: pass
396
404
397 def readline(self):
405 def readline(self):
398 return sys.stdin.readline()[:-1]
406 return sys.stdin.readline()[:-1]
399 def prompt(self, msg, pat=None, default="y"):
407 def prompt(self, msg, pat=None, default="y"):
400 if not self.interactive: return default
408 if not self.interactive: return default
401 while 1:
409 while 1:
402 self.write(msg, " ")
410 self.write(msg, " ")
403 r = self.readline()
411 r = self.readline()
404 if not pat or re.match(pat, r):
412 if not pat or re.match(pat, r):
405 return r
413 return r
406 else:
414 else:
407 self.write(_("unrecognized response\n"))
415 self.write(_("unrecognized response\n"))
408 def getpass(self, prompt=None, default=None):
416 def getpass(self, prompt=None, default=None):
409 if not self.interactive: return default
417 if not self.interactive: return default
410 return getpass.getpass(prompt or _('password: '))
418 return getpass.getpass(prompt or _('password: '))
411 def status(self, *msg):
419 def status(self, *msg):
412 if not self.quiet: self.write(*msg)
420 if not self.quiet: self.write(*msg)
413 def warn(self, *msg):
421 def warn(self, *msg):
414 self.write_err(*msg)
422 self.write_err(*msg)
415 def note(self, *msg):
423 def note(self, *msg):
416 if self.verbose: self.write(*msg)
424 if self.verbose: self.write(*msg)
417 def debug(self, *msg):
425 def debug(self, *msg):
418 if self.debugflag: self.write(*msg)
426 if self.debugflag: self.write(*msg)
419 def edit(self, text, user):
427 def edit(self, text, user):
420 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
428 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
421 text=True)
429 text=True)
422 try:
430 try:
423 f = os.fdopen(fd, "w")
431 f = os.fdopen(fd, "w")
424 f.write(text)
432 f.write(text)
425 f.close()
433 f.close()
426
434
427 editor = (os.environ.get("HGEDITOR") or
435 editor = (os.environ.get("HGEDITOR") or
428 self.config("ui", "editor") or
436 self.config("ui", "editor") or
429 os.environ.get("EDITOR", "vi"))
437 os.environ.get("EDITOR", "vi"))
430
438
431 util.system("%s \"%s\"" % (editor, name),
439 util.system("%s \"%s\"" % (editor, name),
432 environ={'HGUSER': user},
440 environ={'HGUSER': user},
433 onerr=util.Abort, errprefix=_("edit failed"))
441 onerr=util.Abort, errprefix=_("edit failed"))
434
442
435 f = open(name)
443 f = open(name)
436 t = f.read()
444 t = f.read()
437 f.close()
445 f.close()
438 t = re.sub("(?m)^HG:.*\n", "", t)
446 t = re.sub("(?m)^HG:.*\n", "", t)
439 finally:
447 finally:
440 os.unlink(name)
448 os.unlink(name)
441
449
442 return t
450 return t
443
451
444 def print_exc(self):
452 def print_exc(self):
445 '''print exception traceback if traceback printing enabled.
453 '''print exception traceback if traceback printing enabled.
446 only to call in exception handler. returns true if traceback
454 only to call in exception handler. returns true if traceback
447 printed.'''
455 printed.'''
448 if self.traceback:
456 if self.traceback:
449 traceback.print_exc()
457 traceback.print_exc()
450 return self.traceback
458 return self.traceback
@@ -1,584 +1,583
1 3:911600dab2ae
1 3:911600dab2ae
2 requesting all changes
2 requesting all changes
3 adding changesets
3 adding changesets
4 adding manifests
4 adding manifests
5 adding file changes
5 adding file changes
6 added 1 changesets with 3 changes to 3 files
6 added 1 changesets with 3 changes to 3 files
7 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
8
8
9 Extension disabled for lack of a hook
9 Extension disabled for lack of a hook
10 Pushing as user fred
10 Pushing as user fred
11 hgrc = """
11 hgrc = """
12 """
12 """
13 pushing to ../b
13 pushing to ../b
14 searching for changes
14 searching for changes
15 common changesets up to 6675d58eff77
15 common changesets up to 6675d58eff77
16 3 changesets found
16 3 changesets found
17 List of changesets:
17 List of changesets:
18 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
18 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
19 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
19 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
20 911600dab2ae7a9baff75958b84fe606851ce955
20 911600dab2ae7a9baff75958b84fe606851ce955
21 adding changesets
21 adding changesets
22 add changeset ef1ea85a6374
22 add changeset ef1ea85a6374
23 add changeset f9cafe1212c8
23 add changeset f9cafe1212c8
24 add changeset 911600dab2ae
24 add changeset 911600dab2ae
25 adding manifests
25 adding manifests
26 adding file changes
26 adding file changes
27 adding foo/Bar/file.txt revisions
27 adding foo/Bar/file.txt revisions
28 adding foo/file.txt revisions
28 adding foo/file.txt revisions
29 adding quux/file.py revisions
29 adding quux/file.py revisions
30 added 3 changesets with 3 changes to 3 files
30 added 3 changesets with 3 changes to 3 files
31 rolling back last transaction
31 rolling back last transaction
32 0:6675d58eff77
32 0:6675d58eff77
33
33
34 Extension disabled for lack of acl.sources
34 Extension disabled for lack of acl.sources
35 Pushing as user fred
35 Pushing as user fred
36 hgrc = """
36 hgrc = """
37 [hooks]
37 [hooks]
38 pretxnchangegroup.acl = python:hgext.acl.hook
38 pretxnchangegroup.acl = python:hgext.acl.hook
39 """
39 """
40 pushing to ../b
40 pushing to ../b
41 searching for changes
41 searching for changes
42 common changesets up to 6675d58eff77
42 common changesets up to 6675d58eff77
43 3 changesets found
43 3 changesets found
44 List of changesets:
44 List of changesets:
45 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
45 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
46 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
46 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
47 911600dab2ae7a9baff75958b84fe606851ce955
47 911600dab2ae7a9baff75958b84fe606851ce955
48 adding changesets
48 adding changesets
49 add changeset ef1ea85a6374
49 add changeset ef1ea85a6374
50 add changeset f9cafe1212c8
50 add changeset f9cafe1212c8
51 add changeset 911600dab2ae
51 add changeset 911600dab2ae
52 adding manifests
52 adding manifests
53 adding file changes
53 adding file changes
54 adding foo/Bar/file.txt revisions
54 adding foo/Bar/file.txt revisions
55 adding foo/file.txt revisions
55 adding foo/file.txt revisions
56 adding quux/file.py revisions
56 adding quux/file.py revisions
57 added 3 changesets with 3 changes to 3 files
57 added 3 changesets with 3 changes to 3 files
58 calling hook pretxnchangegroup.acl: hgext.acl.hook
58 calling hook pretxnchangegroup.acl: hgext.acl.hook
59 acl: acl.allow not enabled
59 acl: acl.allow not enabled
60 acl: acl.deny not enabled
60 acl: acl.deny not enabled
61 acl: changes have source "push" - skipping
61 acl: changes have source "push" - skipping
62 rolling back last transaction
62 rolling back last transaction
63 0:6675d58eff77
63 0:6675d58eff77
64
64
65 No [acl.allow]/[acl.deny]
65 No [acl.allow]/[acl.deny]
66 Pushing as user fred
66 Pushing as user fred
67 hgrc = """
67 hgrc = """
68 [hooks]
68 [hooks]
69 pretxnchangegroup.acl = python:hgext.acl.hook
69 pretxnchangegroup.acl = python:hgext.acl.hook
70 [acl]
70 [acl]
71 sources = push
71 sources = push
72 """
72 """
73 pushing to ../b
73 pushing to ../b
74 searching for changes
74 searching for changes
75 common changesets up to 6675d58eff77
75 common changesets up to 6675d58eff77
76 3 changesets found
76 3 changesets found
77 List of changesets:
77 List of changesets:
78 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
78 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
79 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
79 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
80 911600dab2ae7a9baff75958b84fe606851ce955
80 911600dab2ae7a9baff75958b84fe606851ce955
81 adding changesets
81 adding changesets
82 add changeset ef1ea85a6374
82 add changeset ef1ea85a6374
83 add changeset f9cafe1212c8
83 add changeset f9cafe1212c8
84 add changeset 911600dab2ae
84 add changeset 911600dab2ae
85 adding manifests
85 adding manifests
86 adding file changes
86 adding file changes
87 adding foo/Bar/file.txt revisions
87 adding foo/Bar/file.txt revisions
88 adding foo/file.txt revisions
88 adding foo/file.txt revisions
89 adding quux/file.py revisions
89 adding quux/file.py revisions
90 added 3 changesets with 3 changes to 3 files
90 added 3 changesets with 3 changes to 3 files
91 calling hook pretxnchangegroup.acl: hgext.acl.hook
91 calling hook pretxnchangegroup.acl: hgext.acl.hook
92 acl: acl.allow not enabled
92 acl: acl.allow not enabled
93 acl: acl.deny not enabled
93 acl: acl.deny not enabled
94 acl: allowing changeset ef1ea85a6374
94 acl: allowing changeset ef1ea85a6374
95 acl: allowing changeset f9cafe1212c8
95 acl: allowing changeset f9cafe1212c8
96 acl: allowing changeset 911600dab2ae
96 acl: allowing changeset 911600dab2ae
97 rolling back last transaction
97 rolling back last transaction
98 0:6675d58eff77
98 0:6675d58eff77
99
99
100 Empty [acl.allow]
100 Empty [acl.allow]
101 Pushing as user fred
101 Pushing as user fred
102 hgrc = """
102 hgrc = """
103 [hooks]
103 [hooks]
104 pretxnchangegroup.acl = python:hgext.acl.hook
104 pretxnchangegroup.acl = python:hgext.acl.hook
105 [acl]
105 [acl]
106 sources = push
106 sources = push
107 [acl.allow]
107 [acl.allow]
108 """
108 """
109 pushing to ../b
109 pushing to ../b
110 searching for changes
110 searching for changes
111 common changesets up to 6675d58eff77
111 common changesets up to 6675d58eff77
112 3 changesets found
112 3 changesets found
113 List of changesets:
113 List of changesets:
114 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
114 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
115 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
115 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
116 911600dab2ae7a9baff75958b84fe606851ce955
116 911600dab2ae7a9baff75958b84fe606851ce955
117 adding changesets
117 adding changesets
118 add changeset ef1ea85a6374
118 add changeset ef1ea85a6374
119 add changeset f9cafe1212c8
119 add changeset f9cafe1212c8
120 add changeset 911600dab2ae
120 add changeset 911600dab2ae
121 adding manifests
121 adding manifests
122 adding file changes
122 adding file changes
123 adding foo/Bar/file.txt revisions
123 adding foo/Bar/file.txt revisions
124 adding foo/file.txt revisions
124 adding foo/file.txt revisions
125 adding quux/file.py revisions
125 adding quux/file.py revisions
126 added 3 changesets with 3 changes to 3 files
126 added 3 changesets with 3 changes to 3 files
127 calling hook pretxnchangegroup.acl: hgext.acl.hook
127 calling hook pretxnchangegroup.acl: hgext.acl.hook
128 acl: acl.allow enabled, 0 entries for user fred
128 acl: acl.allow enabled, 0 entries for user fred
129 acl: acl.deny not enabled
129 acl: acl.deny not enabled
130 acl: user fred not allowed on foo/file.txt
130 acl: user fred not allowed on foo/file.txt
131 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
131 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
132 abort: acl: access denied for changeset ef1ea85a6374
132 abort: acl: access denied for changeset ef1ea85a6374
133 transaction abort!
133 transaction abort!
134 rollback completed
134 rollback completed
135 no rollback information available
135 no rollback information available
136 0:6675d58eff77
136 0:6675d58eff77
137
137
138 fred is allowed inside foo/
138 fred is allowed inside foo/
139 Pushing as user fred
139 Pushing as user fred
140 hgrc = """
140 hgrc = """
141 [hooks]
141 [hooks]
142 pretxnchangegroup.acl = python:hgext.acl.hook
142 pretxnchangegroup.acl = python:hgext.acl.hook
143 [acl]
143 [acl]
144 sources = push
144 sources = push
145 [acl.allow]
145 [acl.allow]
146 foo/** = fred
146 foo/** = fred
147 """
147 """
148 pushing to ../b
148 pushing to ../b
149 searching for changes
149 searching for changes
150 common changesets up to 6675d58eff77
150 common changesets up to 6675d58eff77
151 3 changesets found
151 3 changesets found
152 List of changesets:
152 List of changesets:
153 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
153 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
154 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
154 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
155 911600dab2ae7a9baff75958b84fe606851ce955
155 911600dab2ae7a9baff75958b84fe606851ce955
156 adding changesets
156 adding changesets
157 add changeset ef1ea85a6374
157 add changeset ef1ea85a6374
158 add changeset f9cafe1212c8
158 add changeset f9cafe1212c8
159 add changeset 911600dab2ae
159 add changeset 911600dab2ae
160 adding manifests
160 adding manifests
161 adding file changes
161 adding file changes
162 adding foo/Bar/file.txt revisions
162 adding foo/Bar/file.txt revisions
163 adding foo/file.txt revisions
163 adding foo/file.txt revisions
164 adding quux/file.py revisions
164 adding quux/file.py revisions
165 added 3 changesets with 3 changes to 3 files
165 added 3 changesets with 3 changes to 3 files
166 calling hook pretxnchangegroup.acl: hgext.acl.hook
166 calling hook pretxnchangegroup.acl: hgext.acl.hook
167 acl: acl.allow enabled, 1 entries for user fred
167 acl: acl.allow enabled, 1 entries for user fred
168 acl: acl.deny not enabled
168 acl: acl.deny not enabled
169 acl: allowing changeset ef1ea85a6374
169 acl: allowing changeset ef1ea85a6374
170 acl: allowing changeset f9cafe1212c8
170 acl: allowing changeset f9cafe1212c8
171 acl: user fred not allowed on quux/file.py
171 acl: user fred not allowed on quux/file.py
172 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
172 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
173 abort: acl: access denied for changeset 911600dab2ae
173 abort: acl: access denied for changeset 911600dab2ae
174 transaction abort!
174 transaction abort!
175 rollback completed
175 rollback completed
176 no rollback information available
176 no rollback information available
177 0:6675d58eff77
177 0:6675d58eff77
178
178
179 Empty [acl.deny]
179 Empty [acl.deny]
180 Pushing as user barney
180 Pushing as user barney
181 hgrc = """
181 hgrc = """
182 [hooks]
182 [hooks]
183 pretxnchangegroup.acl = python:hgext.acl.hook
183 pretxnchangegroup.acl = python:hgext.acl.hook
184 [acl]
184 [acl]
185 sources = push
185 sources = push
186 [acl.allow]
186 [acl.allow]
187 foo/** = fred
187 foo/** = fred
188 [acl.deny]
188 [acl.deny]
189 """
189 """
190 pushing to ../b
190 pushing to ../b
191 searching for changes
191 searching for changes
192 common changesets up to 6675d58eff77
192 common changesets up to 6675d58eff77
193 3 changesets found
193 3 changesets found
194 List of changesets:
194 List of changesets:
195 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
195 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
196 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
196 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
197 911600dab2ae7a9baff75958b84fe606851ce955
197 911600dab2ae7a9baff75958b84fe606851ce955
198 adding changesets
198 adding changesets
199 add changeset ef1ea85a6374
199 add changeset ef1ea85a6374
200 add changeset f9cafe1212c8
200 add changeset f9cafe1212c8
201 add changeset 911600dab2ae
201 add changeset 911600dab2ae
202 adding manifests
202 adding manifests
203 adding file changes
203 adding file changes
204 adding foo/Bar/file.txt revisions
204 adding foo/Bar/file.txt revisions
205 adding foo/file.txt revisions
205 adding foo/file.txt revisions
206 adding quux/file.py revisions
206 adding quux/file.py revisions
207 added 3 changesets with 3 changes to 3 files
207 added 3 changesets with 3 changes to 3 files
208 calling hook pretxnchangegroup.acl: hgext.acl.hook
208 calling hook pretxnchangegroup.acl: hgext.acl.hook
209 acl: acl.allow enabled, 0 entries for user barney
209 acl: acl.allow enabled, 0 entries for user barney
210 acl: acl.deny enabled, 0 entries for user barney
210 acl: acl.deny enabled, 0 entries for user barney
211 acl: user barney not allowed on foo/file.txt
211 acl: user barney not allowed on foo/file.txt
212 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
212 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
213 abort: acl: access denied for changeset ef1ea85a6374
213 abort: acl: access denied for changeset ef1ea85a6374
214 transaction abort!
214 transaction abort!
215 rollback completed
215 rollback completed
216 no rollback information available
216 no rollback information available
217 0:6675d58eff77
217 0:6675d58eff77
218
218
219 fred is allowed inside foo/, but not foo/bar/ (case matters)
219 fred is allowed inside foo/, but not foo/bar/ (case matters)
220 Pushing as user fred
220 Pushing as user fred
221 hgrc = """
221 hgrc = """
222 [hooks]
222 [hooks]
223 pretxnchangegroup.acl = python:hgext.acl.hook
223 pretxnchangegroup.acl = python:hgext.acl.hook
224 [acl]
224 [acl]
225 sources = push
225 sources = push
226 [acl.allow]
226 [acl.allow]
227 foo/** = fred
227 foo/** = fred
228 [acl.deny]
228 [acl.deny]
229 foo/bar/** = fred
229 foo/bar/** = fred
230 """
230 """
231 pushing to ../b
231 pushing to ../b
232 searching for changes
232 searching for changes
233 common changesets up to 6675d58eff77
233 common changesets up to 6675d58eff77
234 3 changesets found
234 3 changesets found
235 List of changesets:
235 List of changesets:
236 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
236 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
237 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
237 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
238 911600dab2ae7a9baff75958b84fe606851ce955
238 911600dab2ae7a9baff75958b84fe606851ce955
239 adding changesets
239 adding changesets
240 add changeset ef1ea85a6374
240 add changeset ef1ea85a6374
241 add changeset f9cafe1212c8
241 add changeset f9cafe1212c8
242 add changeset 911600dab2ae
242 add changeset 911600dab2ae
243 adding manifests
243 adding manifests
244 adding file changes
244 adding file changes
245 adding foo/Bar/file.txt revisions
245 adding foo/Bar/file.txt revisions
246 adding foo/file.txt revisions
246 adding foo/file.txt revisions
247 adding quux/file.py revisions
247 adding quux/file.py revisions
248 added 3 changesets with 3 changes to 3 files
248 added 3 changesets with 3 changes to 3 files
249 calling hook pretxnchangegroup.acl: hgext.acl.hook
249 calling hook pretxnchangegroup.acl: hgext.acl.hook
250 acl: acl.allow enabled, 1 entries for user fred
250 acl: acl.allow enabled, 1 entries for user fred
251 acl: acl.deny enabled, 1 entries for user fred
251 acl: acl.deny enabled, 1 entries for user fred
252 acl: allowing changeset ef1ea85a6374
252 acl: allowing changeset ef1ea85a6374
253 acl: allowing changeset f9cafe1212c8
253 acl: allowing changeset f9cafe1212c8
254 acl: user fred not allowed on quux/file.py
254 acl: user fred not allowed on quux/file.py
255 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
255 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
256 abort: acl: access denied for changeset 911600dab2ae
256 abort: acl: access denied for changeset 911600dab2ae
257 transaction abort!
257 transaction abort!
258 rollback completed
258 rollback completed
259 no rollback information available
259 no rollback information available
260 0:6675d58eff77
260 0:6675d58eff77
261
261
262 fred is allowed inside foo/, but not foo/Bar/
262 fred is allowed inside foo/, but not foo/Bar/
263 Pushing as user fred
263 Pushing as user fred
264 hgrc = """
264 hgrc = """
265 [hooks]
265 [hooks]
266 pretxnchangegroup.acl = python:hgext.acl.hook
266 pretxnchangegroup.acl = python:hgext.acl.hook
267 [acl]
267 [acl]
268 sources = push
268 sources = push
269 [acl.allow]
269 [acl.allow]
270 foo/** = fred
270 foo/** = fred
271 [acl.deny]
271 [acl.deny]
272 foo/bar/** = fred
272 foo/bar/** = fred
273 foo/Bar/** = fred
273 foo/Bar/** = fred
274 """
274 """
275 pushing to ../b
275 pushing to ../b
276 searching for changes
276 searching for changes
277 common changesets up to 6675d58eff77
277 common changesets up to 6675d58eff77
278 3 changesets found
278 3 changesets found
279 List of changesets:
279 List of changesets:
280 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
280 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
281 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
281 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
282 911600dab2ae7a9baff75958b84fe606851ce955
282 911600dab2ae7a9baff75958b84fe606851ce955
283 adding changesets
283 adding changesets
284 add changeset ef1ea85a6374
284 add changeset ef1ea85a6374
285 add changeset f9cafe1212c8
285 add changeset f9cafe1212c8
286 add changeset 911600dab2ae
286 add changeset 911600dab2ae
287 adding manifests
287 adding manifests
288 adding file changes
288 adding file changes
289 adding foo/Bar/file.txt revisions
289 adding foo/Bar/file.txt revisions
290 adding foo/file.txt revisions
290 adding foo/file.txt revisions
291 adding quux/file.py revisions
291 adding quux/file.py revisions
292 added 3 changesets with 3 changes to 3 files
292 added 3 changesets with 3 changes to 3 files
293 calling hook pretxnchangegroup.acl: hgext.acl.hook
293 calling hook pretxnchangegroup.acl: hgext.acl.hook
294 acl: acl.allow enabled, 1 entries for user fred
294 acl: acl.allow enabled, 1 entries for user fred
295 acl: acl.deny enabled, 2 entries for user fred
295 acl: acl.deny enabled, 2 entries for user fred
296 acl: allowing changeset ef1ea85a6374
296 acl: allowing changeset ef1ea85a6374
297 acl: user fred denied on foo/Bar/file.txt
297 acl: user fred denied on foo/Bar/file.txt
298 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
298 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
299 abort: acl: access denied for changeset f9cafe1212c8
299 abort: acl: access denied for changeset f9cafe1212c8
300 transaction abort!
300 transaction abort!
301 rollback completed
301 rollback completed
302 no rollback information available
302 no rollback information available
303 0:6675d58eff77
303 0:6675d58eff77
304
304
305 barney is not mentioned => not allowed anywhere
305 barney is not mentioned => not allowed anywhere
306 Pushing as user barney
306 Pushing as user barney
307 hgrc = """
307 hgrc = """
308 [hooks]
308 [hooks]
309 pretxnchangegroup.acl = python:hgext.acl.hook
309 pretxnchangegroup.acl = python:hgext.acl.hook
310 [acl]
310 [acl]
311 sources = push
311 sources = push
312 [acl.allow]
312 [acl.allow]
313 foo/** = fred
313 foo/** = fred
314 [acl.deny]
314 [acl.deny]
315 foo/bar/** = fred
315 foo/bar/** = fred
316 foo/Bar/** = fred
316 foo/Bar/** = fred
317 """
317 """
318 pushing to ../b
318 pushing to ../b
319 searching for changes
319 searching for changes
320 common changesets up to 6675d58eff77
320 common changesets up to 6675d58eff77
321 3 changesets found
321 3 changesets found
322 List of changesets:
322 List of changesets:
323 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
323 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
324 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
324 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
325 911600dab2ae7a9baff75958b84fe606851ce955
325 911600dab2ae7a9baff75958b84fe606851ce955
326 adding changesets
326 adding changesets
327 add changeset ef1ea85a6374
327 add changeset ef1ea85a6374
328 add changeset f9cafe1212c8
328 add changeset f9cafe1212c8
329 add changeset 911600dab2ae
329 add changeset 911600dab2ae
330 adding manifests
330 adding manifests
331 adding file changes
331 adding file changes
332 adding foo/Bar/file.txt revisions
332 adding foo/Bar/file.txt revisions
333 adding foo/file.txt revisions
333 adding foo/file.txt revisions
334 adding quux/file.py revisions
334 adding quux/file.py revisions
335 added 3 changesets with 3 changes to 3 files
335 added 3 changesets with 3 changes to 3 files
336 calling hook pretxnchangegroup.acl: hgext.acl.hook
336 calling hook pretxnchangegroup.acl: hgext.acl.hook
337 acl: acl.allow enabled, 0 entries for user barney
337 acl: acl.allow enabled, 0 entries for user barney
338 acl: acl.deny enabled, 0 entries for user barney
338 acl: acl.deny enabled, 0 entries for user barney
339 acl: user barney not allowed on foo/file.txt
339 acl: user barney not allowed on foo/file.txt
340 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
340 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
341 abort: acl: access denied for changeset ef1ea85a6374
341 abort: acl: access denied for changeset ef1ea85a6374
342 transaction abort!
342 transaction abort!
343 rollback completed
343 rollback completed
344 no rollback information available
344 no rollback information available
345 0:6675d58eff77
345 0:6675d58eff77
346
346
347 barney is allowed everywhere
347 barney is allowed everywhere
348 Pushing as user barney
348 Pushing as user barney
349 hgrc = """
349 hgrc = """
350 [hooks]
350 [hooks]
351 pretxnchangegroup.acl = python:hgext.acl.hook
351 pretxnchangegroup.acl = python:hgext.acl.hook
352 [acl]
352 [acl]
353 sources = push
353 sources = push
354 [acl.allow]
354 [acl.allow]
355 foo/** = fred
355 foo/** = fred
356 [acl.deny]
356 [acl.deny]
357 foo/bar/** = fred
357 foo/bar/** = fred
358 foo/Bar/** = fred
358 foo/Bar/** = fred
359 [acl.allow]
359 [acl.allow]
360 ** = barney
360 ** = barney
361 """
361 """
362 pushing to ../b
362 pushing to ../b
363 searching for changes
363 searching for changes
364 common changesets up to 6675d58eff77
364 common changesets up to 6675d58eff77
365 3 changesets found
365 3 changesets found
366 List of changesets:
366 List of changesets:
367 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
367 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
368 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
368 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
369 911600dab2ae7a9baff75958b84fe606851ce955
369 911600dab2ae7a9baff75958b84fe606851ce955
370 adding changesets
370 adding changesets
371 add changeset ef1ea85a6374
371 add changeset ef1ea85a6374
372 add changeset f9cafe1212c8
372 add changeset f9cafe1212c8
373 add changeset 911600dab2ae
373 add changeset 911600dab2ae
374 adding manifests
374 adding manifests
375 adding file changes
375 adding file changes
376 adding foo/Bar/file.txt revisions
376 adding foo/Bar/file.txt revisions
377 adding foo/file.txt revisions
377 adding foo/file.txt revisions
378 adding quux/file.py revisions
378 adding quux/file.py revisions
379 added 3 changesets with 3 changes to 3 files
379 added 3 changesets with 3 changes to 3 files
380 calling hook pretxnchangegroup.acl: hgext.acl.hook
380 calling hook pretxnchangegroup.acl: hgext.acl.hook
381 acl: acl.allow enabled, 1 entries for user barney
381 acl: acl.allow enabled, 1 entries for user barney
382 acl: acl.deny enabled, 0 entries for user barney
382 acl: acl.deny enabled, 0 entries for user barney
383 acl: allowing changeset ef1ea85a6374
383 acl: allowing changeset ef1ea85a6374
384 acl: allowing changeset f9cafe1212c8
384 acl: allowing changeset f9cafe1212c8
385 acl: allowing changeset 911600dab2ae
385 acl: allowing changeset 911600dab2ae
386 rolling back last transaction
386 rolling back last transaction
387 0:6675d58eff77
387 0:6675d58eff77
388
388
389 wilma can change files with a .txt extension
389 wilma can change files with a .txt extension
390 Pushing as user wilma
390 Pushing as user wilma
391 hgrc = """
391 hgrc = """
392 [hooks]
392 [hooks]
393 pretxnchangegroup.acl = python:hgext.acl.hook
393 pretxnchangegroup.acl = python:hgext.acl.hook
394 [acl]
394 [acl]
395 sources = push
395 sources = push
396 [acl.allow]
396 [acl.allow]
397 foo/** = fred
397 foo/** = fred
398 [acl.deny]
398 [acl.deny]
399 foo/bar/** = fred
399 foo/bar/** = fred
400 foo/Bar/** = fred
400 foo/Bar/** = fred
401 [acl.allow]
401 [acl.allow]
402 ** = barney
402 ** = barney
403 **/*.txt = wilma
403 **/*.txt = wilma
404 """
404 """
405 pushing to ../b
405 pushing to ../b
406 searching for changes
406 searching for changes
407 common changesets up to 6675d58eff77
407 common changesets up to 6675d58eff77
408 3 changesets found
408 3 changesets found
409 List of changesets:
409 List of changesets:
410 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
410 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
411 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
411 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
412 911600dab2ae7a9baff75958b84fe606851ce955
412 911600dab2ae7a9baff75958b84fe606851ce955
413 adding changesets
413 adding changesets
414 add changeset ef1ea85a6374
414 add changeset ef1ea85a6374
415 add changeset f9cafe1212c8
415 add changeset f9cafe1212c8
416 add changeset 911600dab2ae
416 add changeset 911600dab2ae
417 adding manifests
417 adding manifests
418 adding file changes
418 adding file changes
419 adding foo/Bar/file.txt revisions
419 adding foo/Bar/file.txt revisions
420 adding foo/file.txt revisions
420 adding foo/file.txt revisions
421 adding quux/file.py revisions
421 adding quux/file.py revisions
422 added 3 changesets with 3 changes to 3 files
422 added 3 changesets with 3 changes to 3 files
423 calling hook pretxnchangegroup.acl: hgext.acl.hook
423 calling hook pretxnchangegroup.acl: hgext.acl.hook
424 acl: acl.allow enabled, 1 entries for user wilma
424 acl: acl.allow enabled, 1 entries for user wilma
425 acl: acl.deny enabled, 0 entries for user wilma
425 acl: acl.deny enabled, 0 entries for user wilma
426 acl: allowing changeset ef1ea85a6374
426 acl: allowing changeset ef1ea85a6374
427 acl: allowing changeset f9cafe1212c8
427 acl: allowing changeset f9cafe1212c8
428 acl: user wilma not allowed on quux/file.py
428 acl: user wilma not allowed on quux/file.py
429 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
429 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
430 abort: acl: access denied for changeset 911600dab2ae
430 abort: acl: access denied for changeset 911600dab2ae
431 transaction abort!
431 transaction abort!
432 rollback completed
432 rollback completed
433 no rollback information available
433 no rollback information available
434 0:6675d58eff77
434 0:6675d58eff77
435
435
436 file specified by acl.config does not exist
436 file specified by acl.config does not exist
437 Pushing as user barney
437 Pushing as user barney
438 hgrc = """
438 hgrc = """
439 [hooks]
439 [hooks]
440 pretxnchangegroup.acl = python:hgext.acl.hook
440 pretxnchangegroup.acl = python:hgext.acl.hook
441 [acl]
441 [acl]
442 sources = push
442 sources = push
443 [acl.allow]
443 [acl.allow]
444 foo/** = fred
444 foo/** = fred
445 [acl.deny]
445 [acl.deny]
446 foo/bar/** = fred
446 foo/bar/** = fred
447 foo/Bar/** = fred
447 foo/Bar/** = fred
448 [acl.allow]
448 [acl.allow]
449 ** = barney
449 ** = barney
450 **/*.txt = wilma
450 **/*.txt = wilma
451 [acl]
451 [acl]
452 config = ../acl.config
452 config = ../acl.config
453 """
453 """
454 pushing to ../b
454 pushing to ../b
455 searching for changes
455 searching for changes
456 common changesets up to 6675d58eff77
456 common changesets up to 6675d58eff77
457 3 changesets found
457 3 changesets found
458 List of changesets:
458 List of changesets:
459 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
459 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
460 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
460 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
461 911600dab2ae7a9baff75958b84fe606851ce955
461 911600dab2ae7a9baff75958b84fe606851ce955
462 adding changesets
462 adding changesets
463 add changeset ef1ea85a6374
463 add changeset ef1ea85a6374
464 add changeset f9cafe1212c8
464 add changeset f9cafe1212c8
465 add changeset 911600dab2ae
465 add changeset 911600dab2ae
466 adding manifests
466 adding manifests
467 adding file changes
467 adding file changes
468 adding foo/Bar/file.txt revisions
468 adding foo/Bar/file.txt revisions
469 adding foo/file.txt revisions
469 adding foo/file.txt revisions
470 adding quux/file.py revisions
470 adding quux/file.py revisions
471 added 3 changesets with 3 changes to 3 files
471 added 3 changesets with 3 changes to 3 files
472 calling hook pretxnchangegroup.acl: hgext.acl.hook
472 calling hook pretxnchangegroup.acl: hgext.acl.hook
473 acl: acl.allow enabled, 1 entries for user barney
473 error: pretxnchangegroup.acl hook failed: unable to open ../acl.config: No such file or directory
474 acl: acl.deny enabled, 0 entries for user barney
474 abort: unable to open ../acl.config: No such file or directory
475 acl: allowing changeset ef1ea85a6374
475 transaction abort!
476 acl: allowing changeset f9cafe1212c8
476 rollback completed
477 acl: allowing changeset 911600dab2ae
477 no rollback information available
478 rolling back last transaction
479 0:6675d58eff77
478 0:6675d58eff77
480
479
481 betty is allowed inside foo/ by a acl.config file
480 betty is allowed inside foo/ by a acl.config file
482 Pushing as user betty
481 Pushing as user betty
483 hgrc = """
482 hgrc = """
484 [hooks]
483 [hooks]
485 pretxnchangegroup.acl = python:hgext.acl.hook
484 pretxnchangegroup.acl = python:hgext.acl.hook
486 [acl]
485 [acl]
487 sources = push
486 sources = push
488 [acl.allow]
487 [acl.allow]
489 foo/** = fred
488 foo/** = fred
490 [acl.deny]
489 [acl.deny]
491 foo/bar/** = fred
490 foo/bar/** = fred
492 foo/Bar/** = fred
491 foo/Bar/** = fred
493 [acl.allow]
492 [acl.allow]
494 ** = barney
493 ** = barney
495 **/*.txt = wilma
494 **/*.txt = wilma
496 [acl]
495 [acl]
497 config = ../acl.config
496 config = ../acl.config
498 """
497 """
499 acl.config = """
498 acl.config = """
500 [acl.allow]
499 [acl.allow]
501 foo/** = betty
500 foo/** = betty
502 """
501 """
503 pushing to ../b
502 pushing to ../b
504 searching for changes
503 searching for changes
505 common changesets up to 6675d58eff77
504 common changesets up to 6675d58eff77
506 3 changesets found
505 3 changesets found
507 List of changesets:
506 List of changesets:
508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
507 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
508 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
510 911600dab2ae7a9baff75958b84fe606851ce955
509 911600dab2ae7a9baff75958b84fe606851ce955
511 adding changesets
510 adding changesets
512 add changeset ef1ea85a6374
511 add changeset ef1ea85a6374
513 add changeset f9cafe1212c8
512 add changeset f9cafe1212c8
514 add changeset 911600dab2ae
513 add changeset 911600dab2ae
515 adding manifests
514 adding manifests
516 adding file changes
515 adding file changes
517 adding foo/Bar/file.txt revisions
516 adding foo/Bar/file.txt revisions
518 adding foo/file.txt revisions
517 adding foo/file.txt revisions
519 adding quux/file.py revisions
518 adding quux/file.py revisions
520 added 3 changesets with 3 changes to 3 files
519 added 3 changesets with 3 changes to 3 files
521 calling hook pretxnchangegroup.acl: hgext.acl.hook
520 calling hook pretxnchangegroup.acl: hgext.acl.hook
522 acl: acl.allow enabled, 1 entries for user betty
521 acl: acl.allow enabled, 1 entries for user betty
523 acl: acl.deny enabled, 0 entries for user betty
522 acl: acl.deny enabled, 0 entries for user betty
524 acl: allowing changeset ef1ea85a6374
523 acl: allowing changeset ef1ea85a6374
525 acl: allowing changeset f9cafe1212c8
524 acl: allowing changeset f9cafe1212c8
526 acl: user betty not allowed on quux/file.py
525 acl: user betty not allowed on quux/file.py
527 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
526 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
528 abort: acl: access denied for changeset 911600dab2ae
527 abort: acl: access denied for changeset 911600dab2ae
529 transaction abort!
528 transaction abort!
530 rollback completed
529 rollback completed
531 no rollback information available
530 no rollback information available
532 0:6675d58eff77
531 0:6675d58eff77
533
532
534 acl.config can set only [acl.allow]/[acl.deny]
533 acl.config can set only [acl.allow]/[acl.deny]
535 Pushing as user barney
534 Pushing as user barney
536 hgrc = """
535 hgrc = """
537 [hooks]
536 [hooks]
538 pretxnchangegroup.acl = python:hgext.acl.hook
537 pretxnchangegroup.acl = python:hgext.acl.hook
539 [acl]
538 [acl]
540 sources = push
539 sources = push
541 [acl.allow]
540 [acl.allow]
542 foo/** = fred
541 foo/** = fred
543 [acl.deny]
542 [acl.deny]
544 foo/bar/** = fred
543 foo/bar/** = fred
545 foo/Bar/** = fred
544 foo/Bar/** = fred
546 [acl.allow]
545 [acl.allow]
547 ** = barney
546 ** = barney
548 **/*.txt = wilma
547 **/*.txt = wilma
549 [acl]
548 [acl]
550 config = ../acl.config
549 config = ../acl.config
551 """
550 """
552 acl.config = """
551 acl.config = """
553 [acl.allow]
552 [acl.allow]
554 foo/** = betty
553 foo/** = betty
555 [hooks]
554 [hooks]
556 changegroup.acl = false
555 changegroup.acl = false
557 """
556 """
558 pushing to ../b
557 pushing to ../b
559 searching for changes
558 searching for changes
560 common changesets up to 6675d58eff77
559 common changesets up to 6675d58eff77
561 3 changesets found
560 3 changesets found
562 List of changesets:
561 List of changesets:
563 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
562 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
564 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
563 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
565 911600dab2ae7a9baff75958b84fe606851ce955
564 911600dab2ae7a9baff75958b84fe606851ce955
566 adding changesets
565 adding changesets
567 add changeset ef1ea85a6374
566 add changeset ef1ea85a6374
568 add changeset f9cafe1212c8
567 add changeset f9cafe1212c8
569 add changeset 911600dab2ae
568 add changeset 911600dab2ae
570 adding manifests
569 adding manifests
571 adding file changes
570 adding file changes
572 adding foo/Bar/file.txt revisions
571 adding foo/Bar/file.txt revisions
573 adding foo/file.txt revisions
572 adding foo/file.txt revisions
574 adding quux/file.py revisions
573 adding quux/file.py revisions
575 added 3 changesets with 3 changes to 3 files
574 added 3 changesets with 3 changes to 3 files
576 calling hook pretxnchangegroup.acl: hgext.acl.hook
575 calling hook pretxnchangegroup.acl: hgext.acl.hook
577 acl: acl.allow enabled, 1 entries for user barney
576 acl: acl.allow enabled, 1 entries for user barney
578 acl: acl.deny enabled, 0 entries for user barney
577 acl: acl.deny enabled, 0 entries for user barney
579 acl: allowing changeset ef1ea85a6374
578 acl: allowing changeset ef1ea85a6374
580 acl: allowing changeset f9cafe1212c8
579 acl: allowing changeset f9cafe1212c8
581 acl: allowing changeset 911600dab2ae
580 acl: allowing changeset 911600dab2ae
582 rolling back last transaction
581 rolling back last transaction
583 0:6675d58eff77
582 0:6675d58eff77
584
583
@@ -1,56 +1,62
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cat <<EOF >> $HGRCPATH
3 cat <<EOF >> $HGRCPATH
4 [extensions]
4 [extensions]
5 notify=
5 notify=
6
6
7 [hooks]
7 [hooks]
8 incoming.notify = python:hgext.notify.hook
8 incoming.notify = python:hgext.notify.hook
9
9
10 [notify]
10 [notify]
11 sources = pull
11 sources = pull
12 diffstat = False
12 diffstat = False
13
13
14 [usersubs]
14 [usersubs]
15 foo@bar = *
15 foo@bar = *
16
16
17 [reposubs]
17 [reposubs]
18 * = baz
18 * = baz
19 EOF
19 EOF
20
20
21 hg help notify
21 hg help notify
22 hg init a
22 hg init a
23 echo a > a/a
23 echo a > a/a
24 echo % commit
24 echo % commit
25 hg --traceback --cwd a commit -Ama -d '0 0'
25 hg --traceback --cwd a commit -Ama -d '0 0'
26
26
27 echo % clone
27 echo % clone
28 hg --traceback clone a b
28 hg --traceback clone a b
29
29
30 echo a >> a/a
30 echo a >> a/a
31 echo % commit
31 echo % commit
32 hg --traceback --cwd a commit -Amb -d '1 0'
32 hg --traceback --cwd a commit -Amb -d '1 0'
33
33
34 echo '% pull (minimal config)'
34 echo '% pull (minimal config)'
35 hg --traceback --cwd b pull ../a 2>&1 | sed -e 's/\(Message-Id:\).*/\1/' \
35 hg --traceback --cwd b pull ../a 2>&1 | sed -e 's/\(Message-Id:\).*/\1/' \
36 -e 's/changeset \([0-9a-f]* *\)in .*test-notif/changeset \1in test-notif/' \
36 -e 's/changeset \([0-9a-f]* *\)in .*test-notif/changeset \1in test-notif/' \
37 -e 's/^details: .*test-notify/details: test-notify/' \
37 -e 's/^details: .*test-notify/details: test-notify/' \
38 -e 's/^Date:.*/Date:/'
38 -e 's/^Date:.*/Date:/'
39
39
40 cat <<EOF >> $HGRCPATH
40 cat <<EOF >> $HGRCPATH
41 [notify]
41 [notify]
42 config = $HGTMP/.notify.conf
42 config = $HGTMP/.notify.conf
43 domain = test.com
43 domain = test.com
44 strip = 3
44 strip = 3
45 template = Subject: {desc|firstline|strip}\nFrom: {author}\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
45 template = Subject: {desc|firstline|strip}\nFrom: {author}\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
46
46
47 [web]
47 [web]
48 baseurl = http://test/
48 baseurl = http://test/
49 EOF
49 EOF
50
50
51 echo % fail for config file is missing
52 hg --cwd b rollback
53 hg --cwd b pull ../a 2>&1 | grep 'unable to open.*\.notify\.conf' > /dev/null && echo pull failed
54
55 touch "$HGTMP/.notify.conf"
56
51 echo % pull
57 echo % pull
52 hg --cwd b rollback
58 hg --cwd b rollback
53 hg --traceback --cwd b pull ../a 2>&1 | sed -e 's/\(Message-Id:\).*/\1/' \
59 hg --traceback --cwd b pull ../a 2>&1 | sed -e 's/\(Message-Id:\).*/\1/' \
54 -e 's/changeset \([0-9a-f]*\) in .*/changeset \1/' \
60 -e 's/changeset \([0-9a-f]*\) in .*/changeset \1/' \
55 -e 's/^Date:.*/Date:/'
61 -e 's/^Date:.*/Date:/'
56
62
@@ -1,63 +1,66
1 notify extension - No help text available
1 notify extension - No help text available
2
2
3 no commands defined
3 no commands defined
4 % commit
4 % commit
5 adding a
5 adding a
6 % clone
6 % clone
7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
8 % commit
8 % commit
9 % pull (minimal config)
9 % pull (minimal config)
10 pulling from ../a
10 pulling from ../a
11 searching for changes
11 searching for changes
12 adding changesets
12 adding changesets
13 adding manifests
13 adding manifests
14 adding file changes
14 adding file changes
15 added 1 changesets with 1 changes to 1 files
15 added 1 changesets with 1 changes to 1 files
16 Date:
16 Date:
17 Subject: changeset in test-notify/b: b
17 Subject: changeset in test-notify/b: b
18 From: test
18 From: test
19 X-Hg-Notification: changeset 0647d048b600
19 X-Hg-Notification: changeset 0647d048b600
20 Message-Id:
20 Message-Id:
21 To: baz, foo@bar
21 To: baz, foo@bar
22
22
23 changeset 0647d048b600 in test-notify/b
23 changeset 0647d048b600 in test-notify/b
24 details: test-notify/b?cmd=changeset;node=0647d048b600
24 details: test-notify/b?cmd=changeset;node=0647d048b600
25 description:
25 description:
26 b
26 b
27
27
28 diffs (6 lines):
28 diffs (6 lines):
29
29
30 diff -r cb9a9f314b8b -r 0647d048b600 a
30 diff -r cb9a9f314b8b -r 0647d048b600 a
31 --- a/a Thu Jan 01 00:00:00 1970 +0000
31 --- a/a Thu Jan 01 00:00:00 1970 +0000
32 +++ b/a Thu Jan 01 00:00:01 1970 +0000
32 +++ b/a Thu Jan 01 00:00:01 1970 +0000
33 @@ -1,1 +1,2 @@ a
33 @@ -1,1 +1,2 @@ a
34 a
34 a
35 +a
35 +a
36 (run 'hg update' to get a working copy)
36 (run 'hg update' to get a working copy)
37 % fail for config file is missing
38 rolling back last transaction
39 pull failed
37 % pull
40 % pull
38 rolling back last transaction
41 rolling back last transaction
39 pulling from ../a
42 pulling from ../a
40 searching for changes
43 searching for changes
41 adding changesets
44 adding changesets
42 adding manifests
45 adding manifests
43 adding file changes
46 adding file changes
44 added 1 changesets with 1 changes to 1 files
47 added 1 changesets with 1 changes to 1 files
45 Date:
48 Date:
46 Subject: b
49 Subject: b
47 From: test@test.com
50 From: test@test.com
48 X-Hg-Notification: changeset 0647d048b600
51 X-Hg-Notification: changeset 0647d048b600
49 Message-Id:
52 Message-Id:
50 To: baz@test.com, foo@bar
53 To: baz@test.com, foo@bar
51
54
52 changeset 0647d048b600
55 changeset 0647d048b600
53 description:
56 description:
54 b
57 b
55 diffs (6 lines):
58 diffs (6 lines):
56
59
57 diff -r cb9a9f314b8b -r 0647d048b600 a
60 diff -r cb9a9f314b8b -r 0647d048b600 a
58 --- a/a Thu Jan 01 00:00:00 1970 +0000
61 --- a/a Thu Jan 01 00:00:00 1970 +0000
59 +++ b/a Thu Jan 01 00:00:01 1970 +0000
62 +++ b/a Thu Jan 01 00:00:01 1970 +0000
60 @@ -1,1 +1,2 @@ a
63 @@ -1,1 +1,2 @@ a
61 a
64 a
62 +a
65 +a
63 (run 'hg update' to get a working copy)
66 (run 'hg update' to get a working copy)
General Comments 0
You need to be logged in to leave comments. Login now