##// END OF EJS Templates
clfilter: enforce hidden filtering on all repository accesses...
Pierre-Yves David -
r18303:4d1671b3 default
parent child Browse files
Show More
@@ -1,835 +1,833 b''
1 1 # dispatch.py - command dispatching for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 10 import util, commands, hg, fancyopts, extensions, hook, error
11 11 import cmdutil, encoding
12 12 import ui as uimod
13 13
14 14 class request(object):
15 15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 16 ferr=None):
17 17 self.args = args
18 18 self.ui = ui
19 19 self.repo = repo
20 20
21 21 # input/output/error streams
22 22 self.fin = fin
23 23 self.fout = fout
24 24 self.ferr = ferr
25 25
26 26 def run():
27 27 "run the command in sys.argv"
28 28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29 29
30 30 def dispatch(req):
31 31 "run the command specified in req.args"
32 32 if req.ferr:
33 33 ferr = req.ferr
34 34 elif req.ui:
35 35 ferr = req.ui.ferr
36 36 else:
37 37 ferr = sys.stderr
38 38
39 39 try:
40 40 if not req.ui:
41 41 req.ui = uimod.ui()
42 42 if '--traceback' in req.args:
43 43 req.ui.setconfig('ui', 'traceback', 'on')
44 44
45 45 # set ui streams from the request
46 46 if req.fin:
47 47 req.ui.fin = req.fin
48 48 if req.fout:
49 49 req.ui.fout = req.fout
50 50 if req.ferr:
51 51 req.ui.ferr = req.ferr
52 52 except util.Abort, inst:
53 53 ferr.write(_("abort: %s\n") % inst)
54 54 if inst.hint:
55 55 ferr.write(_("(%s)\n") % inst.hint)
56 56 return -1
57 57 except error.ParseError, inst:
58 58 if len(inst.args) > 1:
59 59 ferr.write(_("hg: parse error at %s: %s\n") %
60 60 (inst.args[1], inst.args[0]))
61 61 else:
62 62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
63 63 return -1
64 64
65 65 return _runcatch(req)
66 66
67 67 def _runcatch(req):
68 68 def catchterm(*args):
69 69 raise error.SignalInterrupt
70 70
71 71 ui = req.ui
72 72 try:
73 73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
74 74 num = getattr(signal, name, None)
75 75 if num:
76 76 signal.signal(num, catchterm)
77 77 except ValueError:
78 78 pass # happens if called in a thread
79 79
80 80 try:
81 81 try:
82 82 # enter the debugger before command execution
83 83 if '--debugger' in req.args:
84 84 ui.warn(_("entering debugger - "
85 85 "type c to continue starting hg or h for help\n"))
86 86 pdb.set_trace()
87 87 try:
88 88 return _dispatch(req)
89 89 finally:
90 90 ui.flush()
91 91 except: # re-raises
92 92 # enter the debugger when we hit an exception
93 93 if '--debugger' in req.args:
94 94 traceback.print_exc()
95 95 pdb.post_mortem(sys.exc_info()[2])
96 96 ui.traceback()
97 97 raise
98 98
99 99 # Global exception handling, alphabetically
100 100 # Mercurial-specific first, followed by built-in and library exceptions
101 101 except error.AmbiguousCommand, inst:
102 102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
103 103 (inst.args[0], " ".join(inst.args[1])))
104 104 except error.ParseError, inst:
105 105 if len(inst.args) > 1:
106 106 ui.warn(_("hg: parse error at %s: %s\n") %
107 107 (inst.args[1], inst.args[0]))
108 108 else:
109 109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
110 110 return -1
111 111 except error.LockHeld, inst:
112 112 if inst.errno == errno.ETIMEDOUT:
113 113 reason = _('timed out waiting for lock held by %s') % inst.locker
114 114 else:
115 115 reason = _('lock held by %s') % inst.locker
116 116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
117 117 except error.LockUnavailable, inst:
118 118 ui.warn(_("abort: could not lock %s: %s\n") %
119 119 (inst.desc or inst.filename, inst.strerror))
120 120 except error.CommandError, inst:
121 121 if inst.args[0]:
122 122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
123 123 commands.help_(ui, inst.args[0], full=False, command=True)
124 124 else:
125 125 ui.warn(_("hg: %s\n") % inst.args[1])
126 126 commands.help_(ui, 'shortlist')
127 127 except error.OutOfBandError, inst:
128 128 ui.warn(_("abort: remote error:\n"))
129 129 ui.warn(''.join(inst.args))
130 130 except error.RepoError, inst:
131 131 ui.warn(_("abort: %s!\n") % inst)
132 132 if inst.hint:
133 133 ui.warn(_("(%s)\n") % inst.hint)
134 134 except error.ResponseError, inst:
135 135 ui.warn(_("abort: %s") % inst.args[0])
136 136 if not isinstance(inst.args[1], basestring):
137 137 ui.warn(" %r\n" % (inst.args[1],))
138 138 elif not inst.args[1]:
139 139 ui.warn(_(" empty string\n"))
140 140 else:
141 141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
142 142 except error.RevlogError, inst:
143 143 ui.warn(_("abort: %s!\n") % inst)
144 144 except error.SignalInterrupt:
145 145 ui.warn(_("killed!\n"))
146 146 except error.UnknownCommand, inst:
147 147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
148 148 try:
149 149 # check if the command is in a disabled extension
150 150 # (but don't check for extensions themselves)
151 151 commands.help_(ui, inst.args[0], unknowncmd=True)
152 152 except error.UnknownCommand:
153 153 commands.help_(ui, 'shortlist')
154 154 except util.Abort, inst:
155 155 ui.warn(_("abort: %s\n") % inst)
156 156 if inst.hint:
157 157 ui.warn(_("(%s)\n") % inst.hint)
158 158 except ImportError, inst:
159 159 ui.warn(_("abort: %s!\n") % inst)
160 160 m = str(inst).split()[-1]
161 161 if m in "mpatch bdiff".split():
162 162 ui.warn(_("(did you forget to compile extensions?)\n"))
163 163 elif m in "zlib".split():
164 164 ui.warn(_("(is your Python install correct?)\n"))
165 165 except IOError, inst:
166 166 if util.safehasattr(inst, "code"):
167 167 ui.warn(_("abort: %s\n") % inst)
168 168 elif util.safehasattr(inst, "reason"):
169 169 try: # usually it is in the form (errno, strerror)
170 170 reason = inst.reason.args[1]
171 171 except (AttributeError, IndexError):
172 172 # it might be anything, for example a string
173 173 reason = inst.reason
174 174 ui.warn(_("abort: error: %s\n") % reason)
175 175 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
176 176 if ui.debugflag:
177 177 ui.warn(_("broken pipe\n"))
178 178 elif getattr(inst, "strerror", None):
179 179 if getattr(inst, "filename", None):
180 180 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
181 181 else:
182 182 ui.warn(_("abort: %s\n") % inst.strerror)
183 183 else:
184 184 raise
185 185 except OSError, inst:
186 186 if getattr(inst, "filename", None) is not None:
187 187 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
188 188 else:
189 189 ui.warn(_("abort: %s\n") % inst.strerror)
190 190 except KeyboardInterrupt:
191 191 try:
192 192 ui.warn(_("interrupted!\n"))
193 193 except IOError, inst:
194 194 if inst.errno == errno.EPIPE:
195 195 if ui.debugflag:
196 196 ui.warn(_("\nbroken pipe\n"))
197 197 else:
198 198 raise
199 199 except MemoryError:
200 200 ui.warn(_("abort: out of memory\n"))
201 201 except SystemExit, inst:
202 202 # Commands shouldn't sys.exit directly, but give a return code.
203 203 # Just in case catch this and and pass exit code to caller.
204 204 return inst.code
205 205 except socket.error, inst:
206 206 ui.warn(_("abort: %s\n") % inst.args[-1])
207 207 except: # re-raises
208 208 myver = util.version()
209 209 # For compatibility checking, we discard the portion of the hg
210 210 # version after the + on the assumption that if a "normal
211 211 # user" is running a build with a + in it the packager
212 212 # probably built from fairly close to a tag and anyone with a
213 213 # 'make local' copy of hg (where the version number can be out
214 214 # of date) will be clueful enough to notice the implausible
215 215 # version number and try updating.
216 216 compare = myver.split('+')[0]
217 217 ct = tuplever(compare)
218 218 worst = None, ct, ''
219 219 for name, mod in extensions.extensions():
220 220 testedwith = getattr(mod, 'testedwith', '')
221 221 report = getattr(mod, 'buglink', _('the extension author.'))
222 222 if not testedwith.strip():
223 223 # We found an untested extension. It's likely the culprit.
224 224 worst = name, 'unknown', report
225 225 break
226 226 if compare not in testedwith.split() and testedwith != 'internal':
227 227 tested = [tuplever(v) for v in testedwith.split()]
228 228 lower = [t for t in tested if t < ct]
229 229 nearest = max(lower or tested)
230 230 if worst[0] is None or nearest < worst[1]:
231 231 worst = name, nearest, report
232 232 if worst[0] is not None:
233 233 name, testedwith, report = worst
234 234 if not isinstance(testedwith, str):
235 235 testedwith = '.'.join([str(c) for c in testedwith])
236 236 warning = (_('** Unknown exception encountered with '
237 237 'possibly-broken third-party extension %s\n'
238 238 '** which supports versions %s of Mercurial.\n'
239 239 '** Please disable %s and try your action again.\n'
240 240 '** If that fixes the bug please report it to %s\n')
241 241 % (name, testedwith, name, report))
242 242 else:
243 243 warning = (_("** unknown exception encountered, "
244 244 "please report by visiting\n") +
245 245 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
246 246 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
247 247 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
248 248 (_("** Extensions loaded: %s\n") %
249 249 ", ".join([x[0] for x in extensions.extensions()])))
250 250 ui.warn(warning)
251 251 raise
252 252
253 253 return -1
254 254
255 255 def tuplever(v):
256 256 try:
257 257 return tuple([int(i) for i in v.split('.')])
258 258 except ValueError:
259 259 return tuple()
260 260
261 261 def aliasargs(fn, givenargs):
262 262 args = getattr(fn, 'args', [])
263 263 if args:
264 264 cmd = ' '.join(map(util.shellquote, args))
265 265
266 266 nums = []
267 267 def replacer(m):
268 268 num = int(m.group(1)) - 1
269 269 nums.append(num)
270 270 if num < len(givenargs):
271 271 return givenargs[num]
272 272 raise util.Abort(_('too few arguments for command alias'))
273 273 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
274 274 givenargs = [x for i, x in enumerate(givenargs)
275 275 if i not in nums]
276 276 args = shlex.split(cmd)
277 277 return args + givenargs
278 278
279 279 class cmdalias(object):
280 280 def __init__(self, name, definition, cmdtable):
281 281 self.name = self.cmd = name
282 282 self.cmdname = ''
283 283 self.definition = definition
284 284 self.args = []
285 285 self.opts = []
286 286 self.help = ''
287 287 self.norepo = True
288 288 self.optionalrepo = False
289 289 self.badalias = False
290 290
291 291 try:
292 292 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
293 293 for alias, e in cmdtable.iteritems():
294 294 if e is entry:
295 295 self.cmd = alias
296 296 break
297 297 self.shadows = True
298 298 except error.UnknownCommand:
299 299 self.shadows = False
300 300
301 301 if not self.definition:
302 302 def fn(ui, *args):
303 303 ui.warn(_("no definition for alias '%s'\n") % self.name)
304 304 return 1
305 305 self.fn = fn
306 306 self.badalias = True
307 307 return
308 308
309 309 if self.definition.startswith('!'):
310 310 self.shell = True
311 311 def fn(ui, *args):
312 312 env = {'HG_ARGS': ' '.join((self.name,) + args)}
313 313 def _checkvar(m):
314 314 if m.groups()[0] == '$':
315 315 return m.group()
316 316 elif int(m.groups()[0]) <= len(args):
317 317 return m.group()
318 318 else:
319 319 ui.debug("No argument found for substitution "
320 320 "of %i variable in alias '%s' definition."
321 321 % (int(m.groups()[0]), self.name))
322 322 return ''
323 323 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
324 324 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
325 325 replace['0'] = self.name
326 326 replace['@'] = ' '.join(args)
327 327 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
328 328 return util.system(cmd, environ=env, out=ui.fout)
329 329 self.fn = fn
330 330 return
331 331
332 332 args = shlex.split(self.definition)
333 333 self.cmdname = cmd = args.pop(0)
334 334 args = map(util.expandpath, args)
335 335
336 336 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
337 337 if _earlygetopt([invalidarg], args):
338 338 def fn(ui, *args):
339 339 ui.warn(_("error in definition for alias '%s': %s may only "
340 340 "be given on the command line\n")
341 341 % (self.name, invalidarg))
342 342 return 1
343 343
344 344 self.fn = fn
345 345 self.badalias = True
346 346 return
347 347
348 348 try:
349 349 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
350 350 if len(tableentry) > 2:
351 351 self.fn, self.opts, self.help = tableentry
352 352 else:
353 353 self.fn, self.opts = tableentry
354 354
355 355 self.args = aliasargs(self.fn, args)
356 356 if cmd not in commands.norepo.split(' '):
357 357 self.norepo = False
358 358 if cmd in commands.optionalrepo.split(' '):
359 359 self.optionalrepo = True
360 360 if self.help.startswith("hg " + cmd):
361 361 # drop prefix in old-style help lines so hg shows the alias
362 362 self.help = self.help[4 + len(cmd):]
363 363 self.__doc__ = self.fn.__doc__
364 364
365 365 except error.UnknownCommand:
366 366 def fn(ui, *args):
367 367 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
368 368 % (self.name, cmd))
369 369 try:
370 370 # check if the command is in a disabled extension
371 371 commands.help_(ui, cmd, unknowncmd=True)
372 372 except error.UnknownCommand:
373 373 pass
374 374 return 1
375 375 self.fn = fn
376 376 self.badalias = True
377 377 except error.AmbiguousCommand:
378 378 def fn(ui, *args):
379 379 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
380 380 % (self.name, cmd))
381 381 return 1
382 382 self.fn = fn
383 383 self.badalias = True
384 384
385 385 def __call__(self, ui, *args, **opts):
386 386 if self.shadows:
387 387 ui.debug("alias '%s' shadows command '%s'\n" %
388 388 (self.name, self.cmdname))
389 389
390 390 if util.safehasattr(self, 'shell'):
391 391 return self.fn(ui, *args, **opts)
392 392 else:
393 393 try:
394 394 util.checksignature(self.fn)(ui, *args, **opts)
395 395 except error.SignatureError:
396 396 args = ' '.join([self.cmdname] + self.args)
397 397 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
398 398 raise
399 399
400 400 def addaliases(ui, cmdtable):
401 401 # aliases are processed after extensions have been loaded, so they
402 402 # may use extension commands. Aliases can also use other alias definitions,
403 403 # but only if they have been defined prior to the current definition.
404 404 for alias, definition in ui.configitems('alias'):
405 405 aliasdef = cmdalias(alias, definition, cmdtable)
406 406
407 407 try:
408 408 olddef = cmdtable[aliasdef.cmd][0]
409 409 if olddef.definition == aliasdef.definition:
410 410 continue
411 411 except (KeyError, AttributeError):
412 412 # definition might not exist or it might not be a cmdalias
413 413 pass
414 414
415 415 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
416 416 if aliasdef.norepo:
417 417 commands.norepo += ' %s' % alias
418 418 if aliasdef.optionalrepo:
419 419 commands.optionalrepo += ' %s' % alias
420 420
421 421 def _parse(ui, args):
422 422 options = {}
423 423 cmdoptions = {}
424 424
425 425 try:
426 426 args = fancyopts.fancyopts(args, commands.globalopts, options)
427 427 except fancyopts.getopt.GetoptError, inst:
428 428 raise error.CommandError(None, inst)
429 429
430 430 if args:
431 431 cmd, args = args[0], args[1:]
432 432 aliases, entry = cmdutil.findcmd(cmd, commands.table,
433 433 ui.configbool("ui", "strict"))
434 434 cmd = aliases[0]
435 435 args = aliasargs(entry[0], args)
436 436 defaults = ui.config("defaults", cmd)
437 437 if defaults:
438 438 args = map(util.expandpath, shlex.split(defaults)) + args
439 439 c = list(entry[1])
440 440 else:
441 441 cmd = None
442 442 c = []
443 443
444 444 # combine global options into local
445 445 for o in commands.globalopts:
446 446 c.append((o[0], o[1], options[o[1]], o[3]))
447 447
448 448 try:
449 449 args = fancyopts.fancyopts(args, c, cmdoptions, True)
450 450 except fancyopts.getopt.GetoptError, inst:
451 451 raise error.CommandError(cmd, inst)
452 452
453 453 # separate global options back out
454 454 for o in commands.globalopts:
455 455 n = o[1]
456 456 options[n] = cmdoptions[n]
457 457 del cmdoptions[n]
458 458
459 459 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
460 460
461 461 def _parseconfig(ui, config):
462 462 """parse the --config options from the command line"""
463 463 configs = []
464 464
465 465 for cfg in config:
466 466 try:
467 467 name, value = cfg.split('=', 1)
468 468 section, name = name.split('.', 1)
469 469 if not section or not name:
470 470 raise IndexError
471 471 ui.setconfig(section, name, value)
472 472 configs.append((section, name, value))
473 473 except (IndexError, ValueError):
474 474 raise util.Abort(_('malformed --config option: %r '
475 475 '(use --config section.name=value)') % cfg)
476 476
477 477 return configs
478 478
479 479 def _earlygetopt(aliases, args):
480 480 """Return list of values for an option (or aliases).
481 481
482 482 The values are listed in the order they appear in args.
483 483 The options and values are removed from args.
484 484 """
485 485 try:
486 486 argcount = args.index("--")
487 487 except ValueError:
488 488 argcount = len(args)
489 489 shortopts = [opt for opt in aliases if len(opt) == 2]
490 490 values = []
491 491 pos = 0
492 492 while pos < argcount:
493 493 if args[pos] in aliases:
494 494 if pos + 1 >= argcount:
495 495 # ignore and let getopt report an error if there is no value
496 496 break
497 497 del args[pos]
498 498 values.append(args.pop(pos))
499 499 argcount -= 2
500 500 elif args[pos][:2] in shortopts:
501 501 # short option can have no following space, e.g. hg log -Rfoo
502 502 values.append(args.pop(pos)[2:])
503 503 argcount -= 1
504 504 else:
505 505 pos += 1
506 506 return values
507 507
508 508 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
509 509 # run pre-hook, and abort if it fails
510 510 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
511 511 pats=cmdpats, opts=cmdoptions)
512 512 if ret:
513 513 return ret
514 514 ret = _runcommand(ui, options, cmd, d)
515 515 # run post-hook, passing command result
516 516 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
517 517 result=ret, pats=cmdpats, opts=cmdoptions)
518 518 return ret
519 519
520 520 def _getlocal(ui, rpath):
521 521 """Return (path, local ui object) for the given target path.
522 522
523 523 Takes paths in [cwd]/.hg/hgrc into account."
524 524 """
525 525 try:
526 526 wd = os.getcwd()
527 527 except OSError, e:
528 528 raise util.Abort(_("error getting current working directory: %s") %
529 529 e.strerror)
530 530 path = cmdutil.findrepo(wd) or ""
531 531 if not path:
532 532 lui = ui
533 533 else:
534 534 lui = ui.copy()
535 535 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
536 536
537 537 if rpath and rpath[-1]:
538 538 path = lui.expandpath(rpath[-1])
539 539 lui = ui.copy()
540 540 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
541 541
542 542 return path, lui
543 543
544 544 def _checkshellalias(lui, ui, args):
545 545 options = {}
546 546
547 547 try:
548 548 args = fancyopts.fancyopts(args, commands.globalopts, options)
549 549 except fancyopts.getopt.GetoptError:
550 550 return
551 551
552 552 if not args:
553 553 return
554 554
555 555 norepo = commands.norepo
556 556 optionalrepo = commands.optionalrepo
557 557 def restorecommands():
558 558 commands.norepo = norepo
559 559 commands.optionalrepo = optionalrepo
560 560
561 561 cmdtable = commands.table.copy()
562 562 addaliases(lui, cmdtable)
563 563
564 564 cmd = args[0]
565 565 try:
566 566 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
567 567 lui.configbool("ui", "strict"))
568 568 except (error.AmbiguousCommand, error.UnknownCommand):
569 569 restorecommands()
570 570 return
571 571
572 572 cmd = aliases[0]
573 573 fn = entry[0]
574 574
575 575 if cmd and util.safehasattr(fn, 'shell'):
576 576 d = lambda: fn(ui, *args[1:])
577 577 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
578 578 [], {})
579 579
580 580 restorecommands()
581 581
582 582 _loaded = set()
583 583 def _dispatch(req):
584 584 args = req.args
585 585 ui = req.ui
586 586
587 587 # read --config before doing anything else
588 588 # (e.g. to change trust settings for reading .hg/hgrc)
589 589 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
590 590
591 591 # check for cwd
592 592 cwd = _earlygetopt(['--cwd'], args)
593 593 if cwd:
594 594 os.chdir(cwd[-1])
595 595
596 596 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
597 597 path, lui = _getlocal(ui, rpath)
598 598
599 599 # Now that we're operating in the right directory/repository with
600 600 # the right config settings, check for shell aliases
601 601 shellaliasfn = _checkshellalias(lui, ui, args)
602 602 if shellaliasfn:
603 603 return shellaliasfn()
604 604
605 605 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
606 606 # reposetup. Programs like TortoiseHg will call _dispatch several
607 607 # times so we keep track of configured extensions in _loaded.
608 608 extensions.loadall(lui)
609 609 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
610 610 # Propagate any changes to lui.__class__ by extensions
611 611 ui.__class__ = lui.__class__
612 612
613 613 # (uisetup and extsetup are handled in extensions.loadall)
614 614
615 615 for name, module in exts:
616 616 cmdtable = getattr(module, 'cmdtable', {})
617 617 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
618 618 if overrides:
619 619 ui.warn(_("extension '%s' overrides commands: %s\n")
620 620 % (name, " ".join(overrides)))
621 621 commands.table.update(cmdtable)
622 622 _loaded.add(name)
623 623
624 624 # (reposetup is handled in hg.repository)
625 625
626 626 addaliases(lui, commands.table)
627 627
628 628 # check for fallback encoding
629 629 fallback = lui.config('ui', 'fallbackencoding')
630 630 if fallback:
631 631 encoding.fallbackencoding = fallback
632 632
633 633 fullargs = args
634 634 cmd, func, args, options, cmdoptions = _parse(lui, args)
635 635
636 636 if options["config"]:
637 637 raise util.Abort(_("option --config may not be abbreviated!"))
638 638 if options["cwd"]:
639 639 raise util.Abort(_("option --cwd may not be abbreviated!"))
640 640 if options["repository"]:
641 641 raise util.Abort(_(
642 642 "option -R has to be separated from other options (e.g. not -qR) "
643 643 "and --repository may only be abbreviated as --repo!"))
644 644
645 645 if options["encoding"]:
646 646 encoding.encoding = options["encoding"]
647 647 if options["encodingmode"]:
648 648 encoding.encodingmode = options["encodingmode"]
649 649 if options["time"]:
650 650 def get_times():
651 651 t = os.times()
652 652 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
653 653 t = (t[0], t[1], t[2], t[3], time.clock())
654 654 return t
655 655 s = get_times()
656 656 def print_time():
657 657 t = get_times()
658 658 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
659 659 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
660 660 atexit.register(print_time)
661 661
662 662 uis = set([ui, lui])
663 663
664 664 if req.repo:
665 665 uis.add(req.repo.ui)
666 666
667 667 # copy configs that were passed on the cmdline (--config) to the repo ui
668 668 for cfg in cfgs:
669 669 req.repo.ui.setconfig(*cfg)
670 670
671 671 if options['verbose'] or options['debug'] or options['quiet']:
672 672 for opt in ('verbose', 'debug', 'quiet'):
673 673 val = str(bool(options[opt]))
674 674 for ui_ in uis:
675 675 ui_.setconfig('ui', opt, val)
676 676
677 677 if options['traceback']:
678 678 for ui_ in uis:
679 679 ui_.setconfig('ui', 'traceback', 'on')
680 680
681 681 if options['noninteractive']:
682 682 for ui_ in uis:
683 683 ui_.setconfig('ui', 'interactive', 'off')
684 684
685 685 if cmdoptions.get('insecure', False):
686 686 for ui_ in uis:
687 687 ui_.setconfig('web', 'cacerts', '')
688 688
689 689 if options['version']:
690 690 return commands.version_(ui)
691 691 if options['help']:
692 692 return commands.help_(ui, cmd)
693 693 elif not cmd:
694 694 return commands.help_(ui, 'shortlist')
695 695
696 696 repo = None
697 697 cmdpats = args[:]
698 698 if cmd not in commands.norepo.split():
699 699 # use the repo from the request only if we don't have -R
700 700 if not rpath and not cwd:
701 701 repo = req.repo
702 702
703 703 if repo:
704 704 # set the descriptors of the repo ui to those of ui
705 705 repo.ui.fin = ui.fin
706 706 repo.ui.fout = ui.fout
707 707 repo.ui.ferr = ui.ferr
708 708 else:
709 709 try:
710 710 repo = hg.repository(ui, path=path)
711 711 if not repo.local():
712 712 raise util.Abort(_("repository '%s' is not local") % path)
713 if not options['hidden']:
714 repo = repo.filtered('hidden')
715 else:
713 if options['hidden']:
716 714 repo = repo.unfiltered()
717 715 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
718 716 except error.RequirementError:
719 717 raise
720 718 except error.RepoError:
721 719 if cmd not in commands.optionalrepo.split():
722 720 if (cmd in commands.inferrepo.split() and
723 721 args and not path): # try to infer -R from command args
724 722 repos = map(cmdutil.findrepo, args)
725 723 guess = repos[0]
726 724 if guess and repos.count(guess) == len(repos):
727 725 req.args = ['--repository', guess] + fullargs
728 726 return _dispatch(req)
729 727 if not path:
730 728 raise error.RepoError(_("no repository found in '%s'"
731 729 " (.hg not found)")
732 730 % os.getcwd())
733 731 raise
734 732 if repo:
735 733 ui = repo.ui
736 734 args.insert(0, repo)
737 735 elif rpath:
738 736 ui.warn(_("warning: --repository ignored\n"))
739 737
740 738 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
741 739 ui.log("command", msg + "\n")
742 740 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
743 741 try:
744 742 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
745 743 cmdpats, cmdoptions)
746 744 finally:
747 745 if repo and repo != req.repo:
748 746 repo.close()
749 747
750 748 def lsprofile(ui, func, fp):
751 749 format = ui.config('profiling', 'format', default='text')
752 750 field = ui.config('profiling', 'sort', default='inlinetime')
753 751 climit = ui.configint('profiling', 'nested', default=5)
754 752
755 753 if format not in ['text', 'kcachegrind']:
756 754 ui.warn(_("unrecognized profiling format '%s'"
757 755 " - Ignored\n") % format)
758 756 format = 'text'
759 757
760 758 try:
761 759 from mercurial import lsprof
762 760 except ImportError:
763 761 raise util.Abort(_(
764 762 'lsprof not available - install from '
765 763 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
766 764 p = lsprof.Profiler()
767 765 p.enable(subcalls=True)
768 766 try:
769 767 return func()
770 768 finally:
771 769 p.disable()
772 770
773 771 if format == 'kcachegrind':
774 772 import lsprofcalltree
775 773 calltree = lsprofcalltree.KCacheGrind(p)
776 774 calltree.output(fp)
777 775 else:
778 776 # format == 'text'
779 777 stats = lsprof.Stats(p.getstats())
780 778 stats.sort(field)
781 779 stats.pprint(limit=30, file=fp, climit=climit)
782 780
783 781 def statprofile(ui, func, fp):
784 782 try:
785 783 import statprof
786 784 except ImportError:
787 785 raise util.Abort(_(
788 786 'statprof not available - install using "easy_install statprof"'))
789 787
790 788 freq = ui.configint('profiling', 'freq', default=1000)
791 789 if freq > 0:
792 790 statprof.reset(freq)
793 791 else:
794 792 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
795 793
796 794 statprof.start()
797 795 try:
798 796 return func()
799 797 finally:
800 798 statprof.stop()
801 799 statprof.display(fp)
802 800
803 801 def _runcommand(ui, options, cmd, cmdfunc):
804 802 def checkargs():
805 803 try:
806 804 return cmdfunc()
807 805 except error.SignatureError:
808 806 raise error.CommandError(cmd, _("invalid arguments"))
809 807
810 808 if options['profile']:
811 809 profiler = os.getenv('HGPROF')
812 810 if profiler is None:
813 811 profiler = ui.config('profiling', 'type', default='ls')
814 812 if profiler not in ('ls', 'stat'):
815 813 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
816 814 profiler = 'ls'
817 815
818 816 output = ui.config('profiling', 'output')
819 817
820 818 if output:
821 819 path = ui.expandpath(output)
822 820 fp = open(path, 'wb')
823 821 else:
824 822 fp = sys.stderr
825 823
826 824 try:
827 825 if profiler == 'ls':
828 826 return lsprofile(ui, checkargs, fp)
829 827 else:
830 828 return statprofile(ui, checkargs, fp)
831 829 finally:
832 830 if output:
833 831 fp.close()
834 832 else:
835 833 return checkargs()
@@ -1,646 +1,646 b''
1 1 # hg.py - repository classes for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from i18n import _
10 10 from lock import release
11 11 from node import hex, nullid
12 12 import localrepo, bundlerepo, httppeer, sshpeer, statichttprepo, bookmarks
13 13 import lock, util, extensions, error, node, scmutil, phases, url
14 14 import cmdutil, discovery
15 15 import merge as mergemod
16 16 import verify as verifymod
17 17 import errno, os, shutil
18 18
19 19 def _local(path):
20 20 path = util.expandpath(util.urllocalpath(path))
21 21 return (os.path.isfile(path) and bundlerepo or localrepo)
22 22
23 23 def addbranchrevs(lrepo, other, branches, revs):
24 24 peer = other.peer() # a courtesy to callers using a localrepo for other
25 25 hashbranch, branches = branches
26 26 if not hashbranch and not branches:
27 27 return revs or None, revs and revs[0] or None
28 28 revs = revs and list(revs) or []
29 29 if not peer.capable('branchmap'):
30 30 if branches:
31 31 raise util.Abort(_("remote branch lookup not supported"))
32 32 revs.append(hashbranch)
33 33 return revs, revs[0]
34 34 branchmap = peer.branchmap()
35 35
36 36 def primary(branch):
37 37 if branch == '.':
38 38 if not lrepo:
39 39 raise util.Abort(_("dirstate branch not accessible"))
40 40 branch = lrepo.dirstate.branch()
41 41 if branch in branchmap:
42 42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
43 43 return True
44 44 else:
45 45 return False
46 46
47 47 for branch in branches:
48 48 if not primary(branch):
49 49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
50 50 if hashbranch:
51 51 if not primary(hashbranch):
52 52 revs.append(hashbranch)
53 53 return revs, revs[0]
54 54
55 55 def parseurl(path, branches=None):
56 56 '''parse url#branch, returning (url, (branch, branches))'''
57 57
58 58 u = util.url(path)
59 59 branch = None
60 60 if u.fragment:
61 61 branch = u.fragment
62 62 u.fragment = None
63 63 return str(u), (branch, branches or [])
64 64
65 65 schemes = {
66 66 'bundle': bundlerepo,
67 67 'file': _local,
68 68 'http': httppeer,
69 69 'https': httppeer,
70 70 'ssh': sshpeer,
71 71 'static-http': statichttprepo,
72 72 }
73 73
74 74 def _peerlookup(path):
75 75 u = util.url(path)
76 76 scheme = u.scheme or 'file'
77 77 thing = schemes.get(scheme) or schemes['file']
78 78 try:
79 79 return thing(path)
80 80 except TypeError:
81 81 return thing
82 82
83 83 def islocal(repo):
84 84 '''return true if repo or path is local'''
85 85 if isinstance(repo, str):
86 86 try:
87 87 return _peerlookup(repo).islocal(repo)
88 88 except AttributeError:
89 89 return False
90 90 return repo.local()
91 91
92 92 def openpath(ui, path):
93 93 '''open path with open if local, url.open if remote'''
94 94 if islocal(path):
95 95 return util.posixfile(util.urllocalpath(path), 'rb')
96 96 else:
97 97 return url.open(ui, path)
98 98
99 99 def _peerorrepo(ui, path, create=False):
100 100 """return a repository object for the specified path"""
101 101 obj = _peerlookup(path).instance(ui, path, create)
102 102 ui = getattr(obj, "ui", ui)
103 103 for name, module in extensions.extensions():
104 104 hook = getattr(module, 'reposetup', None)
105 105 if hook:
106 106 hook(ui, obj)
107 107 return obj
108 108
109 109 def repository(ui, path='', create=False):
110 110 """return a repository object for the specified path"""
111 111 peer = _peerorrepo(ui, path, create)
112 112 repo = peer.local()
113 113 if not repo:
114 114 raise util.Abort(_("repository '%s' is not local") %
115 115 (path or peer.url()))
116 return repo
116 return repo.filtered('hidden')
117 117
118 118 def peer(uiorrepo, opts, path, create=False):
119 119 '''return a repository peer for the specified path'''
120 120 rui = remoteui(uiorrepo, opts)
121 121 return _peerorrepo(rui, path, create).peer()
122 122
123 123 def defaultdest(source):
124 124 '''return default destination of clone if none is given'''
125 125 return os.path.basename(os.path.normpath(util.url(source).path))
126 126
127 127 def share(ui, source, dest=None, update=True):
128 128 '''create a shared repository'''
129 129
130 130 if not islocal(source):
131 131 raise util.Abort(_('can only share local repositories'))
132 132
133 133 if not dest:
134 134 dest = defaultdest(source)
135 135 else:
136 136 dest = ui.expandpath(dest)
137 137
138 138 if isinstance(source, str):
139 139 origsource = ui.expandpath(source)
140 140 source, branches = parseurl(origsource)
141 141 srcrepo = repository(ui, source)
142 142 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
143 143 else:
144 144 srcrepo = source.local()
145 145 origsource = source = srcrepo.url()
146 146 checkout = None
147 147
148 148 sharedpath = srcrepo.sharedpath # if our source is already sharing
149 149
150 150 root = os.path.realpath(dest)
151 151 roothg = os.path.join(root, '.hg')
152 152
153 153 if os.path.exists(roothg):
154 154 raise util.Abort(_('destination already exists'))
155 155
156 156 if not os.path.isdir(root):
157 157 os.mkdir(root)
158 158 util.makedir(roothg, notindexed=True)
159 159
160 160 requirements = ''
161 161 try:
162 162 requirements = srcrepo.opener.read('requires')
163 163 except IOError, inst:
164 164 if inst.errno != errno.ENOENT:
165 165 raise
166 166
167 167 requirements += 'shared\n'
168 168 util.writefile(os.path.join(roothg, 'requires'), requirements)
169 169 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
170 170
171 171 r = repository(ui, root)
172 172
173 173 default = srcrepo.ui.config('paths', 'default')
174 174 if not default:
175 175 # set default to source for being able to clone subrepos
176 176 default = os.path.abspath(util.urllocalpath(origsource))
177 177 fp = r.opener("hgrc", "w", text=True)
178 178 fp.write("[paths]\n")
179 179 fp.write("default = %s\n" % default)
180 180 fp.close()
181 181 r.ui.setconfig('paths', 'default', default)
182 182
183 183 if update:
184 184 r.ui.status(_("updating working directory\n"))
185 185 if update is not True:
186 186 checkout = update
187 187 for test in (checkout, 'default', 'tip'):
188 188 if test is None:
189 189 continue
190 190 try:
191 191 uprev = r.lookup(test)
192 192 break
193 193 except error.RepoLookupError:
194 194 continue
195 195 _update(r, uprev)
196 196
197 197 def copystore(ui, srcrepo, destpath):
198 198 '''copy files from store of srcrepo in destpath
199 199
200 200 returns destlock
201 201 '''
202 202 destlock = None
203 203 try:
204 204 hardlink = None
205 205 num = 0
206 206 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
207 207 for f in srcrepo.store.copylist():
208 208 if srcpublishing and f.endswith('phaseroots'):
209 209 continue
210 210 src = os.path.join(srcrepo.sharedpath, f)
211 211 dst = os.path.join(destpath, f)
212 212 dstbase = os.path.dirname(dst)
213 213 if dstbase and not os.path.exists(dstbase):
214 214 os.mkdir(dstbase)
215 215 if os.path.exists(src):
216 216 if dst.endswith('data'):
217 217 # lock to avoid premature writing to the target
218 218 destlock = lock.lock(os.path.join(dstbase, "lock"))
219 219 hardlink, n = util.copyfiles(src, dst, hardlink)
220 220 num += n
221 221 if hardlink:
222 222 ui.debug("linked %d files\n" % num)
223 223 else:
224 224 ui.debug("copied %d files\n" % num)
225 225 return destlock
226 226 except: # re-raises
227 227 release(destlock)
228 228 raise
229 229
230 230 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
231 231 update=True, stream=False, branch=None):
232 232 """Make a copy of an existing repository.
233 233
234 234 Create a copy of an existing repository in a new directory. The
235 235 source and destination are URLs, as passed to the repository
236 236 function. Returns a pair of repository peers, the source and
237 237 newly created destination.
238 238
239 239 The location of the source is added to the new repository's
240 240 .hg/hgrc file, as the default to be used for future pulls and
241 241 pushes.
242 242
243 243 If an exception is raised, the partly cloned/updated destination
244 244 repository will be deleted.
245 245
246 246 Arguments:
247 247
248 248 source: repository object or URL
249 249
250 250 dest: URL of destination repository to create (defaults to base
251 251 name of source repository)
252 252
253 253 pull: always pull from source repository, even in local case
254 254
255 255 stream: stream raw data uncompressed from repository (fast over
256 256 LAN, slow over WAN)
257 257
258 258 rev: revision to clone up to (implies pull=True)
259 259
260 260 update: update working directory after clone completes, if
261 261 destination is local repository (True means update to default rev,
262 262 anything else is treated as a revision)
263 263
264 264 branch: branches to clone
265 265 """
266 266
267 267 if isinstance(source, str):
268 268 origsource = ui.expandpath(source)
269 269 source, branch = parseurl(origsource, branch)
270 270 srcpeer = peer(ui, peeropts, source)
271 271 else:
272 272 srcpeer = source.peer() # in case we were called with a localrepo
273 273 branch = (None, branch or [])
274 274 origsource = source = srcpeer.url()
275 275 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
276 276
277 277 if dest is None:
278 278 dest = defaultdest(source)
279 279 ui.status(_("destination directory: %s\n") % dest)
280 280 else:
281 281 dest = ui.expandpath(dest)
282 282
283 283 dest = util.urllocalpath(dest)
284 284 source = util.urllocalpath(source)
285 285
286 286 if not dest:
287 287 raise util.Abort(_("empty destination path is not valid"))
288 288 if os.path.exists(dest):
289 289 if not os.path.isdir(dest):
290 290 raise util.Abort(_("destination '%s' already exists") % dest)
291 291 elif os.listdir(dest):
292 292 raise util.Abort(_("destination '%s' is not empty") % dest)
293 293
294 294 class DirCleanup(object):
295 295 def __init__(self, dir_):
296 296 self.rmtree = shutil.rmtree
297 297 self.dir_ = dir_
298 298 def close(self):
299 299 self.dir_ = None
300 300 def cleanup(self):
301 301 if self.dir_:
302 302 self.rmtree(self.dir_, True)
303 303
304 304 srclock = destlock = dircleanup = None
305 305 srcrepo = srcpeer.local()
306 306 try:
307 307 abspath = origsource
308 308 if islocal(origsource):
309 309 abspath = os.path.abspath(util.urllocalpath(origsource))
310 310
311 311 if islocal(dest):
312 312 dircleanup = DirCleanup(dest)
313 313
314 314 copy = False
315 315 if (srcrepo and srcrepo.cancopy() and islocal(dest)
316 316 and not phases.hassecret(srcrepo)):
317 317 copy = not pull and not rev
318 318
319 319 if copy:
320 320 try:
321 321 # we use a lock here because if we race with commit, we
322 322 # can end up with extra data in the cloned revlogs that's
323 323 # not pointed to by changesets, thus causing verify to
324 324 # fail
325 325 srclock = srcrepo.lock(wait=False)
326 326 except error.LockError:
327 327 copy = False
328 328
329 329 if copy:
330 330 srcrepo.hook('preoutgoing', throw=True, source='clone')
331 331 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
332 332 if not os.path.exists(dest):
333 333 os.mkdir(dest)
334 334 else:
335 335 # only clean up directories we create ourselves
336 336 dircleanup.dir_ = hgdir
337 337 try:
338 338 destpath = hgdir
339 339 util.makedir(destpath, notindexed=True)
340 340 except OSError, inst:
341 341 if inst.errno == errno.EEXIST:
342 342 dircleanup.close()
343 343 raise util.Abort(_("destination '%s' already exists")
344 344 % dest)
345 345 raise
346 346
347 347 destlock = copystore(ui, srcrepo, destpath)
348 348
349 349 # Recomputing branch cache might be slow on big repos,
350 350 # so just copy it
351 351 dstcachedir = os.path.join(destpath, 'cache')
352 352 srcbranchcache = srcrepo.sjoin('cache/branchheads')
353 353 dstbranchcache = os.path.join(dstcachedir, 'branchheads')
354 354 if os.path.exists(srcbranchcache):
355 355 if not os.path.exists(dstcachedir):
356 356 os.mkdir(dstcachedir)
357 357 util.copyfile(srcbranchcache, dstbranchcache)
358 358
359 359 # we need to re-init the repo after manually copying the data
360 360 # into it
361 361 destpeer = peer(srcrepo, peeropts, dest)
362 362 srcrepo.hook('outgoing', source='clone',
363 363 node=node.hex(node.nullid))
364 364 else:
365 365 try:
366 366 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
367 367 # only pass ui when no srcrepo
368 368 except OSError, inst:
369 369 if inst.errno == errno.EEXIST:
370 370 dircleanup.close()
371 371 raise util.Abort(_("destination '%s' already exists")
372 372 % dest)
373 373 raise
374 374
375 375 revs = None
376 376 if rev:
377 377 if not srcpeer.capable('lookup'):
378 378 raise util.Abort(_("src repository does not support "
379 379 "revision lookup and so doesn't "
380 380 "support clone by revision"))
381 381 revs = [srcpeer.lookup(r) for r in rev]
382 382 checkout = revs[0]
383 383 if destpeer.local():
384 384 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
385 385 elif srcrepo:
386 386 srcrepo.push(destpeer, revs=revs)
387 387 else:
388 388 raise util.Abort(_("clone from remote to remote not supported"))
389 389
390 390 if dircleanup:
391 391 dircleanup.close()
392 392
393 393 # clone all bookmarks except divergent ones
394 394 destrepo = destpeer.local()
395 395 if destrepo and srcpeer.capable("pushkey"):
396 396 rb = srcpeer.listkeys('bookmarks')
397 397 marks = destrepo._bookmarks
398 398 for k, n in rb.iteritems():
399 399 try:
400 400 m = destrepo.lookup(n)
401 401 marks[k] = m
402 402 except error.RepoLookupError:
403 403 pass
404 404 if rb:
405 405 marks.write()
406 406 elif srcrepo and destpeer.capable("pushkey"):
407 407 for k, n in srcrepo._bookmarks.iteritems():
408 408 destpeer.pushkey('bookmarks', k, '', hex(n))
409 409
410 410 if destrepo:
411 411 fp = destrepo.opener("hgrc", "w", text=True)
412 412 fp.write("[paths]\n")
413 413 u = util.url(abspath)
414 414 u.passwd = None
415 415 defaulturl = str(u)
416 416 fp.write("default = %s\n" % defaulturl)
417 417 fp.close()
418 418
419 419 destrepo.ui.setconfig('paths', 'default', defaulturl)
420 420
421 421 if update:
422 422 if update is not True:
423 423 checkout = srcpeer.lookup(update)
424 424 uprev = None
425 425 status = None
426 426 if checkout is not None:
427 427 try:
428 428 uprev = destrepo.lookup(checkout)
429 429 except error.RepoLookupError:
430 430 pass
431 431 if uprev is None:
432 432 try:
433 433 uprev = destrepo._bookmarks['@']
434 434 update = '@'
435 435 bn = destrepo[uprev].branch()
436 436 if bn == 'default':
437 437 status = _("updating to bookmark @\n")
438 438 else:
439 439 status = _("updating to bookmark @ on branch %s\n"
440 440 % bn)
441 441 except KeyError:
442 442 try:
443 443 uprev = destrepo.branchtip('default')
444 444 except error.RepoLookupError:
445 445 uprev = destrepo.lookup('tip')
446 446 if not status:
447 447 bn = destrepo[uprev].branch()
448 448 status = _("updating to branch %s\n") % bn
449 449 destrepo.ui.status(status)
450 450 _update(destrepo, uprev)
451 451 if update in destrepo._bookmarks:
452 452 bookmarks.setcurrent(destrepo, update)
453 453
454 454 return srcpeer, destpeer
455 455 finally:
456 456 release(srclock, destlock)
457 457 if dircleanup is not None:
458 458 dircleanup.cleanup()
459 459 if srcpeer is not None:
460 460 srcpeer.close()
461 461
462 462 def _showstats(repo, stats):
463 463 repo.ui.status(_("%d files updated, %d files merged, "
464 464 "%d files removed, %d files unresolved\n") % stats)
465 465
466 466 def updaterepo(repo, node, overwrite):
467 467 """Update the working directory to node.
468 468
469 469 When overwrite is set, changes are clobbered, merged else
470 470
471 471 returns stats (see pydoc mercurial.merge.applyupdates)"""
472 472 return mergemod.update(repo, node, False, overwrite, None)
473 473
474 474 def update(repo, node):
475 475 """update the working directory to node, merging linear changes"""
476 476 stats = updaterepo(repo, node, False)
477 477 _showstats(repo, stats)
478 478 if stats[3]:
479 479 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
480 480 return stats[3] > 0
481 481
482 482 # naming conflict in clone()
483 483 _update = update
484 484
485 485 def clean(repo, node, show_stats=True):
486 486 """forcibly switch the working directory to node, clobbering changes"""
487 487 stats = updaterepo(repo, node, True)
488 488 if show_stats:
489 489 _showstats(repo, stats)
490 490 return stats[3] > 0
491 491
492 492 def merge(repo, node, force=None, remind=True):
493 493 """Branch merge with node, resolving changes. Return true if any
494 494 unresolved conflicts."""
495 495 stats = mergemod.update(repo, node, True, force, False)
496 496 _showstats(repo, stats)
497 497 if stats[3]:
498 498 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
499 499 "or 'hg update -C .' to abandon\n"))
500 500 elif remind:
501 501 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
502 502 return stats[3] > 0
503 503
504 504 def _incoming(displaychlist, subreporecurse, ui, repo, source,
505 505 opts, buffered=False):
506 506 """
507 507 Helper for incoming / gincoming.
508 508 displaychlist gets called with
509 509 (remoterepo, incomingchangesetlist, displayer) parameters,
510 510 and is supposed to contain only code that can't be unified.
511 511 """
512 512 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
513 513 other = peer(repo, opts, source)
514 514 ui.status(_('comparing with %s\n') % util.hidepassword(source))
515 515 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
516 516
517 517 if revs:
518 518 revs = [other.lookup(rev) for rev in revs]
519 519 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
520 520 revs, opts["bundle"], opts["force"])
521 521 try:
522 522 if not chlist:
523 523 ui.status(_("no changes found\n"))
524 524 return subreporecurse()
525 525
526 526 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
527 527
528 528 # XXX once graphlog extension makes it into core,
529 529 # should be replaced by a if graph/else
530 530 displaychlist(other, chlist, displayer)
531 531
532 532 displayer.close()
533 533 finally:
534 534 cleanupfn()
535 535 subreporecurse()
536 536 return 0 # exit code is zero since we found incoming changes
537 537
538 538 def incoming(ui, repo, source, opts):
539 539 def subreporecurse():
540 540 ret = 1
541 541 if opts.get('subrepos'):
542 542 ctx = repo[None]
543 543 for subpath in sorted(ctx.substate):
544 544 sub = ctx.sub(subpath)
545 545 ret = min(ret, sub.incoming(ui, source, opts))
546 546 return ret
547 547
548 548 def display(other, chlist, displayer):
549 549 limit = cmdutil.loglimit(opts)
550 550 if opts.get('newest_first'):
551 551 chlist.reverse()
552 552 count = 0
553 553 for n in chlist:
554 554 if limit is not None and count >= limit:
555 555 break
556 556 parents = [p for p in other.changelog.parents(n) if p != nullid]
557 557 if opts.get('no_merges') and len(parents) == 2:
558 558 continue
559 559 count += 1
560 560 displayer.show(other[n])
561 561 return _incoming(display, subreporecurse, ui, repo, source, opts)
562 562
563 563 def _outgoing(ui, repo, dest, opts):
564 564 dest = ui.expandpath(dest or 'default-push', dest or 'default')
565 565 dest, branches = parseurl(dest, opts.get('branch'))
566 566 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
567 567 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
568 568 if revs:
569 569 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
570 570
571 571 other = peer(repo, opts, dest)
572 572 outgoing = discovery.findcommonoutgoing(repo, other, revs,
573 573 force=opts.get('force'))
574 574 o = outgoing.missing
575 575 if not o:
576 576 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
577 577 return None
578 578 return o
579 579
580 580 def outgoing(ui, repo, dest, opts):
581 581 def recurse():
582 582 ret = 1
583 583 if opts.get('subrepos'):
584 584 ctx = repo[None]
585 585 for subpath in sorted(ctx.substate):
586 586 sub = ctx.sub(subpath)
587 587 ret = min(ret, sub.outgoing(ui, dest, opts))
588 588 return ret
589 589
590 590 limit = cmdutil.loglimit(opts)
591 591 o = _outgoing(ui, repo, dest, opts)
592 592 if o is None:
593 593 return recurse()
594 594
595 595 if opts.get('newest_first'):
596 596 o.reverse()
597 597 displayer = cmdutil.show_changeset(ui, repo, opts)
598 598 count = 0
599 599 for n in o:
600 600 if limit is not None and count >= limit:
601 601 break
602 602 parents = [p for p in repo.changelog.parents(n) if p != nullid]
603 603 if opts.get('no_merges') and len(parents) == 2:
604 604 continue
605 605 count += 1
606 606 displayer.show(repo[n])
607 607 displayer.close()
608 608 recurse()
609 609 return 0 # exit code is zero since we found outgoing changes
610 610
611 611 def revert(repo, node, choose):
612 612 """revert changes to revision in node without updating dirstate"""
613 613 return mergemod.update(repo, node, False, True, choose)[3] > 0
614 614
615 615 def verify(repo):
616 616 """verify the consistency of a repository"""
617 617 return verifymod.verify(repo)
618 618
619 619 def remoteui(src, opts):
620 620 'build a remote ui from ui or repo and opts'
621 621 if util.safehasattr(src, 'baseui'): # looks like a repository
622 622 dst = src.baseui.copy() # drop repo-specific config
623 623 src = src.ui # copy target options from repo
624 624 else: # assume it's a global ui object
625 625 dst = src.copy() # keep all global options
626 626
627 627 # copy ssh-specific options
628 628 for o in 'ssh', 'remotecmd':
629 629 v = opts.get(o) or src.config('ui', o)
630 630 if v:
631 631 dst.setconfig("ui", o, v)
632 632
633 633 # copy bundle-specific options
634 634 r = src.config('bundle', 'mainreporoot')
635 635 if r:
636 636 dst.setconfig('bundle', 'mainreporoot', r)
637 637
638 638 # copy selected local settings to the remote ui
639 639 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
640 640 for key, val in src.configitems(sect):
641 641 dst.setconfig(sect, key, val)
642 642 v = src.config('web', 'cacerts')
643 643 if v:
644 644 dst.setconfig('web', 'cacerts', util.expandpath(v))
645 645
646 646 return dst
General Comments 0
You need to be logged in to leave comments. Login now