##// END OF EJS Templates
dispatch: error out on invalid -R path even if optionalrepo (issue4805) (BC)...
Yuya Nishihara -
r26142:7332bf4a default
parent child Browse files
Show More
@@ -1,1037 +1,1039 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 __future__ import absolute_import
9 9
10 10 import atexit
11 11 import difflib
12 12 import errno
13 13 import os
14 14 import pdb
15 15 import re
16 16 import shlex
17 17 import signal
18 18 import socket
19 19 import sys
20 20 import time
21 21 import traceback
22 22
23 23
24 24 from .i18n import _
25 25
26 26 from . import (
27 27 cmdutil,
28 28 commands,
29 29 demandimport,
30 30 encoding,
31 31 error,
32 32 extensions,
33 33 fancyopts,
34 34 hg,
35 35 hook,
36 36 ui as uimod,
37 37 util,
38 38 )
39 39
40 40 class request(object):
41 41 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
42 42 ferr=None):
43 43 self.args = args
44 44 self.ui = ui
45 45 self.repo = repo
46 46
47 47 # input/output/error streams
48 48 self.fin = fin
49 49 self.fout = fout
50 50 self.ferr = ferr
51 51
52 52 def run():
53 53 "run the command in sys.argv"
54 54 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
55 55
56 56 def _getsimilar(symbols, value):
57 57 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
58 58 # The cutoff for similarity here is pretty arbitrary. It should
59 59 # probably be investigated and tweaked.
60 60 return [s for s in symbols if sim(s) > 0.6]
61 61
62 62 def _formatparse(write, inst):
63 63 similar = []
64 64 if isinstance(inst, error.UnknownIdentifier):
65 65 # make sure to check fileset first, as revset can invoke fileset
66 66 similar = _getsimilar(inst.symbols, inst.function)
67 67 if len(inst.args) > 1:
68 68 write(_("hg: parse error at %s: %s\n") %
69 69 (inst.args[1], inst.args[0]))
70 70 if (inst.args[0][0] == ' '):
71 71 write(_("unexpected leading whitespace\n"))
72 72 else:
73 73 write(_("hg: parse error: %s\n") % inst.args[0])
74 74 if similar:
75 75 if len(similar) == 1:
76 76 write(_("(did you mean %r?)\n") % similar[0])
77 77 else:
78 78 ss = ", ".join(sorted(similar))
79 79 write(_("(did you mean one of %s?)\n") % ss)
80 80
81 81 def dispatch(req):
82 82 "run the command specified in req.args"
83 83 if req.ferr:
84 84 ferr = req.ferr
85 85 elif req.ui:
86 86 ferr = req.ui.ferr
87 87 else:
88 88 ferr = sys.stderr
89 89
90 90 try:
91 91 if not req.ui:
92 92 req.ui = uimod.ui()
93 93 if '--traceback' in req.args:
94 94 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
95 95
96 96 # set ui streams from the request
97 97 if req.fin:
98 98 req.ui.fin = req.fin
99 99 if req.fout:
100 100 req.ui.fout = req.fout
101 101 if req.ferr:
102 102 req.ui.ferr = req.ferr
103 103 except util.Abort as inst:
104 104 ferr.write(_("abort: %s\n") % inst)
105 105 if inst.hint:
106 106 ferr.write(_("(%s)\n") % inst.hint)
107 107 return -1
108 108 except error.ParseError as inst:
109 109 _formatparse(ferr.write, inst)
110 110 return -1
111 111
112 112 msg = ' '.join(' ' in a and repr(a) or a for a in req.args)
113 113 starttime = time.time()
114 114 ret = None
115 115 try:
116 116 ret = _runcatch(req)
117 117 return ret
118 118 finally:
119 119 duration = time.time() - starttime
120 120 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
121 121 msg, ret or 0, duration)
122 122
123 123 def _runcatch(req):
124 124 def catchterm(*args):
125 125 raise error.SignalInterrupt
126 126
127 127 ui = req.ui
128 128 try:
129 129 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
130 130 num = getattr(signal, name, None)
131 131 if num:
132 132 signal.signal(num, catchterm)
133 133 except ValueError:
134 134 pass # happens if called in a thread
135 135
136 136 try:
137 137 try:
138 138 debugger = 'pdb'
139 139 debugtrace = {
140 140 'pdb' : pdb.set_trace
141 141 }
142 142 debugmortem = {
143 143 'pdb' : pdb.post_mortem
144 144 }
145 145
146 146 # read --config before doing anything else
147 147 # (e.g. to change trust settings for reading .hg/hgrc)
148 148 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
149 149
150 150 if req.repo:
151 151 # copy configs that were passed on the cmdline (--config) to
152 152 # the repo ui
153 153 for sec, name, val in cfgs:
154 154 req.repo.ui.setconfig(sec, name, val, source='--config')
155 155
156 156 # developer config: ui.debugger
157 157 debugger = ui.config("ui", "debugger")
158 158 debugmod = pdb
159 159 if not debugger or ui.plain():
160 160 # if we are in HGPLAIN mode, then disable custom debugging
161 161 debugger = 'pdb'
162 162 elif '--debugger' in req.args:
163 163 # This import can be slow for fancy debuggers, so only
164 164 # do it when absolutely necessary, i.e. when actual
165 165 # debugging has been requested
166 166 with demandimport.deactivated():
167 167 try:
168 168 debugmod = __import__(debugger)
169 169 except ImportError:
170 170 pass # Leave debugmod = pdb
171 171
172 172 debugtrace[debugger] = debugmod.set_trace
173 173 debugmortem[debugger] = debugmod.post_mortem
174 174
175 175 # enter the debugger before command execution
176 176 if '--debugger' in req.args:
177 177 ui.warn(_("entering debugger - "
178 178 "type c to continue starting hg or h for help\n"))
179 179
180 180 if (debugger != 'pdb' and
181 181 debugtrace[debugger] == debugtrace['pdb']):
182 182 ui.warn(_("%s debugger specified "
183 183 "but its module was not found\n") % debugger)
184 184
185 185 debugtrace[debugger]()
186 186 try:
187 187 return _dispatch(req)
188 188 finally:
189 189 ui.flush()
190 190 except: # re-raises
191 191 # enter the debugger when we hit an exception
192 192 if '--debugger' in req.args:
193 193 traceback.print_exc()
194 194 debugmortem[debugger](sys.exc_info()[2])
195 195 ui.traceback()
196 196 raise
197 197
198 198 # Global exception handling, alphabetically
199 199 # Mercurial-specific first, followed by built-in and library exceptions
200 200 except error.AmbiguousCommand as inst:
201 201 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
202 202 (inst.args[0], " ".join(inst.args[1])))
203 203 except error.ParseError as inst:
204 204 _formatparse(ui.warn, inst)
205 205 return -1
206 206 except error.LockHeld as inst:
207 207 if inst.errno == errno.ETIMEDOUT:
208 208 reason = _('timed out waiting for lock held by %s') % inst.locker
209 209 else:
210 210 reason = _('lock held by %s') % inst.locker
211 211 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
212 212 except error.LockUnavailable as inst:
213 213 ui.warn(_("abort: could not lock %s: %s\n") %
214 214 (inst.desc or inst.filename, inst.strerror))
215 215 except error.CommandError as inst:
216 216 if inst.args[0]:
217 217 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
218 218 commands.help_(ui, inst.args[0], full=False, command=True)
219 219 else:
220 220 ui.warn(_("hg: %s\n") % inst.args[1])
221 221 commands.help_(ui, 'shortlist')
222 222 except error.OutOfBandError as inst:
223 223 if inst.args:
224 224 msg = _("abort: remote error:\n")
225 225 else:
226 226 msg = _("abort: remote error\n")
227 227 ui.warn(msg)
228 228 if inst.args:
229 229 ui.warn(''.join(inst.args))
230 230 if inst.hint:
231 231 ui.warn('(%s)\n' % inst.hint)
232 232 except error.RepoError as inst:
233 233 ui.warn(_("abort: %s!\n") % inst)
234 234 if inst.hint:
235 235 ui.warn(_("(%s)\n") % inst.hint)
236 236 except error.ResponseError as inst:
237 237 ui.warn(_("abort: %s") % inst.args[0])
238 238 if not isinstance(inst.args[1], basestring):
239 239 ui.warn(" %r\n" % (inst.args[1],))
240 240 elif not inst.args[1]:
241 241 ui.warn(_(" empty string\n"))
242 242 else:
243 243 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
244 244 except error.CensoredNodeError as inst:
245 245 ui.warn(_("abort: file censored %s!\n") % inst)
246 246 except error.RevlogError as inst:
247 247 ui.warn(_("abort: %s!\n") % inst)
248 248 except error.SignalInterrupt:
249 249 ui.warn(_("killed!\n"))
250 250 except error.UnknownCommand as inst:
251 251 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
252 252 try:
253 253 # check if the command is in a disabled extension
254 254 # (but don't check for extensions themselves)
255 255 commands.help_(ui, inst.args[0], unknowncmd=True)
256 256 except error.UnknownCommand:
257 257 suggested = False
258 258 if len(inst.args) == 2:
259 259 sim = _getsimilar(inst.args[1], inst.args[0])
260 260 if sim:
261 261 ui.warn(_('(did you mean one of %s?)\n') %
262 262 ', '.join(sorted(sim)))
263 263 suggested = True
264 264 if not suggested:
265 265 commands.help_(ui, 'shortlist')
266 266 except error.InterventionRequired as inst:
267 267 ui.warn("%s\n" % inst)
268 268 return 1
269 269 except util.Abort as inst:
270 270 ui.warn(_("abort: %s\n") % inst)
271 271 if inst.hint:
272 272 ui.warn(_("(%s)\n") % inst.hint)
273 273 except ImportError as inst:
274 274 ui.warn(_("abort: %s!\n") % inst)
275 275 m = str(inst).split()[-1]
276 276 if m in "mpatch bdiff".split():
277 277 ui.warn(_("(did you forget to compile extensions?)\n"))
278 278 elif m in "zlib".split():
279 279 ui.warn(_("(is your Python install correct?)\n"))
280 280 except IOError as inst:
281 281 if util.safehasattr(inst, "code"):
282 282 ui.warn(_("abort: %s\n") % inst)
283 283 elif util.safehasattr(inst, "reason"):
284 284 try: # usually it is in the form (errno, strerror)
285 285 reason = inst.reason.args[1]
286 286 except (AttributeError, IndexError):
287 287 # it might be anything, for example a string
288 288 reason = inst.reason
289 289 if isinstance(reason, unicode):
290 290 # SSLError of Python 2.7.9 contains a unicode
291 291 reason = reason.encode(encoding.encoding, 'replace')
292 292 ui.warn(_("abort: error: %s\n") % reason)
293 293 elif (util.safehasattr(inst, "args")
294 294 and inst.args and inst.args[0] == errno.EPIPE):
295 295 if ui.debugflag:
296 296 ui.warn(_("broken pipe\n"))
297 297 elif getattr(inst, "strerror", None):
298 298 if getattr(inst, "filename", None):
299 299 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
300 300 else:
301 301 ui.warn(_("abort: %s\n") % inst.strerror)
302 302 else:
303 303 raise
304 304 except OSError as inst:
305 305 if getattr(inst, "filename", None) is not None:
306 306 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
307 307 else:
308 308 ui.warn(_("abort: %s\n") % inst.strerror)
309 309 except KeyboardInterrupt:
310 310 try:
311 311 ui.warn(_("interrupted!\n"))
312 312 except IOError as inst:
313 313 if inst.errno == errno.EPIPE:
314 314 if ui.debugflag:
315 315 ui.warn(_("\nbroken pipe\n"))
316 316 else:
317 317 raise
318 318 except MemoryError:
319 319 ui.warn(_("abort: out of memory\n"))
320 320 except SystemExit as inst:
321 321 # Commands shouldn't sys.exit directly, but give a return code.
322 322 # Just in case catch this and and pass exit code to caller.
323 323 return inst.code
324 324 except socket.error as inst:
325 325 ui.warn(_("abort: %s\n") % inst.args[-1])
326 326 except: # re-raises
327 327 myver = util.version()
328 328 # For compatibility checking, we discard the portion of the hg
329 329 # version after the + on the assumption that if a "normal
330 330 # user" is running a build with a + in it the packager
331 331 # probably built from fairly close to a tag and anyone with a
332 332 # 'make local' copy of hg (where the version number can be out
333 333 # of date) will be clueful enough to notice the implausible
334 334 # version number and try updating.
335 335 compare = myver.split('+')[0]
336 336 ct = tuplever(compare)
337 337 worst = None, ct, ''
338 338 for name, mod in extensions.extensions():
339 339 testedwith = getattr(mod, 'testedwith', '')
340 340 report = getattr(mod, 'buglink', _('the extension author.'))
341 341 if not testedwith.strip():
342 342 # We found an untested extension. It's likely the culprit.
343 343 worst = name, 'unknown', report
344 344 break
345 345
346 346 # Never blame on extensions bundled with Mercurial.
347 347 if testedwith == 'internal':
348 348 continue
349 349
350 350 tested = [tuplever(t) for t in testedwith.split()]
351 351 if ct in tested:
352 352 continue
353 353
354 354 lower = [t for t in tested if t < ct]
355 355 nearest = max(lower or tested)
356 356 if worst[0] is None or nearest < worst[1]:
357 357 worst = name, nearest, report
358 358 if worst[0] is not None:
359 359 name, testedwith, report = worst
360 360 if not isinstance(testedwith, str):
361 361 testedwith = '.'.join([str(c) for c in testedwith])
362 362 warning = (_('** Unknown exception encountered with '
363 363 'possibly-broken third-party extension %s\n'
364 364 '** which supports versions %s of Mercurial.\n'
365 365 '** Please disable %s and try your action again.\n'
366 366 '** If that fixes the bug please report it to %s\n')
367 367 % (name, testedwith, name, report))
368 368 else:
369 369 warning = (_("** unknown exception encountered, "
370 370 "please report by visiting\n") +
371 371 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
372 372 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
373 373 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
374 374 (_("** Extensions loaded: %s\n") %
375 375 ", ".join([x[0] for x in extensions.extensions()])))
376 376 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
377 377 ui.warn(warning)
378 378 raise
379 379
380 380 return -1
381 381
382 382 def tuplever(v):
383 383 try:
384 384 # Assertion: tuplever is only used for extension compatibility
385 385 # checking. Otherwise, the discarding of extra version fields is
386 386 # incorrect.
387 387 return tuple([int(i) for i in v.split('.')[0:2]])
388 388 except ValueError:
389 389 return tuple()
390 390
391 391 def aliasargs(fn, givenargs):
392 392 args = getattr(fn, 'args', [])
393 393 if args:
394 394 cmd = ' '.join(map(util.shellquote, args))
395 395
396 396 nums = []
397 397 def replacer(m):
398 398 num = int(m.group(1)) - 1
399 399 nums.append(num)
400 400 if num < len(givenargs):
401 401 return givenargs[num]
402 402 raise util.Abort(_('too few arguments for command alias'))
403 403 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
404 404 givenargs = [x for i, x in enumerate(givenargs)
405 405 if i not in nums]
406 406 args = shlex.split(cmd)
407 407 return args + givenargs
408 408
409 409 def aliasinterpolate(name, args, cmd):
410 410 '''interpolate args into cmd for shell aliases
411 411
412 412 This also handles $0, $@ and "$@".
413 413 '''
414 414 # util.interpolate can't deal with "$@" (with quotes) because it's only
415 415 # built to match prefix + patterns.
416 416 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
417 417 replacemap['$0'] = name
418 418 replacemap['$$'] = '$'
419 419 replacemap['$@'] = ' '.join(args)
420 420 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
421 421 # parameters, separated out into words. Emulate the same behavior here by
422 422 # quoting the arguments individually. POSIX shells will then typically
423 423 # tokenize each argument into exactly one word.
424 424 replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
425 425 # escape '\$' for regex
426 426 regex = '|'.join(replacemap.keys()).replace('$', r'\$')
427 427 r = re.compile(regex)
428 428 return r.sub(lambda x: replacemap[x.group()], cmd)
429 429
430 430 class cmdalias(object):
431 431 def __init__(self, name, definition, cmdtable):
432 432 self.name = self.cmd = name
433 433 self.cmdname = ''
434 434 self.definition = definition
435 435 self.fn = None
436 436 self.args = []
437 437 self.opts = []
438 438 self.help = ''
439 439 self.norepo = True
440 440 self.optionalrepo = False
441 441 self.badalias = None
442 442 self.unknowncmd = False
443 443
444 444 try:
445 445 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
446 446 for alias, e in cmdtable.iteritems():
447 447 if e is entry:
448 448 self.cmd = alias
449 449 break
450 450 self.shadows = True
451 451 except error.UnknownCommand:
452 452 self.shadows = False
453 453
454 454 if not self.definition:
455 455 self.badalias = _("no definition for alias '%s'") % self.name
456 456 return
457 457
458 458 if self.definition.startswith('!'):
459 459 self.shell = True
460 460 def fn(ui, *args):
461 461 env = {'HG_ARGS': ' '.join((self.name,) + args)}
462 462 def _checkvar(m):
463 463 if m.groups()[0] == '$':
464 464 return m.group()
465 465 elif int(m.groups()[0]) <= len(args):
466 466 return m.group()
467 467 else:
468 468 ui.debug("No argument found for substitution "
469 469 "of %i variable in alias '%s' definition."
470 470 % (int(m.groups()[0]), self.name))
471 471 return ''
472 472 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
473 473 cmd = aliasinterpolate(self.name, args, cmd)
474 474 return ui.system(cmd, environ=env)
475 475 self.fn = fn
476 476 return
477 477
478 478 try:
479 479 args = shlex.split(self.definition)
480 480 except ValueError as inst:
481 481 self.badalias = (_("error in definition for alias '%s': %s")
482 482 % (self.name, inst))
483 483 return
484 484 self.cmdname = cmd = args.pop(0)
485 485 args = map(util.expandpath, args)
486 486
487 487 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
488 488 if _earlygetopt([invalidarg], args):
489 489 self.badalias = (_("error in definition for alias '%s': %s may "
490 490 "only be given on the command line")
491 491 % (self.name, invalidarg))
492 492 return
493 493
494 494 try:
495 495 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
496 496 if len(tableentry) > 2:
497 497 self.fn, self.opts, self.help = tableentry
498 498 else:
499 499 self.fn, self.opts = tableentry
500 500
501 501 self.args = aliasargs(self.fn, args)
502 502 if cmd not in commands.norepo.split(' '):
503 503 self.norepo = False
504 504 if cmd in commands.optionalrepo.split(' '):
505 505 self.optionalrepo = True
506 506 if self.help.startswith("hg " + cmd):
507 507 # drop prefix in old-style help lines so hg shows the alias
508 508 self.help = self.help[4 + len(cmd):]
509 509 self.__doc__ = self.fn.__doc__
510 510
511 511 except error.UnknownCommand:
512 512 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
513 513 % (self.name, cmd))
514 514 self.unknowncmd = True
515 515 except error.AmbiguousCommand:
516 516 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
517 517 % (self.name, cmd))
518 518
519 519 def __call__(self, ui, *args, **opts):
520 520 if self.badalias:
521 521 hint = None
522 522 if self.unknowncmd:
523 523 try:
524 524 # check if the command is in a disabled extension
525 525 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
526 526 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
527 527 except error.UnknownCommand:
528 528 pass
529 529 raise util.Abort(self.badalias, hint=hint)
530 530 if self.shadows:
531 531 ui.debug("alias '%s' shadows command '%s'\n" %
532 532 (self.name, self.cmdname))
533 533
534 534 if util.safehasattr(self, 'shell'):
535 535 return self.fn(ui, *args, **opts)
536 536 else:
537 537 try:
538 538 return util.checksignature(self.fn)(ui, *args, **opts)
539 539 except error.SignatureError:
540 540 args = ' '.join([self.cmdname] + self.args)
541 541 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
542 542 raise
543 543
544 544 def addaliases(ui, cmdtable):
545 545 # aliases are processed after extensions have been loaded, so they
546 546 # may use extension commands. Aliases can also use other alias definitions,
547 547 # but only if they have been defined prior to the current definition.
548 548 for alias, definition in ui.configitems('alias'):
549 549 aliasdef = cmdalias(alias, definition, cmdtable)
550 550
551 551 try:
552 552 olddef = cmdtable[aliasdef.cmd][0]
553 553 if olddef.definition == aliasdef.definition:
554 554 continue
555 555 except (KeyError, AttributeError):
556 556 # definition might not exist or it might not be a cmdalias
557 557 pass
558 558
559 559 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
560 560 if aliasdef.norepo:
561 561 commands.norepo += ' %s' % alias
562 562 if aliasdef.optionalrepo:
563 563 commands.optionalrepo += ' %s' % alias
564 564
565 565 def _parse(ui, args):
566 566 options = {}
567 567 cmdoptions = {}
568 568
569 569 try:
570 570 args = fancyopts.fancyopts(args, commands.globalopts, options)
571 571 except fancyopts.getopt.GetoptError as inst:
572 572 raise error.CommandError(None, inst)
573 573
574 574 if args:
575 575 cmd, args = args[0], args[1:]
576 576 aliases, entry = cmdutil.findcmd(cmd, commands.table,
577 577 ui.configbool("ui", "strict"))
578 578 cmd = aliases[0]
579 579 args = aliasargs(entry[0], args)
580 580 defaults = ui.config("defaults", cmd)
581 581 if defaults:
582 582 args = map(util.expandpath, shlex.split(defaults)) + args
583 583 c = list(entry[1])
584 584 else:
585 585 cmd = None
586 586 c = []
587 587
588 588 # combine global options into local
589 589 for o in commands.globalopts:
590 590 c.append((o[0], o[1], options[o[1]], o[3]))
591 591
592 592 try:
593 593 args = fancyopts.fancyopts(args, c, cmdoptions, True)
594 594 except fancyopts.getopt.GetoptError as inst:
595 595 raise error.CommandError(cmd, inst)
596 596
597 597 # separate global options back out
598 598 for o in commands.globalopts:
599 599 n = o[1]
600 600 options[n] = cmdoptions[n]
601 601 del cmdoptions[n]
602 602
603 603 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
604 604
605 605 def _parseconfig(ui, config):
606 606 """parse the --config options from the command line"""
607 607 configs = []
608 608
609 609 for cfg in config:
610 610 try:
611 611 name, value = cfg.split('=', 1)
612 612 section, name = name.split('.', 1)
613 613 if not section or not name:
614 614 raise IndexError
615 615 ui.setconfig(section, name, value, '--config')
616 616 configs.append((section, name, value))
617 617 except (IndexError, ValueError):
618 618 raise util.Abort(_('malformed --config option: %r '
619 619 '(use --config section.name=value)') % cfg)
620 620
621 621 return configs
622 622
623 623 def _earlygetopt(aliases, args):
624 624 """Return list of values for an option (or aliases).
625 625
626 626 The values are listed in the order they appear in args.
627 627 The options and values are removed from args.
628 628
629 629 >>> args = ['x', '--cwd', 'foo', 'y']
630 630 >>> _earlygetopt(['--cwd'], args), args
631 631 (['foo'], ['x', 'y'])
632 632
633 633 >>> args = ['x', '--cwd=bar', 'y']
634 634 >>> _earlygetopt(['--cwd'], args), args
635 635 (['bar'], ['x', 'y'])
636 636
637 637 >>> args = ['x', '-R', 'foo', 'y']
638 638 >>> _earlygetopt(['-R'], args), args
639 639 (['foo'], ['x', 'y'])
640 640
641 641 >>> args = ['x', '-Rbar', 'y']
642 642 >>> _earlygetopt(['-R'], args), args
643 643 (['bar'], ['x', 'y'])
644 644 """
645 645 try:
646 646 argcount = args.index("--")
647 647 except ValueError:
648 648 argcount = len(args)
649 649 shortopts = [opt for opt in aliases if len(opt) == 2]
650 650 values = []
651 651 pos = 0
652 652 while pos < argcount:
653 653 fullarg = arg = args[pos]
654 654 equals = arg.find('=')
655 655 if equals > -1:
656 656 arg = arg[:equals]
657 657 if arg in aliases:
658 658 del args[pos]
659 659 if equals > -1:
660 660 values.append(fullarg[equals + 1:])
661 661 argcount -= 1
662 662 else:
663 663 if pos + 1 >= argcount:
664 664 # ignore and let getopt report an error if there is no value
665 665 break
666 666 values.append(args.pop(pos))
667 667 argcount -= 2
668 668 elif arg[:2] in shortopts:
669 669 # short option can have no following space, e.g. hg log -Rfoo
670 670 values.append(args.pop(pos)[2:])
671 671 argcount -= 1
672 672 else:
673 673 pos += 1
674 674 return values
675 675
676 676 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
677 677 # run pre-hook, and abort if it fails
678 678 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
679 679 pats=cmdpats, opts=cmdoptions)
680 680 ret = _runcommand(ui, options, cmd, d)
681 681 # run post-hook, passing command result
682 682 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
683 683 result=ret, pats=cmdpats, opts=cmdoptions)
684 684 return ret
685 685
686 686 def _getlocal(ui, rpath):
687 687 """Return (path, local ui object) for the given target path.
688 688
689 689 Takes paths in [cwd]/.hg/hgrc into account."
690 690 """
691 691 try:
692 692 wd = os.getcwd()
693 693 except OSError as e:
694 694 raise util.Abort(_("error getting current working directory: %s") %
695 695 e.strerror)
696 696 path = cmdutil.findrepo(wd) or ""
697 697 if not path:
698 698 lui = ui
699 699 else:
700 700 lui = ui.copy()
701 701 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
702 702
703 703 if rpath and rpath[-1]:
704 704 path = lui.expandpath(rpath[-1])
705 705 lui = ui.copy()
706 706 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
707 707
708 708 return path, lui
709 709
710 710 def _checkshellalias(lui, ui, args, precheck=True):
711 711 """Return the function to run the shell alias, if it is required
712 712
713 713 'precheck' is whether this function is invoked before adding
714 714 aliases or not.
715 715 """
716 716 options = {}
717 717
718 718 try:
719 719 args = fancyopts.fancyopts(args, commands.globalopts, options)
720 720 except fancyopts.getopt.GetoptError:
721 721 return
722 722
723 723 if not args:
724 724 return
725 725
726 726 if precheck:
727 727 strict = True
728 728 norepo = commands.norepo
729 729 optionalrepo = commands.optionalrepo
730 730 def restorecommands():
731 731 commands.norepo = norepo
732 732 commands.optionalrepo = optionalrepo
733 733 cmdtable = commands.table.copy()
734 734 addaliases(lui, cmdtable)
735 735 else:
736 736 strict = False
737 737 def restorecommands():
738 738 pass
739 739 cmdtable = commands.table
740 740
741 741 cmd = args[0]
742 742 try:
743 743 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
744 744 except (error.AmbiguousCommand, error.UnknownCommand):
745 745 restorecommands()
746 746 return
747 747
748 748 cmd = aliases[0]
749 749 fn = entry[0]
750 750
751 751 if cmd and util.safehasattr(fn, 'shell'):
752 752 d = lambda: fn(ui, *args[1:])
753 753 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
754 754 [], {})
755 755
756 756 restorecommands()
757 757
758 758 _loaded = set()
759 759 def _dispatch(req):
760 760 args = req.args
761 761 ui = req.ui
762 762
763 763 # check for cwd
764 764 cwd = _earlygetopt(['--cwd'], args)
765 765 if cwd:
766 766 os.chdir(cwd[-1])
767 767
768 768 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
769 769 path, lui = _getlocal(ui, rpath)
770 770
771 771 # Now that we're operating in the right directory/repository with
772 772 # the right config settings, check for shell aliases
773 773 shellaliasfn = _checkshellalias(lui, ui, args)
774 774 if shellaliasfn:
775 775 return shellaliasfn()
776 776
777 777 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
778 778 # reposetup. Programs like TortoiseHg will call _dispatch several
779 779 # times so we keep track of configured extensions in _loaded.
780 780 extensions.loadall(lui)
781 781 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
782 782 # Propagate any changes to lui.__class__ by extensions
783 783 ui.__class__ = lui.__class__
784 784
785 785 # (uisetup and extsetup are handled in extensions.loadall)
786 786
787 787 for name, module in exts:
788 788 cmdtable = getattr(module, 'cmdtable', {})
789 789 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
790 790 if overrides:
791 791 ui.warn(_("extension '%s' overrides commands: %s\n")
792 792 % (name, " ".join(overrides)))
793 793 commands.table.update(cmdtable)
794 794 _loaded.add(name)
795 795
796 796 # (reposetup is handled in hg.repository)
797 797
798 798 addaliases(lui, commands.table)
799 799
800 800 if not lui.configbool("ui", "strict"):
801 801 # All aliases and commands are completely defined, now.
802 802 # Check abbreviation/ambiguity of shell alias again, because shell
803 803 # alias may cause failure of "_parse" (see issue4355)
804 804 shellaliasfn = _checkshellalias(lui, ui, args, precheck=False)
805 805 if shellaliasfn:
806 806 return shellaliasfn()
807 807
808 808 # check for fallback encoding
809 809 fallback = lui.config('ui', 'fallbackencoding')
810 810 if fallback:
811 811 encoding.fallbackencoding = fallback
812 812
813 813 fullargs = args
814 814 cmd, func, args, options, cmdoptions = _parse(lui, args)
815 815
816 816 if options["config"]:
817 817 raise util.Abort(_("option --config may not be abbreviated!"))
818 818 if options["cwd"]:
819 819 raise util.Abort(_("option --cwd may not be abbreviated!"))
820 820 if options["repository"]:
821 821 raise util.Abort(_(
822 822 "option -R has to be separated from other options (e.g. not -qR) "
823 823 "and --repository may only be abbreviated as --repo!"))
824 824
825 825 if options["encoding"]:
826 826 encoding.encoding = options["encoding"]
827 827 if options["encodingmode"]:
828 828 encoding.encodingmode = options["encodingmode"]
829 829 if options["time"]:
830 830 def get_times():
831 831 t = os.times()
832 832 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
833 833 t = (t[0], t[1], t[2], t[3], time.clock())
834 834 return t
835 835 s = get_times()
836 836 def print_time():
837 837 t = get_times()
838 838 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
839 839 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
840 840 atexit.register(print_time)
841 841
842 842 uis = set([ui, lui])
843 843
844 844 if req.repo:
845 845 uis.add(req.repo.ui)
846 846
847 847 if options['verbose'] or options['debug'] or options['quiet']:
848 848 for opt in ('verbose', 'debug', 'quiet'):
849 849 val = str(bool(options[opt]))
850 850 for ui_ in uis:
851 851 ui_.setconfig('ui', opt, val, '--' + opt)
852 852
853 853 if options['traceback']:
854 854 for ui_ in uis:
855 855 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
856 856
857 857 if options['noninteractive']:
858 858 for ui_ in uis:
859 859 ui_.setconfig('ui', 'interactive', 'off', '-y')
860 860
861 861 if cmdoptions.get('insecure', False):
862 862 for ui_ in uis:
863 863 ui_.setconfig('web', 'cacerts', '!', '--insecure')
864 864
865 865 if options['version']:
866 866 return commands.version_(ui)
867 867 if options['help']:
868 868 return commands.help_(ui, cmd, command=True)
869 869 elif not cmd:
870 870 return commands.help_(ui, 'shortlist')
871 871
872 872 repo = None
873 873 cmdpats = args[:]
874 874 if cmd not in commands.norepo.split():
875 875 # use the repo from the request only if we don't have -R
876 876 if not rpath and not cwd:
877 877 repo = req.repo
878 878
879 879 if repo:
880 880 # set the descriptors of the repo ui to those of ui
881 881 repo.ui.fin = ui.fin
882 882 repo.ui.fout = ui.fout
883 883 repo.ui.ferr = ui.ferr
884 884 else:
885 885 try:
886 886 repo = hg.repository(ui, path=path)
887 887 if not repo.local():
888 888 raise util.Abort(_("repository '%s' is not local") % path)
889 889 repo.ui.setconfig("bundle", "mainreporoot", repo.root, 'repo')
890 890 except error.RequirementError:
891 891 raise
892 892 except error.RepoError:
893 if rpath and rpath[-1]: # invalid -R path
894 raise
893 895 if cmd not in commands.optionalrepo.split():
894 896 if (cmd in commands.inferrepo.split() and
895 897 args and not path): # try to infer -R from command args
896 898 repos = map(cmdutil.findrepo, args)
897 899 guess = repos[0]
898 900 if guess and repos.count(guess) == len(repos):
899 901 req.args = ['--repository', guess] + fullargs
900 902 return _dispatch(req)
901 903 if not path:
902 904 raise error.RepoError(_("no repository found in '%s'"
903 905 " (.hg not found)")
904 906 % os.getcwd())
905 907 raise
906 908 if repo:
907 909 ui = repo.ui
908 910 if options['hidden']:
909 911 repo = repo.unfiltered()
910 912 args.insert(0, repo)
911 913 elif rpath:
912 914 ui.warn(_("warning: --repository ignored\n"))
913 915
914 916 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
915 917 ui.log("command", '%s\n', msg)
916 918 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
917 919 try:
918 920 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
919 921 cmdpats, cmdoptions)
920 922 finally:
921 923 if repo and repo != req.repo:
922 924 repo.close()
923 925
924 926 def lsprofile(ui, func, fp):
925 927 format = ui.config('profiling', 'format', default='text')
926 928 field = ui.config('profiling', 'sort', default='inlinetime')
927 929 limit = ui.configint('profiling', 'limit', default=30)
928 930 climit = ui.configint('profiling', 'nested', default=0)
929 931
930 932 if format not in ['text', 'kcachegrind']:
931 933 ui.warn(_("unrecognized profiling format '%s'"
932 934 " - Ignored\n") % format)
933 935 format = 'text'
934 936
935 937 try:
936 938 from . import lsprof
937 939 except ImportError:
938 940 raise util.Abort(_(
939 941 'lsprof not available - install from '
940 942 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
941 943 p = lsprof.Profiler()
942 944 p.enable(subcalls=True)
943 945 try:
944 946 return func()
945 947 finally:
946 948 p.disable()
947 949
948 950 if format == 'kcachegrind':
949 951 from . import lsprofcalltree
950 952 calltree = lsprofcalltree.KCacheGrind(p)
951 953 calltree.output(fp)
952 954 else:
953 955 # format == 'text'
954 956 stats = lsprof.Stats(p.getstats())
955 957 stats.sort(field)
956 958 stats.pprint(limit=limit, file=fp, climit=climit)
957 959
958 960 def flameprofile(ui, func, fp):
959 961 try:
960 962 from flamegraph import flamegraph
961 963 except ImportError:
962 964 raise util.Abort(_(
963 965 'flamegraph not available - install from '
964 966 'https://github.com/evanhempel/python-flamegraph'))
965 967 # developer config: profiling.freq
966 968 freq = ui.configint('profiling', 'freq', default=1000)
967 969 filter_ = None
968 970 collapse_recursion = True
969 971 thread = flamegraph.ProfileThread(fp, 1.0 / freq,
970 972 filter_, collapse_recursion)
971 973 start_time = time.clock()
972 974 try:
973 975 thread.start()
974 976 func()
975 977 finally:
976 978 thread.stop()
977 979 thread.join()
978 980 print 'Collected %d stack frames (%d unique) in %2.2f seconds.' % (
979 981 time.clock() - start_time, thread.num_frames(),
980 982 thread.num_frames(unique=True))
981 983
982 984
983 985 def statprofile(ui, func, fp):
984 986 try:
985 987 import statprof
986 988 except ImportError:
987 989 raise util.Abort(_(
988 990 'statprof not available - install using "easy_install statprof"'))
989 991
990 992 freq = ui.configint('profiling', 'freq', default=1000)
991 993 if freq > 0:
992 994 statprof.reset(freq)
993 995 else:
994 996 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
995 997
996 998 statprof.start()
997 999 try:
998 1000 return func()
999 1001 finally:
1000 1002 statprof.stop()
1001 1003 statprof.display(fp)
1002 1004
1003 1005 def _runcommand(ui, options, cmd, cmdfunc):
1004 1006 def checkargs():
1005 1007 try:
1006 1008 return cmdfunc()
1007 1009 except error.SignatureError:
1008 1010 raise error.CommandError(cmd, _("invalid arguments"))
1009 1011
1010 1012 if options['profile']:
1011 1013 profiler = os.getenv('HGPROF')
1012 1014 if profiler is None:
1013 1015 profiler = ui.config('profiling', 'type', default='ls')
1014 1016 if profiler not in ('ls', 'stat', 'flame'):
1015 1017 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
1016 1018 profiler = 'ls'
1017 1019
1018 1020 output = ui.config('profiling', 'output')
1019 1021
1020 1022 if output:
1021 1023 path = ui.expandpath(output)
1022 1024 fp = open(path, 'wb')
1023 1025 else:
1024 1026 fp = sys.stderr
1025 1027
1026 1028 try:
1027 1029 if profiler == 'ls':
1028 1030 return lsprofile(ui, checkargs, fp)
1029 1031 elif profiler == 'flame':
1030 1032 return flameprofile(ui, checkargs, fp)
1031 1033 else:
1032 1034 return statprofile(ui, checkargs, fp)
1033 1035 finally:
1034 1036 if output:
1035 1037 fp.close()
1036 1038 else:
1037 1039 return checkargs()
@@ -1,1027 +1,1027 b''
1 1 Prepare repo a:
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo a > a
6 6 $ hg add a
7 7 $ hg commit -m test
8 8 $ echo first line > b
9 9 $ hg add b
10 10
11 11 Create a non-inlined filelog:
12 12
13 13 $ $PYTHON -c 'file("data1", "wb").write("".join("%s\n" % x for x in range(10000)))'
14 14 $ for j in 0 1 2 3 4 5 6 7 8 9; do
15 15 > cat data1 >> b
16 16 > hg commit -m test
17 17 > done
18 18
19 19 List files in store/data (should show a 'b.d'):
20 20
21 21 $ for i in .hg/store/data/*; do
22 22 > echo $i
23 23 > done
24 24 .hg/store/data/a.i
25 25 .hg/store/data/b.d
26 26 .hg/store/data/b.i
27 27
28 28 Trigger branchcache creation:
29 29
30 30 $ hg branches
31 31 default 10:a7949464abda
32 32 $ ls .hg/cache
33 33 branch2-served
34 34 rbc-names-v1
35 35 rbc-revs-v1
36 36
37 37 Default operation:
38 38
39 39 $ hg clone . ../b
40 40 updating to branch default
41 41 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 42 $ cd ../b
43 43
44 44 Ensure branchcache got copied over:
45 45
46 46 $ ls .hg/cache
47 47 branch2-served
48 48
49 49 $ cat a
50 50 a
51 51 $ hg verify
52 52 checking changesets
53 53 checking manifests
54 54 crosschecking files in changesets and manifests
55 55 checking files
56 56 2 files, 11 changesets, 11 total revisions
57 57
58 58 Invalid dest '' must abort:
59 59
60 60 $ hg clone . ''
61 61 abort: empty destination path is not valid
62 62 [255]
63 63
64 64 No update, with debug option:
65 65
66 66 #if hardlink
67 67 $ hg --debug clone -U . ../c --config progress.debug=true
68 68 linking: 1
69 69 linking: 2
70 70 linking: 3
71 71 linking: 4
72 72 linking: 5
73 73 linking: 6
74 74 linking: 7
75 75 linking: 8
76 76 linked 8 files
77 77 #else
78 78 $ hg --debug clone -U . ../c --config progress.debug=true
79 79 linking: 1
80 80 copying: 2
81 81 copying: 3
82 82 copying: 4
83 83 copying: 5
84 84 copying: 6
85 85 copying: 7
86 86 copying: 8
87 87 copied 8 files
88 88 #endif
89 89 $ cd ../c
90 90
91 91 Ensure branchcache got copied over:
92 92
93 93 $ ls .hg/cache
94 94 branch2-served
95 95
96 96 $ cat a 2>/dev/null || echo "a not present"
97 97 a not present
98 98 $ hg verify
99 99 checking changesets
100 100 checking manifests
101 101 crosschecking files in changesets and manifests
102 102 checking files
103 103 2 files, 11 changesets, 11 total revisions
104 104
105 105 Default destination:
106 106
107 107 $ mkdir ../d
108 108 $ cd ../d
109 109 $ hg clone ../a
110 110 destination directory: a
111 111 updating to branch default
112 112 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 113 $ cd a
114 114 $ hg cat a
115 115 a
116 116 $ cd ../..
117 117
118 118 Check that we drop the 'file:' from the path before writing the .hgrc:
119 119
120 120 $ hg clone file:a e
121 121 updating to branch default
122 122 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 123 $ grep 'file:' e/.hg/hgrc
124 124 [1]
125 125
126 126 Check that path aliases are expanded:
127 127
128 128 $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
129 129 $ hg -R f showconfig paths.default
130 130 $TESTTMP/a#0 (glob)
131 131
132 132 Use --pull:
133 133
134 134 $ hg clone --pull a g
135 135 requesting all changes
136 136 adding changesets
137 137 adding manifests
138 138 adding file changes
139 139 added 11 changesets with 11 changes to 2 files
140 140 updating to branch default
141 141 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 142 $ hg -R g verify
143 143 checking changesets
144 144 checking manifests
145 145 crosschecking files in changesets and manifests
146 146 checking files
147 147 2 files, 11 changesets, 11 total revisions
148 148
149 149 Invalid dest '' with --pull must abort (issue2528):
150 150
151 151 $ hg clone --pull a ''
152 152 abort: empty destination path is not valid
153 153 [255]
154 154
155 155 Clone to '.':
156 156
157 157 $ mkdir h
158 158 $ cd h
159 159 $ hg clone ../a .
160 160 updating to branch default
161 161 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 162 $ cd ..
163 163
164 164
165 165 *** Tests for option -u ***
166 166
167 167 Adding some more history to repo a:
168 168
169 169 $ cd a
170 170 $ hg tag ref1
171 171 $ echo the quick brown fox >a
172 172 $ hg ci -m "hacked default"
173 173 $ hg up ref1
174 174 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
175 175 $ hg branch stable
176 176 marked working directory as branch stable
177 177 (branches are permanent and global, did you want a bookmark?)
178 178 $ echo some text >a
179 179 $ hg ci -m "starting branch stable"
180 180 $ hg tag ref2
181 181 $ echo some more text >a
182 182 $ hg ci -m "another change for branch stable"
183 183 $ hg up ref2
184 184 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
185 185 $ hg parents
186 186 changeset: 13:e8ece76546a6
187 187 branch: stable
188 188 tag: ref2
189 189 parent: 10:a7949464abda
190 190 user: test
191 191 date: Thu Jan 01 00:00:00 1970 +0000
192 192 summary: starting branch stable
193 193
194 194
195 195 Repo a has two heads:
196 196
197 197 $ hg heads
198 198 changeset: 15:0aae7cf88f0d
199 199 branch: stable
200 200 tag: tip
201 201 user: test
202 202 date: Thu Jan 01 00:00:00 1970 +0000
203 203 summary: another change for branch stable
204 204
205 205 changeset: 12:f21241060d6a
206 206 user: test
207 207 date: Thu Jan 01 00:00:00 1970 +0000
208 208 summary: hacked default
209 209
210 210
211 211 $ cd ..
212 212
213 213
214 214 Testing --noupdate with --updaterev (must abort):
215 215
216 216 $ hg clone --noupdate --updaterev 1 a ua
217 217 abort: cannot specify both --noupdate and --updaterev
218 218 [255]
219 219
220 220
221 221 Testing clone -u:
222 222
223 223 $ hg clone -u . a ua
224 224 updating to branch stable
225 225 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 226
227 227 Repo ua has both heads:
228 228
229 229 $ hg -R ua heads
230 230 changeset: 15:0aae7cf88f0d
231 231 branch: stable
232 232 tag: tip
233 233 user: test
234 234 date: Thu Jan 01 00:00:00 1970 +0000
235 235 summary: another change for branch stable
236 236
237 237 changeset: 12:f21241060d6a
238 238 user: test
239 239 date: Thu Jan 01 00:00:00 1970 +0000
240 240 summary: hacked default
241 241
242 242
243 243 Same revision checked out in repo a and ua:
244 244
245 245 $ hg -R a parents --template "{node|short}\n"
246 246 e8ece76546a6
247 247 $ hg -R ua parents --template "{node|short}\n"
248 248 e8ece76546a6
249 249
250 250 $ rm -r ua
251 251
252 252
253 253 Testing clone --pull -u:
254 254
255 255 $ hg clone --pull -u . a ua
256 256 requesting all changes
257 257 adding changesets
258 258 adding manifests
259 259 adding file changes
260 260 added 16 changesets with 16 changes to 3 files (+1 heads)
261 261 updating to branch stable
262 262 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 263
264 264 Repo ua has both heads:
265 265
266 266 $ hg -R ua heads
267 267 changeset: 15:0aae7cf88f0d
268 268 branch: stable
269 269 tag: tip
270 270 user: test
271 271 date: Thu Jan 01 00:00:00 1970 +0000
272 272 summary: another change for branch stable
273 273
274 274 changeset: 12:f21241060d6a
275 275 user: test
276 276 date: Thu Jan 01 00:00:00 1970 +0000
277 277 summary: hacked default
278 278
279 279
280 280 Same revision checked out in repo a and ua:
281 281
282 282 $ hg -R a parents --template "{node|short}\n"
283 283 e8ece76546a6
284 284 $ hg -R ua parents --template "{node|short}\n"
285 285 e8ece76546a6
286 286
287 287 $ rm -r ua
288 288
289 289
290 290 Testing clone -u <branch>:
291 291
292 292 $ hg clone -u stable a ua
293 293 updating to branch stable
294 294 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 295
296 296 Repo ua has both heads:
297 297
298 298 $ hg -R ua heads
299 299 changeset: 15:0aae7cf88f0d
300 300 branch: stable
301 301 tag: tip
302 302 user: test
303 303 date: Thu Jan 01 00:00:00 1970 +0000
304 304 summary: another change for branch stable
305 305
306 306 changeset: 12:f21241060d6a
307 307 user: test
308 308 date: Thu Jan 01 00:00:00 1970 +0000
309 309 summary: hacked default
310 310
311 311
312 312 Branch 'stable' is checked out:
313 313
314 314 $ hg -R ua parents
315 315 changeset: 15:0aae7cf88f0d
316 316 branch: stable
317 317 tag: tip
318 318 user: test
319 319 date: Thu Jan 01 00:00:00 1970 +0000
320 320 summary: another change for branch stable
321 321
322 322
323 323 $ rm -r ua
324 324
325 325
326 326 Testing default checkout:
327 327
328 328 $ hg clone a ua
329 329 updating to branch default
330 330 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
331 331
332 332 Repo ua has both heads:
333 333
334 334 $ hg -R ua heads
335 335 changeset: 15:0aae7cf88f0d
336 336 branch: stable
337 337 tag: tip
338 338 user: test
339 339 date: Thu Jan 01 00:00:00 1970 +0000
340 340 summary: another change for branch stable
341 341
342 342 changeset: 12:f21241060d6a
343 343 user: test
344 344 date: Thu Jan 01 00:00:00 1970 +0000
345 345 summary: hacked default
346 346
347 347
348 348 Branch 'default' is checked out:
349 349
350 350 $ hg -R ua parents
351 351 changeset: 12:f21241060d6a
352 352 user: test
353 353 date: Thu Jan 01 00:00:00 1970 +0000
354 354 summary: hacked default
355 355
356 356 Test clone with a branch named "@" (issue3677)
357 357
358 358 $ hg -R ua branch @
359 359 marked working directory as branch @
360 360 $ hg -R ua commit -m 'created branch @'
361 361 $ hg clone ua atbranch
362 362 updating to branch default
363 363 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
364 364 $ hg -R atbranch heads
365 365 changeset: 16:798b6d97153e
366 366 branch: @
367 367 tag: tip
368 368 parent: 12:f21241060d6a
369 369 user: test
370 370 date: Thu Jan 01 00:00:00 1970 +0000
371 371 summary: created branch @
372 372
373 373 changeset: 15:0aae7cf88f0d
374 374 branch: stable
375 375 user: test
376 376 date: Thu Jan 01 00:00:00 1970 +0000
377 377 summary: another change for branch stable
378 378
379 379 changeset: 12:f21241060d6a
380 380 user: test
381 381 date: Thu Jan 01 00:00:00 1970 +0000
382 382 summary: hacked default
383 383
384 384 $ hg -R atbranch parents
385 385 changeset: 12:f21241060d6a
386 386 user: test
387 387 date: Thu Jan 01 00:00:00 1970 +0000
388 388 summary: hacked default
389 389
390 390
391 391 $ rm -r ua atbranch
392 392
393 393
394 394 Testing #<branch>:
395 395
396 396 $ hg clone -u . a#stable ua
397 397 adding changesets
398 398 adding manifests
399 399 adding file changes
400 400 added 14 changesets with 14 changes to 3 files
401 401 updating to branch stable
402 402 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 403
404 404 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
405 405
406 406 $ hg -R ua heads
407 407 changeset: 13:0aae7cf88f0d
408 408 branch: stable
409 409 tag: tip
410 410 user: test
411 411 date: Thu Jan 01 00:00:00 1970 +0000
412 412 summary: another change for branch stable
413 413
414 414 changeset: 10:a7949464abda
415 415 user: test
416 416 date: Thu Jan 01 00:00:00 1970 +0000
417 417 summary: test
418 418
419 419
420 420 Same revision checked out in repo a and ua:
421 421
422 422 $ hg -R a parents --template "{node|short}\n"
423 423 e8ece76546a6
424 424 $ hg -R ua parents --template "{node|short}\n"
425 425 e8ece76546a6
426 426
427 427 $ rm -r ua
428 428
429 429
430 430 Testing -u -r <branch>:
431 431
432 432 $ hg clone -u . -r stable a ua
433 433 adding changesets
434 434 adding manifests
435 435 adding file changes
436 436 added 14 changesets with 14 changes to 3 files
437 437 updating to branch stable
438 438 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
439 439
440 440 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
441 441
442 442 $ hg -R ua heads
443 443 changeset: 13:0aae7cf88f0d
444 444 branch: stable
445 445 tag: tip
446 446 user: test
447 447 date: Thu Jan 01 00:00:00 1970 +0000
448 448 summary: another change for branch stable
449 449
450 450 changeset: 10:a7949464abda
451 451 user: test
452 452 date: Thu Jan 01 00:00:00 1970 +0000
453 453 summary: test
454 454
455 455
456 456 Same revision checked out in repo a and ua:
457 457
458 458 $ hg -R a parents --template "{node|short}\n"
459 459 e8ece76546a6
460 460 $ hg -R ua parents --template "{node|short}\n"
461 461 e8ece76546a6
462 462
463 463 $ rm -r ua
464 464
465 465
466 466 Testing -r <branch>:
467 467
468 468 $ hg clone -r stable a ua
469 469 adding changesets
470 470 adding manifests
471 471 adding file changes
472 472 added 14 changesets with 14 changes to 3 files
473 473 updating to branch stable
474 474 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 475
476 476 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
477 477
478 478 $ hg -R ua heads
479 479 changeset: 13:0aae7cf88f0d
480 480 branch: stable
481 481 tag: tip
482 482 user: test
483 483 date: Thu Jan 01 00:00:00 1970 +0000
484 484 summary: another change for branch stable
485 485
486 486 changeset: 10:a7949464abda
487 487 user: test
488 488 date: Thu Jan 01 00:00:00 1970 +0000
489 489 summary: test
490 490
491 491
492 492 Branch 'stable' is checked out:
493 493
494 494 $ hg -R ua parents
495 495 changeset: 13:0aae7cf88f0d
496 496 branch: stable
497 497 tag: tip
498 498 user: test
499 499 date: Thu Jan 01 00:00:00 1970 +0000
500 500 summary: another change for branch stable
501 501
502 502
503 503 $ rm -r ua
504 504
505 505
506 506 Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
507 507 iterable in addbranchrevs()
508 508
509 509 $ cat <<EOF > simpleclone.py
510 510 > from mercurial import ui, hg
511 511 > myui = ui.ui()
512 512 > repo = hg.repository(myui, 'a')
513 513 > hg.clone(myui, {}, repo, dest="ua")
514 514 > EOF
515 515
516 516 $ python simpleclone.py
517 517 updating to branch default
518 518 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
519 519
520 520 $ rm -r ua
521 521
522 522 $ cat <<EOF > branchclone.py
523 523 > from mercurial import ui, hg, extensions
524 524 > myui = ui.ui()
525 525 > extensions.loadall(myui)
526 526 > repo = hg.repository(myui, 'a')
527 527 > hg.clone(myui, {}, repo, dest="ua", branch=["stable",])
528 528 > EOF
529 529
530 530 $ python branchclone.py
531 531 adding changesets
532 532 adding manifests
533 533 adding file changes
534 534 added 14 changesets with 14 changes to 3 files
535 535 updating to branch stable
536 536 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
537 537 $ rm -r ua
538 538
539 539
540 540 Test clone with special '@' bookmark:
541 541 $ cd a
542 542 $ hg bookmark -r a7949464abda @ # branch point of stable from default
543 543 $ hg clone . ../i
544 544 updating to bookmark @
545 545 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
546 546 $ hg id -i ../i
547 547 a7949464abda
548 548 $ rm -r ../i
549 549
550 550 $ hg bookmark -f -r stable @
551 551 $ hg bookmarks
552 552 @ 15:0aae7cf88f0d
553 553 $ hg clone . ../i
554 554 updating to bookmark @ on branch stable
555 555 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 556 $ hg id -i ../i
557 557 0aae7cf88f0d
558 558 $ cd "$TESTTMP"
559 559
560 560
561 561 Testing failures:
562 562
563 563 $ mkdir fail
564 564 $ cd fail
565 565
566 566 No local source
567 567
568 568 $ hg clone a b
569 569 abort: repository a not found!
570 570 [255]
571 571
572 572 No remote source
573 573
574 574 #if windows
575 575 $ hg clone http://127.0.0.1:3121/a b
576 576 abort: error: * (glob)
577 577 [255]
578 578 #else
579 579 $ hg clone http://127.0.0.1:3121/a b
580 580 abort: error: *refused* (glob)
581 581 [255]
582 582 #endif
583 583 $ rm -rf b # work around bug with http clone
584 584
585 585
586 586 #if unix-permissions no-root
587 587
588 588 Inaccessible source
589 589
590 590 $ mkdir a
591 591 $ chmod 000 a
592 592 $ hg clone a b
593 593 abort: repository a not found!
594 594 [255]
595 595
596 596 Inaccessible destination
597 597
598 598 $ hg init b
599 599 $ cd b
600 600 $ hg clone . ../a
601 601 abort: Permission denied: '../a'
602 602 [255]
603 603 $ cd ..
604 604 $ chmod 700 a
605 605 $ rm -r a b
606 606
607 607 #endif
608 608
609 609
610 610 #if fifo
611 611
612 612 Source of wrong type
613 613
614 614 $ mkfifo a
615 615 $ hg clone a b
616 616 abort: repository a not found!
617 617 [255]
618 618 $ rm a
619 619
620 620 #endif
621 621
622 622 Default destination, same directory
623 623
624 624 $ hg init q
625 625 $ hg clone q
626 626 destination directory: q
627 627 abort: destination 'q' is not empty
628 628 [255]
629 629
630 630 destination directory not empty
631 631
632 632 $ mkdir a
633 633 $ echo stuff > a/a
634 634 $ hg clone q a
635 635 abort: destination 'a' is not empty
636 636 [255]
637 637
638 638
639 639 #if unix-permissions no-root
640 640
641 641 leave existing directory in place after clone failure
642 642
643 643 $ hg init c
644 644 $ cd c
645 645 $ echo c > c
646 646 $ hg commit -A -m test
647 647 adding c
648 648 $ chmod -rx .hg/store/data
649 649 $ cd ..
650 650 $ mkdir d
651 651 $ hg clone c d 2> err
652 652 [255]
653 653 $ test -d d
654 654 $ test -d d/.hg
655 655 [1]
656 656
657 657 re-enable perm to allow deletion
658 658
659 659 $ chmod +rx c/.hg/store/data
660 660
661 661 #endif
662 662
663 663 $ cd ..
664 664
665 665 Test clone from the repository in (emulated) revlog format 0 (issue4203):
666 666
667 667 $ mkdir issue4203
668 668 $ mkdir -p src/.hg
669 669 $ echo foo > src/foo
670 670 $ hg -R src add src/foo
671 671 $ hg -R src commit -m '#0'
672 672 $ hg -R src log -q
673 673 0:e1bab28bca43
674 674 $ hg clone -U -q src dst
675 675 $ hg -R dst log -q
676 676 0:e1bab28bca43
677 677
678 678 Create repositories to test auto sharing functionality
679 679
680 680 $ cat >> $HGRCPATH << EOF
681 681 > [extensions]
682 682 > share=
683 683 > EOF
684 684
685 685 $ hg init empty
686 686 $ hg init source1a
687 687 $ cd source1a
688 688 $ echo initial1 > foo
689 689 $ hg -q commit -A -m initial
690 690 $ echo second > foo
691 691 $ hg commit -m second
692 692 $ cd ..
693 693
694 694 $ hg init filteredrev0
695 695 $ cd filteredrev0
696 696 $ cat >> .hg/hgrc << EOF
697 697 > [experimental]
698 698 > evolution=createmarkers
699 699 > EOF
700 700 $ echo initial1 > foo
701 701 $ hg -q commit -A -m initial0
702 702 $ hg -q up -r null
703 703 $ echo initial2 > foo
704 704 $ hg -q commit -A -m initial1
705 705 $ hg debugobsolete c05d5c47a5cf81401869999f3d05f7d699d2b29a e082c1832e09a7d1e78b7fd49a592d372de854c8
706 706 $ cd ..
707 707
708 708 $ hg -q clone --pull source1a source1b
709 709 $ cd source1a
710 710 $ hg bookmark bookA
711 711 $ echo 1a > foo
712 712 $ hg commit -m 1a
713 713 $ cd ../source1b
714 714 $ hg -q up -r 0
715 715 $ echo head1 > foo
716 716 $ hg commit -m head1
717 717 created new head
718 718 $ hg bookmark head1
719 719 $ hg -q up -r 0
720 720 $ echo head2 > foo
721 721 $ hg commit -m head2
722 722 created new head
723 723 $ hg bookmark head2
724 724 $ hg -q up -r 0
725 725 $ hg branch branch1
726 726 marked working directory as branch branch1
727 727 (branches are permanent and global, did you want a bookmark?)
728 728 $ echo branch1 > foo
729 729 $ hg commit -m branch1
730 730 $ hg -q up -r 0
731 731 $ hg branch branch2
732 732 marked working directory as branch branch2
733 733 $ echo branch2 > foo
734 734 $ hg commit -m branch2
735 735 $ cd ..
736 736 $ hg init source2
737 737 $ cd source2
738 738 $ echo initial2 > foo
739 739 $ hg -q commit -A -m initial2
740 740 $ echo second > foo
741 741 $ hg commit -m second
742 742 $ cd ..
743 743
744 744 Clone with auto share from an empty repo should not result in share
745 745
746 746 $ mkdir share
747 747 $ hg --config share.pool=share clone empty share-empty
748 748 (not using pooled storage: remote appears to be empty)
749 749 updating to branch default
750 750 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
751 751 $ ls share
752 752 $ test -d share-empty/.hg/store
753 753 $ test -f share-empty/.hg/sharedpath
754 754 [1]
755 755
756 756 Clone with auto share from a repo with filtered revision 0 should not result in share
757 757
758 758 $ hg --config share.pool=share clone filteredrev0 share-filtered
759 759 (not using pooled storage: unable to resolve identity of remote)
760 760 requesting all changes
761 761 adding changesets
762 762 adding manifests
763 763 adding file changes
764 764 added 1 changesets with 1 changes to 1 files
765 765 updating to branch default
766 766 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
767 767
768 768 Clone from repo with content should result in shared store being created
769 769
770 770 $ hg --config share.pool=share clone source1a share-dest1a
771 771 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
772 772 requesting all changes
773 773 adding changesets
774 774 adding manifests
775 775 adding file changes
776 776 added 3 changesets with 3 changes to 1 files
777 777 updating working directory
778 778 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
779 779 searching for changes
780 780 no changes found
781 781 adding remote bookmark bookA
782 782
783 783 The shared repo should have been created
784 784
785 785 $ ls share
786 786 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
787 787
788 788 The destination should point to it
789 789
790 790 $ cat share-dest1a/.hg/sharedpath; echo
791 791 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg (glob)
792 792
793 793 The destination should have bookmarks
794 794
795 795 $ hg -R share-dest1a bookmarks
796 796 bookA 2:e5bfe23c0b47
797 797
798 798 The default path should be the remote, not the share
799 799
800 800 $ hg -R share-dest1a config paths.default
801 801 $TESTTMP/source1a (glob)
802 802
803 803 Clone with existing share dir should result in pull + share
804 804
805 805 $ hg --config share.pool=share clone source1b share-dest1b
806 806 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
807 807 updating working directory
808 808 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
809 809 searching for changes
810 810 adding changesets
811 811 adding manifests
812 812 adding file changes
813 813 added 4 changesets with 4 changes to 1 files (+4 heads)
814 814 adding remote bookmark head1
815 815 adding remote bookmark head2
816 816
817 817 $ ls share
818 818 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
819 819
820 820 $ cat share-dest1b/.hg/sharedpath; echo
821 821 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg (glob)
822 822
823 823 We only get bookmarks from the remote, not everything in the share
824 824
825 825 $ hg -R share-dest1b bookmarks
826 826 head1 3:4a8dc1ab4c13
827 827 head2 4:99f71071f117
828 828
829 829 Default path should be source, not share.
830 830
831 831 $ hg -R share-dest1b config paths.default
832 832 $TESTTMP/source1a (glob)
833 833
834 834 Clone from unrelated repo should result in new share
835 835
836 836 $ hg --config share.pool=share clone source2 share-dest2
837 837 (sharing from new pooled repository 22aeff664783fd44c6d9b435618173c118c3448e)
838 838 requesting all changes
839 839 adding changesets
840 840 adding manifests
841 841 adding file changes
842 842 added 2 changesets with 2 changes to 1 files
843 843 updating working directory
844 844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 845 searching for changes
846 846 no changes found
847 847
848 848 $ ls share
849 849 22aeff664783fd44c6d9b435618173c118c3448e
850 850 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
851 851
852 852 remote naming mode works as advertised
853 853
854 854 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1a share-remote1a
855 855 (sharing from new pooled repository 195bb1fcdb595c14a6c13e0269129ed78f6debde)
856 856 requesting all changes
857 857 adding changesets
858 858 adding manifests
859 859 adding file changes
860 860 added 3 changesets with 3 changes to 1 files
861 861 updating working directory
862 862 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
863 863 searching for changes
864 864 no changes found
865 865 adding remote bookmark bookA
866 866
867 867 $ ls shareremote
868 868 195bb1fcdb595c14a6c13e0269129ed78f6debde
869 869
870 870 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1b share-remote1b
871 871 (sharing from new pooled repository c0d4f83847ca2a873741feb7048a45085fd47c46)
872 872 requesting all changes
873 873 adding changesets
874 874 adding manifests
875 875 adding file changes
876 876 added 6 changesets with 6 changes to 1 files (+4 heads)
877 877 updating working directory
878 878 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
879 879 searching for changes
880 880 no changes found
881 881 adding remote bookmark head1
882 882 adding remote bookmark head2
883 883
884 884 $ ls shareremote
885 885 195bb1fcdb595c14a6c13e0269129ed78f6debde
886 886 c0d4f83847ca2a873741feb7048a45085fd47c46
887 887
888 888 request to clone a single revision is respected in sharing mode
889 889
890 890 $ hg --config share.pool=sharerevs clone -r 4a8dc1ab4c13 source1b share-1arev
891 891 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
892 892 adding changesets
893 893 adding manifests
894 894 adding file changes
895 895 added 2 changesets with 2 changes to 1 files
896 896 updating working directory
897 897 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
898 898 no changes found
899 899 adding remote bookmark head1
900 900
901 901 $ hg -R share-1arev log -G
902 902 @ changeset: 1:4a8dc1ab4c13
903 903 | bookmark: head1
904 904 | tag: tip
905 905 | user: test
906 906 | date: Thu Jan 01 00:00:00 1970 +0000
907 907 | summary: head1
908 908 |
909 909 o changeset: 0:b5f04eac9d8f
910 910 user: test
911 911 date: Thu Jan 01 00:00:00 1970 +0000
912 912 summary: initial
913 913
914 914
915 915 making another clone should only pull down requested rev
916 916
917 917 $ hg --config share.pool=sharerevs clone -r 99f71071f117 source1b share-1brev
918 918 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
919 919 updating working directory
920 920 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
921 921 searching for changes
922 922 adding changesets
923 923 adding manifests
924 924 adding file changes
925 925 added 1 changesets with 1 changes to 1 files (+1 heads)
926 926 adding remote bookmark head1
927 927 adding remote bookmark head2
928 928
929 929 $ hg -R share-1brev log -G
930 930 o changeset: 2:99f71071f117
931 931 | bookmark: head2
932 932 | tag: tip
933 933 | parent: 0:b5f04eac9d8f
934 934 | user: test
935 935 | date: Thu Jan 01 00:00:00 1970 +0000
936 936 | summary: head2
937 937 |
938 938 | @ changeset: 1:4a8dc1ab4c13
939 939 |/ bookmark: head1
940 940 | user: test
941 941 | date: Thu Jan 01 00:00:00 1970 +0000
942 942 | summary: head1
943 943 |
944 944 o changeset: 0:b5f04eac9d8f
945 945 user: test
946 946 date: Thu Jan 01 00:00:00 1970 +0000
947 947 summary: initial
948 948
949 949
950 950 Request to clone a single branch is respected in sharing mode
951 951
952 952 $ hg --config share.pool=sharebranch clone -b branch1 source1b share-1bbranch1
953 953 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
954 954 adding changesets
955 955 adding manifests
956 956 adding file changes
957 957 added 2 changesets with 2 changes to 1 files
958 958 updating working directory
959 959 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
960 960 no changes found
961 961
962 962 $ hg -R share-1bbranch1 log -G
963 963 o changeset: 1:5f92a6c1a1b1
964 964 | branch: branch1
965 965 | tag: tip
966 966 | user: test
967 967 | date: Thu Jan 01 00:00:00 1970 +0000
968 968 | summary: branch1
969 969 |
970 970 @ changeset: 0:b5f04eac9d8f
971 971 user: test
972 972 date: Thu Jan 01 00:00:00 1970 +0000
973 973 summary: initial
974 974
975 975
976 976 $ hg --config share.pool=sharebranch clone -b branch2 source1b share-1bbranch2
977 977 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
978 978 updating working directory
979 979 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
980 980 searching for changes
981 981 adding changesets
982 982 adding manifests
983 983 adding file changes
984 984 added 1 changesets with 1 changes to 1 files (+1 heads)
985 985
986 986 $ hg -R share-1bbranch2 log -G
987 987 o changeset: 2:6bacf4683960
988 988 | branch: branch2
989 989 | tag: tip
990 990 | parent: 0:b5f04eac9d8f
991 991 | user: test
992 992 | date: Thu Jan 01 00:00:00 1970 +0000
993 993 | summary: branch2
994 994 |
995 995 | o changeset: 1:5f92a6c1a1b1
996 996 |/ branch: branch1
997 997 | user: test
998 998 | date: Thu Jan 01 00:00:00 1970 +0000
999 999 | summary: branch1
1000 1000 |
1001 1001 @ changeset: 0:b5f04eac9d8f
1002 1002 user: test
1003 1003 date: Thu Jan 01 00:00:00 1970 +0000
1004 1004 summary: initial
1005 1005
1006 1006
1007 1007 -U is respected in share clone mode
1008 1008
1009 1009 $ hg --config share.pool=share clone -U source1a share-1anowc
1010 1010 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1011 1011 searching for changes
1012 1012 no changes found
1013 1013 adding remote bookmark bookA
1014 1014
1015 1015 $ ls share-1anowc
1016 1016
1017 1017 Test that auto sharing doesn't cause failure of "hg clone local remote"
1018 1018
1019 1019 $ cd $TESTTMP
1020 1020 $ hg -R a id -r 0
1021 1021 acb14030fe0a
1022 1022 $ hg id -R remote -r 0
1023 abort: there is no Mercurial repository here (.hg not found)
1023 abort: repository remote not found!
1024 1024 [255]
1025 1025 $ hg --config share.pool=share -q clone -e "python \"$TESTDIR/dummyssh\"" a ssh://user@dummy/remote
1026 1026 $ hg -R remote id -r 0
1027 1027 acb14030fe0a
@@ -1,649 +1,658 b''
1 1 #if windows
2 2 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
3 3 #else
4 4 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
5 5 #endif
6 6 $ export PYTHONPATH
7 7
8 8 typical client does not want echo-back messages, so test without it:
9 9
10 10 $ grep -v '^promptecho ' < $HGRCPATH >> $HGRCPATH.new
11 11 $ mv $HGRCPATH.new $HGRCPATH
12 12
13 13 $ hg init repo
14 14 $ cd repo
15 15
16 16 >>> from hgclient import readchannel, runcommand, check
17 17 >>> @check
18 18 ... def hellomessage(server):
19 19 ... ch, data = readchannel(server)
20 20 ... print '%c, %r' % (ch, data)
21 21 ... # run an arbitrary command to make sure the next thing the server
22 22 ... # sends isn't part of the hello message
23 23 ... runcommand(server, ['id'])
24 24 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
25 25 *** runcommand id
26 26 000000000000 tip
27 27
28 28 >>> from hgclient import check
29 29 >>> @check
30 30 ... def unknowncommand(server):
31 31 ... server.stdin.write('unknowncommand\n')
32 32 abort: unknown command unknowncommand
33 33
34 34 >>> from hgclient import readchannel, runcommand, check
35 35 >>> @check
36 36 ... def checkruncommand(server):
37 37 ... # hello block
38 38 ... readchannel(server)
39 39 ...
40 40 ... # no args
41 41 ... runcommand(server, [])
42 42 ...
43 43 ... # global options
44 44 ... runcommand(server, ['id', '--quiet'])
45 45 ...
46 46 ... # make sure global options don't stick through requests
47 47 ... runcommand(server, ['id'])
48 48 ...
49 49 ... # --config
50 50 ... runcommand(server, ['id', '--config', 'ui.quiet=True'])
51 51 ...
52 52 ... # make sure --config doesn't stick
53 53 ... runcommand(server, ['id'])
54 54 ...
55 55 ... # negative return code should be masked
56 56 ... runcommand(server, ['id', '-runknown'])
57 57 *** runcommand
58 58 Mercurial Distributed SCM
59 59
60 60 basic commands:
61 61
62 62 add add the specified files on the next commit
63 63 annotate show changeset information by line for each file
64 64 clone make a copy of an existing repository
65 65 commit commit the specified files or all outstanding changes
66 66 diff diff repository (or selected files)
67 67 export dump the header and diffs for one or more changesets
68 68 forget forget the specified files on the next commit
69 69 init create a new repository in the given directory
70 70 log show revision history of entire repository or files
71 71 merge merge another revision into working directory
72 72 pull pull changes from the specified source
73 73 push push changes to the specified destination
74 74 remove remove the specified files on the next commit
75 75 serve start stand-alone webserver
76 76 status show changed files in the working directory
77 77 summary summarize working directory state
78 78 update update working directory (or switch revisions)
79 79
80 80 (use "hg help" for the full list of commands or "hg -v" for details)
81 81 *** runcommand id --quiet
82 82 000000000000
83 83 *** runcommand id
84 84 000000000000 tip
85 85 *** runcommand id --config ui.quiet=True
86 86 000000000000
87 87 *** runcommand id
88 88 000000000000 tip
89 89 *** runcommand id -runknown
90 90 abort: unknown revision 'unknown'!
91 91 [255]
92 92
93 93 >>> from hgclient import readchannel, check
94 94 >>> @check
95 95 ... def inputeof(server):
96 96 ... readchannel(server)
97 97 ... server.stdin.write('runcommand\n')
98 98 ... # close stdin while server is waiting for input
99 99 ... server.stdin.close()
100 100 ...
101 101 ... # server exits with 1 if the pipe closed while reading the command
102 102 ... print 'server exit code =', server.wait()
103 103 server exit code = 1
104 104
105 105 >>> import cStringIO
106 106 >>> from hgclient import readchannel, runcommand, check
107 107 >>> @check
108 108 ... def serverinput(server):
109 109 ... readchannel(server)
110 110 ...
111 111 ... patch = """
112 112 ... # HG changeset patch
113 113 ... # User test
114 114 ... # Date 0 0
115 115 ... # Node ID c103a3dec114d882c98382d684d8af798d09d857
116 116 ... # Parent 0000000000000000000000000000000000000000
117 117 ... 1
118 118 ...
119 119 ... diff -r 000000000000 -r c103a3dec114 a
120 120 ... --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121 121 ... +++ b/a Thu Jan 01 00:00:00 1970 +0000
122 122 ... @@ -0,0 +1,1 @@
123 123 ... +1
124 124 ... """
125 125 ...
126 126 ... runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch))
127 127 ... runcommand(server, ['log'])
128 128 *** runcommand import -
129 129 applying patch from stdin
130 130 *** runcommand log
131 131 changeset: 0:eff892de26ec
132 132 tag: tip
133 133 user: test
134 134 date: Thu Jan 01 00:00:00 1970 +0000
135 135 summary: 1
136 136
137 137
138 138 check that --cwd doesn't persist between requests:
139 139
140 140 $ mkdir foo
141 141 $ touch foo/bar
142 142 >>> from hgclient import readchannel, runcommand, check
143 143 >>> @check
144 144 ... def cwd(server):
145 145 ... readchannel(server)
146 146 ... runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
147 147 ... runcommand(server, ['st', 'foo/bar'])
148 148 *** runcommand --cwd foo st bar
149 149 ? bar
150 150 *** runcommand st foo/bar
151 151 ? foo/bar
152 152
153 153 $ rm foo/bar
154 154
155 155
156 156 check that local configs for the cached repo aren't inherited when -R is used:
157 157
158 158 $ cat <<EOF >> .hg/hgrc
159 159 > [ui]
160 160 > foo = bar
161 161 > EOF
162 162
163 163 >>> from hgclient import readchannel, sep, runcommand, check
164 164 >>> @check
165 165 ... def localhgrc(server):
166 166 ... readchannel(server)
167 167 ...
168 168 ... # the cached repo local hgrc contains ui.foo=bar, so showconfig should
169 169 ... # show it
170 170 ... runcommand(server, ['showconfig'], outfilter=sep)
171 171 ...
172 172 ... # but not for this repo
173 173 ... runcommand(server, ['init', 'foo'])
174 174 ... runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
175 175 *** runcommand showconfig
176 176 bundle.mainreporoot=$TESTTMP/repo
177 177 defaults.backout=-d "0 0"
178 178 defaults.commit=-d "0 0"
179 179 defaults.shelve=--date "0 0"
180 180 defaults.tag=-d "0 0"
181 181 devel.all-warnings=true
182 182 largefiles.usercache=$TESTTMP/.cache/largefiles
183 183 ui.slash=True
184 184 ui.interactive=False
185 185 ui.mergemarkers=detailed
186 186 ui.foo=bar
187 187 ui.nontty=true
188 188 *** runcommand init foo
189 189 *** runcommand -R foo showconfig ui defaults
190 190 defaults.backout=-d "0 0"
191 191 defaults.commit=-d "0 0"
192 192 defaults.shelve=--date "0 0"
193 193 defaults.tag=-d "0 0"
194 194 ui.slash=True
195 195 ui.interactive=False
196 196 ui.mergemarkers=detailed
197 197 ui.nontty=true
198 198
199 199 $ rm -R foo
200 200
201 201 #if windows
202 202 $ PYTHONPATH="$TESTTMP/repo;$PYTHONPATH"
203 203 #else
204 204 $ PYTHONPATH="$TESTTMP/repo:$PYTHONPATH"
205 205 #endif
206 206
207 207 $ cat <<EOF > hook.py
208 208 > import sys
209 209 > def hook(**args):
210 210 > print 'hook talking'
211 211 > print 'now try to read something: %r' % sys.stdin.read()
212 212 > EOF
213 213
214 214 >>> import cStringIO
215 215 >>> from hgclient import readchannel, runcommand, check
216 216 >>> @check
217 217 ... def hookoutput(server):
218 218 ... readchannel(server)
219 219 ... runcommand(server, ['--config',
220 220 ... 'hooks.pre-identify=python:hook.hook',
221 221 ... 'id'],
222 222 ... input=cStringIO.StringIO('some input'))
223 223 *** runcommand --config hooks.pre-identify=python:hook.hook id
224 224 hook talking
225 225 now try to read something: 'some input'
226 226 eff892de26ec tip
227 227
228 228 $ rm hook.py*
229 229
230 230 $ echo a >> a
231 231 >>> import os
232 232 >>> from hgclient import readchannel, runcommand, check
233 233 >>> @check
234 234 ... def outsidechanges(server):
235 235 ... readchannel(server)
236 236 ... runcommand(server, ['status'])
237 237 ... os.system('hg ci -Am2')
238 238 ... runcommand(server, ['tip'])
239 239 ... runcommand(server, ['status'])
240 240 *** runcommand status
241 241 M a
242 242 *** runcommand tip
243 243 changeset: 1:d3a0a68be6de
244 244 tag: tip
245 245 user: test
246 246 date: Thu Jan 01 00:00:00 1970 +0000
247 247 summary: 2
248 248
249 249 *** runcommand status
250 250
251 251 >>> import os
252 252 >>> from hgclient import readchannel, runcommand, check
253 253 >>> @check
254 254 ... def bookmarks(server):
255 255 ... readchannel(server)
256 256 ... runcommand(server, ['bookmarks'])
257 257 ...
258 258 ... # changes .hg/bookmarks
259 259 ... os.system('hg bookmark -i bm1')
260 260 ... os.system('hg bookmark -i bm2')
261 261 ... runcommand(server, ['bookmarks'])
262 262 ...
263 263 ... # changes .hg/bookmarks.current
264 264 ... os.system('hg upd bm1 -q')
265 265 ... runcommand(server, ['bookmarks'])
266 266 ...
267 267 ... runcommand(server, ['bookmarks', 'bm3'])
268 268 ... f = open('a', 'ab')
269 269 ... f.write('a\n')
270 270 ... f.close()
271 271 ... runcommand(server, ['commit', '-Amm'])
272 272 ... runcommand(server, ['bookmarks'])
273 273 *** runcommand bookmarks
274 274 no bookmarks set
275 275 *** runcommand bookmarks
276 276 bm1 1:d3a0a68be6de
277 277 bm2 1:d3a0a68be6de
278 278 *** runcommand bookmarks
279 279 * bm1 1:d3a0a68be6de
280 280 bm2 1:d3a0a68be6de
281 281 *** runcommand bookmarks bm3
282 282 *** runcommand commit -Amm
283 283 *** runcommand bookmarks
284 284 bm1 1:d3a0a68be6de
285 285 bm2 1:d3a0a68be6de
286 286 * bm3 2:aef17e88f5f0
287 287
288 288 >>> import os
289 289 >>> from hgclient import readchannel, runcommand, check
290 290 >>> @check
291 291 ... def tagscache(server):
292 292 ... readchannel(server)
293 293 ... runcommand(server, ['id', '-t', '-r', '0'])
294 294 ... os.system('hg tag -r 0 foo')
295 295 ... runcommand(server, ['id', '-t', '-r', '0'])
296 296 *** runcommand id -t -r 0
297 297
298 298 *** runcommand id -t -r 0
299 299 foo
300 300
301 301 >>> import os
302 302 >>> from hgclient import readchannel, runcommand, check
303 303 >>> @check
304 304 ... def setphase(server):
305 305 ... readchannel(server)
306 306 ... runcommand(server, ['phase', '-r', '.'])
307 307 ... os.system('hg phase -r . -p')
308 308 ... runcommand(server, ['phase', '-r', '.'])
309 309 *** runcommand phase -r .
310 310 3: draft
311 311 *** runcommand phase -r .
312 312 3: public
313 313
314 314 $ echo a >> a
315 315 >>> from hgclient import readchannel, runcommand, check
316 316 >>> @check
317 317 ... def rollback(server):
318 318 ... readchannel(server)
319 319 ... runcommand(server, ['phase', '-r', '.', '-p'])
320 320 ... runcommand(server, ['commit', '-Am.'])
321 321 ... runcommand(server, ['rollback'])
322 322 ... runcommand(server, ['phase', '-r', '.'])
323 323 *** runcommand phase -r . -p
324 324 no phases changed
325 325 [1]
326 326 *** runcommand commit -Am.
327 327 *** runcommand rollback
328 328 repository tip rolled back to revision 3 (undo commit)
329 329 working directory now based on revision 3
330 330 *** runcommand phase -r .
331 331 3: public
332 332
333 333 >>> import os
334 334 >>> from hgclient import readchannel, runcommand, check
335 335 >>> @check
336 336 ... def branch(server):
337 337 ... readchannel(server)
338 338 ... runcommand(server, ['branch'])
339 339 ... os.system('hg branch foo')
340 340 ... runcommand(server, ['branch'])
341 341 ... os.system('hg branch default')
342 342 *** runcommand branch
343 343 default
344 344 marked working directory as branch foo
345 345 (branches are permanent and global, did you want a bookmark?)
346 346 *** runcommand branch
347 347 foo
348 348 marked working directory as branch default
349 349 (branches are permanent and global, did you want a bookmark?)
350 350
351 351 $ touch .hgignore
352 352 >>> import os
353 353 >>> from hgclient import readchannel, runcommand, check
354 354 >>> @check
355 355 ... def hgignore(server):
356 356 ... readchannel(server)
357 357 ... runcommand(server, ['commit', '-Am.'])
358 358 ... f = open('ignored-file', 'ab')
359 359 ... f.write('')
360 360 ... f.close()
361 361 ... f = open('.hgignore', 'ab')
362 362 ... f.write('ignored-file')
363 363 ... f.close()
364 364 ... runcommand(server, ['status', '-i', '-u'])
365 365 *** runcommand commit -Am.
366 366 adding .hgignore
367 367 *** runcommand status -i -u
368 368 I ignored-file
369 369
370 370 >>> import os
371 371 >>> from hgclient import readchannel, sep, runcommand, check
372 372 >>> @check
373 373 ... def phasecacheafterstrip(server):
374 374 ... readchannel(server)
375 375 ...
376 376 ... # create new head, 5:731265503d86
377 377 ... runcommand(server, ['update', '-C', '0'])
378 378 ... f = open('a', 'ab')
379 379 ... f.write('a\n')
380 380 ... f.close()
381 381 ... runcommand(server, ['commit', '-Am.', 'a'])
382 382 ... runcommand(server, ['log', '-Gq'])
383 383 ...
384 384 ... # make it public; draft marker moves to 4:7966c8e3734d
385 385 ... runcommand(server, ['phase', '-p', '.'])
386 386 ... # load _phasecache.phaseroots
387 387 ... runcommand(server, ['phase', '.'], outfilter=sep)
388 388 ...
389 389 ... # strip 1::4 outside server
390 390 ... os.system('hg -q --config extensions.mq= strip 1')
391 391 ...
392 392 ... # shouldn't raise "7966c8e3734d: no node!"
393 393 ... runcommand(server, ['branches'])
394 394 *** runcommand update -C 0
395 395 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
396 396 (leaving bookmark bm3)
397 397 *** runcommand commit -Am. a
398 398 created new head
399 399 *** runcommand log -Gq
400 400 @ 5:731265503d86
401 401 |
402 402 | o 4:7966c8e3734d
403 403 | |
404 404 | o 3:b9b85890c400
405 405 | |
406 406 | o 2:aef17e88f5f0
407 407 | |
408 408 | o 1:d3a0a68be6de
409 409 |/
410 410 o 0:eff892de26ec
411 411
412 412 *** runcommand phase -p .
413 413 *** runcommand phase .
414 414 5: public
415 415 *** runcommand branches
416 416 default 1:731265503d86
417 417
418 418 $ cat >> .hg/hgrc << EOF
419 419 > [experimental]
420 420 > evolution=createmarkers
421 421 > EOF
422 422
423 423 >>> import os
424 424 >>> from hgclient import readchannel, runcommand, check
425 425 >>> @check
426 426 ... def obsolete(server):
427 427 ... readchannel(server)
428 428 ...
429 429 ... runcommand(server, ['up', 'null'])
430 430 ... runcommand(server, ['phase', '-df', 'tip'])
431 431 ... cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
432 432 ... if os.name == 'nt':
433 433 ... cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
434 434 ... os.system(cmd)
435 435 ... runcommand(server, ['log', '--hidden'])
436 436 ... runcommand(server, ['log'])
437 437 *** runcommand up null
438 438 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
439 439 *** runcommand phase -df tip
440 440 *** runcommand log --hidden
441 441 changeset: 1:731265503d86
442 442 tag: tip
443 443 user: test
444 444 date: Thu Jan 01 00:00:00 1970 +0000
445 445 summary: .
446 446
447 447 changeset: 0:eff892de26ec
448 448 bookmark: bm1
449 449 bookmark: bm2
450 450 bookmark: bm3
451 451 user: test
452 452 date: Thu Jan 01 00:00:00 1970 +0000
453 453 summary: 1
454 454
455 455 *** runcommand log
456 456 changeset: 0:eff892de26ec
457 457 bookmark: bm1
458 458 bookmark: bm2
459 459 bookmark: bm3
460 460 tag: tip
461 461 user: test
462 462 date: Thu Jan 01 00:00:00 1970 +0000
463 463 summary: 1
464 464
465 465
466 466 $ cat <<EOF >> .hg/hgrc
467 467 > [extensions]
468 468 > mq =
469 469 > EOF
470 470
471 471 >>> import os
472 472 >>> from hgclient import readchannel, runcommand, check
473 473 >>> @check
474 474 ... def mqoutsidechanges(server):
475 475 ... readchannel(server)
476 476 ...
477 477 ... # load repo.mq
478 478 ... runcommand(server, ['qapplied'])
479 479 ... os.system('hg qnew 0.diff')
480 480 ... # repo.mq should be invalidated
481 481 ... runcommand(server, ['qapplied'])
482 482 ...
483 483 ... runcommand(server, ['qpop', '--all'])
484 484 ... os.system('hg qqueue --create foo')
485 485 ... # repo.mq should be recreated to point to new queue
486 486 ... runcommand(server, ['qqueue', '--active'])
487 487 *** runcommand qapplied
488 488 *** runcommand qapplied
489 489 0.diff
490 490 *** runcommand qpop --all
491 491 popping 0.diff
492 492 patch queue now empty
493 493 *** runcommand qqueue --active
494 494 foo
495 495
496 496 $ cat <<EOF > dbgui.py
497 497 > import os, sys
498 498 > from mercurial import cmdutil, commands
499 499 > cmdtable = {}
500 500 > command = cmdutil.command(cmdtable)
501 501 > @command("debuggetpass", norepo=True)
502 502 > def debuggetpass(ui):
503 503 > ui.write("%s\\n" % ui.getpass())
504 504 > @command("debugprompt", norepo=True)
505 505 > def debugprompt(ui):
506 506 > ui.write("%s\\n" % ui.prompt("prompt:"))
507 507 > @command("debugreadstdin", norepo=True)
508 508 > def debugreadstdin(ui):
509 509 > ui.write("read: %r\n" % sys.stdin.read(1))
510 510 > @command("debugwritestdout", norepo=True)
511 511 > def debugwritestdout(ui):
512 512 > os.write(1, "low-level stdout fd and\n")
513 513 > sys.stdout.write("stdout should be redirected to /dev/null\n")
514 514 > sys.stdout.flush()
515 515 > EOF
516 516 $ cat <<EOF >> .hg/hgrc
517 517 > [extensions]
518 518 > dbgui = dbgui.py
519 519 > EOF
520 520
521 521 >>> import cStringIO
522 522 >>> from hgclient import readchannel, runcommand, check
523 523 >>> @check
524 524 ... def getpass(server):
525 525 ... readchannel(server)
526 526 ... runcommand(server, ['debuggetpass', '--config',
527 527 ... 'ui.interactive=True'],
528 528 ... input=cStringIO.StringIO('1234\n'))
529 529 ... runcommand(server, ['debugprompt', '--config',
530 530 ... 'ui.interactive=True'],
531 531 ... input=cStringIO.StringIO('5678\n'))
532 532 ... runcommand(server, ['debugreadstdin'])
533 533 ... runcommand(server, ['debugwritestdout'])
534 534 *** runcommand debuggetpass --config ui.interactive=True
535 535 password: 1234
536 536 *** runcommand debugprompt --config ui.interactive=True
537 537 prompt: 5678
538 538 *** runcommand debugreadstdin
539 539 read: ''
540 540 *** runcommand debugwritestdout
541 541
542 542
543 543 run commandserver in commandserver, which is silly but should work:
544 544
545 545 >>> import cStringIO
546 546 >>> from hgclient import readchannel, runcommand, check
547 547 >>> @check
548 548 ... def nested(server):
549 549 ... print '%c, %r' % readchannel(server)
550 550 ... class nestedserver(object):
551 551 ... stdin = cStringIO.StringIO('getencoding\n')
552 552 ... stdout = cStringIO.StringIO()
553 553 ... runcommand(server, ['serve', '--cmdserver', 'pipe'],
554 554 ... output=nestedserver.stdout, input=nestedserver.stdin)
555 555 ... nestedserver.stdout.seek(0)
556 556 ... print '%c, %r' % readchannel(nestedserver) # hello
557 557 ... print '%c, %r' % readchannel(nestedserver) # getencoding
558 558 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
559 559 *** runcommand serve --cmdserver pipe
560 560 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
561 561 r, '*' (glob)
562 562
563 563
564 564 start without repository:
565 565
566 566 $ cd ..
567 567
568 568 >>> from hgclient import readchannel, runcommand, check
569 569 >>> @check
570 570 ... def hellomessage(server):
571 571 ... ch, data = readchannel(server)
572 572 ... print '%c, %r' % (ch, data)
573 573 ... # run an arbitrary command to make sure the next thing the server
574 574 ... # sends isn't part of the hello message
575 575 ... runcommand(server, ['id'])
576 576 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
577 577 *** runcommand id
578 578 abort: there is no Mercurial repository here (.hg not found)
579 579 [255]
580 580
581 581 >>> from hgclient import readchannel, runcommand, check
582 582 >>> @check
583 583 ... def startwithoutrepo(server):
584 584 ... readchannel(server)
585 585 ... runcommand(server, ['init', 'repo2'])
586 586 ... runcommand(server, ['id', '-R', 'repo2'])
587 587 *** runcommand init repo2
588 588 *** runcommand id -R repo2
589 589 000000000000 tip
590 590
591 591
592 don't fall back to cwd if invalid -R path is specified (issue4805):
593
594 $ cd repo
595 $ hg serve --cmdserver pipe -R ../nonexistent
596 abort: repository ../nonexistent not found!
597 [255]
598 $ cd ..
599
600
592 601 unix domain socket:
593 602
594 603 $ cd repo
595 604 $ hg update -q
596 605
597 606 #if unix-socket unix-permissions
598 607
599 608 >>> import cStringIO
600 609 >>> from hgclient import unixserver, readchannel, runcommand, check
601 610 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
602 611 >>> def hellomessage(conn):
603 612 ... ch, data = readchannel(conn)
604 613 ... print '%c, %r' % (ch, data)
605 614 ... runcommand(conn, ['id'])
606 615 >>> check(hellomessage, server.connect)
607 616 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
608 617 *** runcommand id
609 618 eff892de26ec tip bm1/bm2/bm3
610 619 >>> def unknowncommand(conn):
611 620 ... readchannel(conn)
612 621 ... conn.stdin.write('unknowncommand\n')
613 622 >>> check(unknowncommand, server.connect) # error sent to server.log
614 623 >>> def serverinput(conn):
615 624 ... readchannel(conn)
616 625 ... patch = """
617 626 ... # HG changeset patch
618 627 ... # User test
619 628 ... # Date 0 0
620 629 ... 2
621 630 ...
622 631 ... diff -r eff892de26ec -r 1ed24be7e7a0 a
623 632 ... --- a/a
624 633 ... +++ b/a
625 634 ... @@ -1,1 +1,2 @@
626 635 ... 1
627 636 ... +2
628 637 ... """
629 638 ... runcommand(conn, ['import', '-'], input=cStringIO.StringIO(patch))
630 639 ... runcommand(conn, ['log', '-rtip', '-q'])
631 640 >>> check(serverinput, server.connect)
632 641 *** runcommand import -
633 642 applying patch from stdin
634 643 *** runcommand log -rtip -q
635 644 2:1ed24be7e7a0
636 645 >>> server.shutdown()
637 646
638 647 $ cat .hg/server.log
639 648 listening at .hg/server.sock
640 649 abort: unknown command unknowncommand
641 650 killed!
642 651 #endif
643 652 #if no-unix-socket
644 653
645 654 $ hg serve --cmdserver unix -a .hg/server.sock
646 655 abort: unsupported platform
647 656 [255]
648 657
649 658 #endif
@@ -1,512 +1,512 b''
1 1 This test is a duplicate of 'test-http.t' feel free to factor out
2 2 parts that are not bundle1/bundle2 specific.
3 3
4 4 $ cat << EOF >> $HGRCPATH
5 5 > [experimental]
6 6 > # This test is dedicated to interaction through old bundle
7 7 > bundle2-exp = False
8 8 > EOF
9 9
10 10
11 11 This test tries to exercise the ssh functionality with a dummy script
12 12
13 13 creating 'remote' repo
14 14
15 15 $ hg init remote
16 16 $ cd remote
17 17 $ echo this > foo
18 18 $ echo this > fooO
19 19 $ hg ci -A -m "init" foo fooO
20 20
21 21 insert a closed branch (issue4428)
22 22
23 23 $ hg up null
24 24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 25 $ hg branch closed
26 26 marked working directory as branch closed
27 27 (branches are permanent and global, did you want a bookmark?)
28 28 $ hg ci -mc0
29 29 $ hg ci --close-branch -mc1
30 30 $ hg up -q default
31 31
32 32 configure for serving
33 33
34 34 $ cat <<EOF > .hg/hgrc
35 35 > [server]
36 36 > uncompressed = True
37 37 >
38 38 > [hooks]
39 39 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
40 40 > EOF
41 41 $ cd ..
42 42
43 43 repo not found error
44 44
45 45 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
46 remote: abort: there is no Mercurial repository here (.hg not found)!
46 remote: abort: repository nonexistent not found!
47 47 abort: no suitable response from remote hg!
48 48 [255]
49 49
50 50 non-existent absolute path
51 51
52 52 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
53 remote: abort: there is no Mercurial repository here (.hg not found)!
53 remote: abort: repository /$TESTTMP/nonexistent not found!
54 54 abort: no suitable response from remote hg!
55 55 [255]
56 56
57 57 clone remote via stream
58 58
59 59 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
60 60 streaming all changes
61 61 4 files to transfer, 615 bytes of data
62 62 transferred 615 bytes in * seconds (*) (glob)
63 63 searching for changes
64 64 no changes found
65 65 updating to branch default
66 66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 67 $ cd local-stream
68 68 $ hg verify
69 69 checking changesets
70 70 checking manifests
71 71 crosschecking files in changesets and manifests
72 72 checking files
73 73 2 files, 3 changesets, 2 total revisions
74 74 $ hg branches
75 75 default 0:1160648e36ce
76 76 $ cd ..
77 77
78 78 clone bookmarks via stream
79 79
80 80 $ hg -R local-stream book mybook
81 81 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
82 82 streaming all changes
83 83 4 files to transfer, 615 bytes of data
84 84 transferred 615 bytes in * seconds (*) (glob)
85 85 searching for changes
86 86 no changes found
87 87 updating to branch default
88 88 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 89 $ cd stream2
90 90 $ hg book
91 91 mybook 0:1160648e36ce
92 92 $ cd ..
93 93 $ rm -rf local-stream stream2
94 94
95 95 clone remote via pull
96 96
97 97 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
98 98 requesting all changes
99 99 adding changesets
100 100 adding manifests
101 101 adding file changes
102 102 added 3 changesets with 2 changes to 2 files
103 103 updating to branch default
104 104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 105
106 106 verify
107 107
108 108 $ cd local
109 109 $ hg verify
110 110 checking changesets
111 111 checking manifests
112 112 crosschecking files in changesets and manifests
113 113 checking files
114 114 2 files, 3 changesets, 2 total revisions
115 115 $ echo '[hooks]' >> .hg/hgrc
116 116 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
117 117
118 118 empty default pull
119 119
120 120 $ hg paths
121 121 default = ssh://user@dummy/remote
122 122 $ hg pull -e "python \"$TESTDIR/dummyssh\""
123 123 pulling from ssh://user@dummy/remote
124 124 searching for changes
125 125 no changes found
126 126
127 127 pull from wrong ssh URL
128 128
129 129 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
130 130 pulling from ssh://user@dummy/doesnotexist
131 remote: abort: there is no Mercurial repository here (.hg not found)!
131 remote: abort: repository doesnotexist not found!
132 132 abort: no suitable response from remote hg!
133 133 [255]
134 134
135 135 local change
136 136
137 137 $ echo bleah > foo
138 138 $ hg ci -m "add"
139 139
140 140 updating rc
141 141
142 142 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
143 143 $ echo "[ui]" >> .hg/hgrc
144 144 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
145 145
146 146 find outgoing
147 147
148 148 $ hg out ssh://user@dummy/remote
149 149 comparing with ssh://user@dummy/remote
150 150 searching for changes
151 151 changeset: 3:a28a9d1a809c
152 152 tag: tip
153 153 parent: 0:1160648e36ce
154 154 user: test
155 155 date: Thu Jan 01 00:00:00 1970 +0000
156 156 summary: add
157 157
158 158
159 159 find incoming on the remote side
160 160
161 161 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
162 162 comparing with ssh://user@dummy/local
163 163 searching for changes
164 164 changeset: 3:a28a9d1a809c
165 165 tag: tip
166 166 parent: 0:1160648e36ce
167 167 user: test
168 168 date: Thu Jan 01 00:00:00 1970 +0000
169 169 summary: add
170 170
171 171
172 172 find incoming on the remote side (using absolute path)
173 173
174 174 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
175 175 comparing with ssh://user@dummy/$TESTTMP/local
176 176 searching for changes
177 177 changeset: 3:a28a9d1a809c
178 178 tag: tip
179 179 parent: 0:1160648e36ce
180 180 user: test
181 181 date: Thu Jan 01 00:00:00 1970 +0000
182 182 summary: add
183 183
184 184
185 185 push
186 186
187 187 $ hg push
188 188 pushing to ssh://user@dummy/remote
189 189 searching for changes
190 190 remote: adding changesets
191 191 remote: adding manifests
192 192 remote: adding file changes
193 193 remote: added 1 changesets with 1 changes to 1 files
194 194 $ cd ../remote
195 195
196 196 check remote tip
197 197
198 198 $ hg tip
199 199 changeset: 3:a28a9d1a809c
200 200 tag: tip
201 201 parent: 0:1160648e36ce
202 202 user: test
203 203 date: Thu Jan 01 00:00:00 1970 +0000
204 204 summary: add
205 205
206 206 $ hg verify
207 207 checking changesets
208 208 checking manifests
209 209 crosschecking files in changesets and manifests
210 210 checking files
211 211 2 files, 4 changesets, 3 total revisions
212 212 $ hg cat -r tip foo
213 213 bleah
214 214 $ echo z > z
215 215 $ hg ci -A -m z z
216 216 created new head
217 217
218 218 test pushkeys and bookmarks
219 219
220 220 $ cd ../local
221 221 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
222 222 bookmarks
223 223 namespaces
224 224 phases
225 225 $ hg book foo -r 0
226 226 $ hg out -B
227 227 comparing with ssh://user@dummy/remote
228 228 searching for changed bookmarks
229 229 foo 1160648e36ce
230 230 $ hg push -B foo
231 231 pushing to ssh://user@dummy/remote
232 232 searching for changes
233 233 no changes found
234 234 exporting bookmark foo
235 235 [1]
236 236 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
237 237 foo 1160648e36cec0054048a7edc4110c6f84fde594
238 238 $ hg book -f foo
239 239 $ hg push --traceback
240 240 pushing to ssh://user@dummy/remote
241 241 searching for changes
242 242 no changes found
243 243 updating bookmark foo
244 244 [1]
245 245 $ hg book -d foo
246 246 $ hg in -B
247 247 comparing with ssh://user@dummy/remote
248 248 searching for changed bookmarks
249 249 foo a28a9d1a809c
250 250 $ hg book -f -r 0 foo
251 251 $ hg pull -B foo
252 252 pulling from ssh://user@dummy/remote
253 253 no changes found
254 254 updating bookmark foo
255 255 $ hg book -d foo
256 256 $ hg push -B foo
257 257 pushing to ssh://user@dummy/remote
258 258 searching for changes
259 259 no changes found
260 260 deleting remote bookmark foo
261 261 [1]
262 262
263 263 a bad, evil hook that prints to stdout
264 264
265 265 $ cat <<EOF > $TESTTMP/badhook
266 266 > import sys
267 267 > sys.stdout.write("KABOOM\n")
268 268 > EOF
269 269
270 270 $ echo '[hooks]' >> ../remote/.hg/hgrc
271 271 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
272 272 $ echo r > r
273 273 $ hg ci -A -m z r
274 274
275 275 push should succeed even though it has an unexpected response
276 276
277 277 $ hg push
278 278 pushing to ssh://user@dummy/remote
279 279 searching for changes
280 280 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
281 281 remote: adding changesets
282 282 remote: adding manifests
283 283 remote: adding file changes
284 284 remote: added 1 changesets with 1 changes to 1 files
285 285 remote: KABOOM
286 286 $ hg -R ../remote heads
287 287 changeset: 5:1383141674ec
288 288 tag: tip
289 289 parent: 3:a28a9d1a809c
290 290 user: test
291 291 date: Thu Jan 01 00:00:00 1970 +0000
292 292 summary: z
293 293
294 294 changeset: 4:6c0482d977a3
295 295 parent: 0:1160648e36ce
296 296 user: test
297 297 date: Thu Jan 01 00:00:00 1970 +0000
298 298 summary: z
299 299
300 300
301 301 clone bookmarks
302 302
303 303 $ hg -R ../remote bookmark test
304 304 $ hg -R ../remote bookmarks
305 305 * test 4:6c0482d977a3
306 306 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
307 307 requesting all changes
308 308 adding changesets
309 309 adding manifests
310 310 adding file changes
311 311 added 6 changesets with 5 changes to 4 files (+1 heads)
312 312 updating to branch default
313 313 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 314 $ hg -R local-bookmarks bookmarks
315 315 test 4:6c0482d977a3
316 316
317 317 passwords in ssh urls are not supported
318 318 (we use a glob here because different Python versions give different
319 319 results here)
320 320
321 321 $ hg push ssh://user:erroneouspwd@dummy/remote
322 322 pushing to ssh://user:*@dummy/remote (glob)
323 323 abort: password in URL not supported!
324 324 [255]
325 325
326 326 $ cd ..
327 327
328 328 hide outer repo
329 329 $ hg init
330 330
331 331 Test remote paths with spaces (issue2983):
332 332
333 333 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
334 334 $ touch "$TESTTMP/a repo/test"
335 335 $ hg -R 'a repo' commit -A -m "test"
336 336 adding test
337 337 $ hg -R 'a repo' tag tag
338 338 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
339 339 73649e48688a
340 340
341 341 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
342 342 abort: unknown revision 'noNoNO'!
343 343 [255]
344 344
345 345 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
346 346
347 347 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
348 348 destination directory: a repo
349 349 abort: destination 'a repo' is not empty
350 350 [255]
351 351
352 352 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
353 353 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
354 354 parameters:
355 355
356 356 $ cat > ssh.sh << EOF
357 357 > userhost="\$1"
358 358 > SSH_ORIGINAL_COMMAND="\$2"
359 359 > export SSH_ORIGINAL_COMMAND
360 360 > PYTHONPATH="$PYTHONPATH"
361 361 > export PYTHONPATH
362 362 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
363 363 > EOF
364 364
365 365 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
366 366 73649e48688a
367 367
368 368 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
369 369 remote: Illegal repository "$TESTTMP/a'repo" (glob)
370 370 abort: no suitable response from remote hg!
371 371 [255]
372 372
373 373 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
374 374 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
375 375 abort: no suitable response from remote hg!
376 376 [255]
377 377
378 378 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
379 379 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
380 380 [255]
381 381
382 382 Test hg-ssh in read-only mode:
383 383
384 384 $ cat > ssh.sh << EOF
385 385 > userhost="\$1"
386 386 > SSH_ORIGINAL_COMMAND="\$2"
387 387 > export SSH_ORIGINAL_COMMAND
388 388 > PYTHONPATH="$PYTHONPATH"
389 389 > export PYTHONPATH
390 390 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
391 391 > EOF
392 392
393 393 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
394 394 requesting all changes
395 395 adding changesets
396 396 adding manifests
397 397 adding file changes
398 398 added 6 changesets with 5 changes to 4 files (+1 heads)
399 399 updating to branch default
400 400 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
401 401
402 402 $ cd read-only-local
403 403 $ echo "baz" > bar
404 404 $ hg ci -A -m "unpushable commit" bar
405 405 $ hg push --ssh "sh ../ssh.sh"
406 406 pushing to ssh://user@dummy/*/remote (glob)
407 407 searching for changes
408 408 remote: Permission denied
409 409 remote: abort: pretxnopen.hg-ssh hook failed
410 410 remote: Permission denied
411 411 remote: pushkey-abort: prepushkey.hg-ssh hook failed
412 412 updating 6c0482d977a3 to public failed!
413 413 [1]
414 414
415 415 $ cd ..
416 416
417 417 stderr from remote commands should be printed before stdout from local code (issue4336)
418 418
419 419 $ hg clone remote stderr-ordering
420 420 updating to branch default
421 421 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 422 $ cd stderr-ordering
423 423 $ cat >> localwrite.py << EOF
424 424 > from mercurial import exchange, extensions
425 425 >
426 426 > def wrappedpush(orig, repo, *args, **kwargs):
427 427 > res = orig(repo, *args, **kwargs)
428 428 > repo.ui.write('local stdout\n')
429 429 > return res
430 430 >
431 431 > def extsetup(ui):
432 432 > extensions.wrapfunction(exchange, 'push', wrappedpush)
433 433 > EOF
434 434
435 435 $ cat >> .hg/hgrc << EOF
436 436 > [paths]
437 437 > default-push = ssh://user@dummy/remote
438 438 > [ui]
439 439 > ssh = python "$TESTDIR/dummyssh"
440 440 > [extensions]
441 441 > localwrite = localwrite.py
442 442 > EOF
443 443
444 444 $ echo localwrite > foo
445 445 $ hg commit -m 'testing localwrite'
446 446 $ hg push
447 447 pushing to ssh://user@dummy/remote
448 448 searching for changes
449 449 remote: adding changesets
450 450 remote: adding manifests
451 451 remote: adding file changes
452 452 remote: added 1 changesets with 1 changes to 1 files
453 453 remote: KABOOM
454 454 local stdout
455 455
456 456 debug output
457 457
458 458 $ hg pull --debug ssh://user@dummy/remote
459 459 pulling from ssh://user@dummy/remote
460 460 running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
461 461 sending hello command
462 462 sending between command
463 463 remote: 345
464 464 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
465 465 remote: 1
466 466 preparing listkeys for "bookmarks"
467 467 sending listkeys command
468 468 received listkey for "bookmarks": 45 bytes
469 469 query 1; heads
470 470 sending batch command
471 471 searching for changes
472 472 all remote heads known locally
473 473 no changes found
474 474 preparing listkeys for "phases"
475 475 sending listkeys command
476 476 received listkey for "phases": 15 bytes
477 477 checking for updated bookmarks
478 478
479 479 $ cd ..
480 480
481 481 $ cat dummylog
482 482 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
483 483 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
484 484 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
485 485 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
486 486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 488 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
489 489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 490 Got arguments 1:user@dummy 2:hg -R local serve --stdio
491 491 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
492 492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 493 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
494 494 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 496 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
497 497 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
498 498 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
499 499 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 503 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
504 504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 505 Got arguments 1:user@dummy 2:hg init 'a repo'
506 506 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
507 507 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
508 508 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
509 509 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
510 510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
511 511 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
512 512 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
@@ -1,503 +1,503 b''
1 1
2 2 This test tries to exercise the ssh functionality with a dummy script
3 3
4 4 creating 'remote' repo
5 5
6 6 $ hg init remote
7 7 $ cd remote
8 8 $ echo this > foo
9 9 $ echo this > fooO
10 10 $ hg ci -A -m "init" foo fooO
11 11
12 12 insert a closed branch (issue4428)
13 13
14 14 $ hg up null
15 15 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
16 16 $ hg branch closed
17 17 marked working directory as branch closed
18 18 (branches are permanent and global, did you want a bookmark?)
19 19 $ hg ci -mc0
20 20 $ hg ci --close-branch -mc1
21 21 $ hg up -q default
22 22
23 23 configure for serving
24 24
25 25 $ cat <<EOF > .hg/hgrc
26 26 > [server]
27 27 > uncompressed = True
28 28 >
29 29 > [hooks]
30 30 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
31 31 > EOF
32 32 $ cd ..
33 33
34 34 repo not found error
35 35
36 36 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
37 remote: abort: there is no Mercurial repository here (.hg not found)!
37 remote: abort: repository nonexistent not found!
38 38 abort: no suitable response from remote hg!
39 39 [255]
40 40
41 41 non-existent absolute path
42 42
43 43 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/nonexistent local
44 remote: abort: there is no Mercurial repository here (.hg not found)!
44 remote: abort: repository $TESTTMP/nonexistent not found!
45 45 abort: no suitable response from remote hg!
46 46 [255]
47 47
48 48 clone remote via stream
49 49
50 50 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
51 51 streaming all changes
52 52 4 files to transfer, 615 bytes of data
53 53 transferred 615 bytes in * seconds (*) (glob)
54 54 searching for changes
55 55 no changes found
56 56 updating to branch default
57 57 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 58 $ cd local-stream
59 59 $ hg verify
60 60 checking changesets
61 61 checking manifests
62 62 crosschecking files in changesets and manifests
63 63 checking files
64 64 2 files, 3 changesets, 2 total revisions
65 65 $ hg branches
66 66 default 0:1160648e36ce
67 67 $ cd ..
68 68
69 69 clone bookmarks via stream
70 70
71 71 $ hg -R local-stream book mybook
72 72 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
73 73 streaming all changes
74 74 4 files to transfer, 615 bytes of data
75 75 transferred 615 bytes in * seconds (*) (glob)
76 76 searching for changes
77 77 no changes found
78 78 updating to branch default
79 79 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 80 $ cd stream2
81 81 $ hg book
82 82 mybook 0:1160648e36ce
83 83 $ cd ..
84 84 $ rm -rf local-stream stream2
85 85
86 86 clone remote via pull
87 87
88 88 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
89 89 requesting all changes
90 90 adding changesets
91 91 adding manifests
92 92 adding file changes
93 93 added 3 changesets with 2 changes to 2 files
94 94 updating to branch default
95 95 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 96
97 97 verify
98 98
99 99 $ cd local
100 100 $ hg verify
101 101 checking changesets
102 102 checking manifests
103 103 crosschecking files in changesets and manifests
104 104 checking files
105 105 2 files, 3 changesets, 2 total revisions
106 106 $ echo '[hooks]' >> .hg/hgrc
107 107 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
108 108
109 109 empty default pull
110 110
111 111 $ hg paths
112 112 default = ssh://user@dummy/remote
113 113 $ hg pull -e "python \"$TESTDIR/dummyssh\""
114 114 pulling from ssh://user@dummy/remote
115 115 searching for changes
116 116 no changes found
117 117
118 118 pull from wrong ssh URL
119 119
120 120 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
121 121 pulling from ssh://user@dummy/doesnotexist
122 remote: abort: there is no Mercurial repository here (.hg not found)!
122 remote: abort: repository doesnotexist not found!
123 123 abort: no suitable response from remote hg!
124 124 [255]
125 125
126 126 local change
127 127
128 128 $ echo bleah > foo
129 129 $ hg ci -m "add"
130 130
131 131 updating rc
132 132
133 133 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
134 134 $ echo "[ui]" >> .hg/hgrc
135 135 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
136 136
137 137 find outgoing
138 138
139 139 $ hg out ssh://user@dummy/remote
140 140 comparing with ssh://user@dummy/remote
141 141 searching for changes
142 142 changeset: 3:a28a9d1a809c
143 143 tag: tip
144 144 parent: 0:1160648e36ce
145 145 user: test
146 146 date: Thu Jan 01 00:00:00 1970 +0000
147 147 summary: add
148 148
149 149
150 150 find incoming on the remote side
151 151
152 152 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
153 153 comparing with ssh://user@dummy/local
154 154 searching for changes
155 155 changeset: 3:a28a9d1a809c
156 156 tag: tip
157 157 parent: 0:1160648e36ce
158 158 user: test
159 159 date: Thu Jan 01 00:00:00 1970 +0000
160 160 summary: add
161 161
162 162
163 163 find incoming on the remote side (using absolute path)
164 164
165 165 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
166 166 comparing with ssh://user@dummy/$TESTTMP/local
167 167 searching for changes
168 168 changeset: 3:a28a9d1a809c
169 169 tag: tip
170 170 parent: 0:1160648e36ce
171 171 user: test
172 172 date: Thu Jan 01 00:00:00 1970 +0000
173 173 summary: add
174 174
175 175
176 176 push
177 177
178 178 $ hg push
179 179 pushing to ssh://user@dummy/remote
180 180 searching for changes
181 181 remote: adding changesets
182 182 remote: adding manifests
183 183 remote: adding file changes
184 184 remote: added 1 changesets with 1 changes to 1 files
185 185 $ cd ../remote
186 186
187 187 check remote tip
188 188
189 189 $ hg tip
190 190 changeset: 3:a28a9d1a809c
191 191 tag: tip
192 192 parent: 0:1160648e36ce
193 193 user: test
194 194 date: Thu Jan 01 00:00:00 1970 +0000
195 195 summary: add
196 196
197 197 $ hg verify
198 198 checking changesets
199 199 checking manifests
200 200 crosschecking files in changesets and manifests
201 201 checking files
202 202 2 files, 4 changesets, 3 total revisions
203 203 $ hg cat -r tip foo
204 204 bleah
205 205 $ echo z > z
206 206 $ hg ci -A -m z z
207 207 created new head
208 208
209 209 test pushkeys and bookmarks
210 210
211 211 $ cd ../local
212 212 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
213 213 bookmarks
214 214 namespaces
215 215 phases
216 216 $ hg book foo -r 0
217 217 $ hg out -B
218 218 comparing with ssh://user@dummy/remote
219 219 searching for changed bookmarks
220 220 foo 1160648e36ce
221 221 $ hg push -B foo
222 222 pushing to ssh://user@dummy/remote
223 223 searching for changes
224 224 no changes found
225 225 exporting bookmark foo
226 226 [1]
227 227 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
228 228 foo 1160648e36cec0054048a7edc4110c6f84fde594
229 229 $ hg book -f foo
230 230 $ hg push --traceback
231 231 pushing to ssh://user@dummy/remote
232 232 searching for changes
233 233 no changes found
234 234 updating bookmark foo
235 235 [1]
236 236 $ hg book -d foo
237 237 $ hg in -B
238 238 comparing with ssh://user@dummy/remote
239 239 searching for changed bookmarks
240 240 foo a28a9d1a809c
241 241 $ hg book -f -r 0 foo
242 242 $ hg pull -B foo
243 243 pulling from ssh://user@dummy/remote
244 244 no changes found
245 245 updating bookmark foo
246 246 $ hg book -d foo
247 247 $ hg push -B foo
248 248 pushing to ssh://user@dummy/remote
249 249 searching for changes
250 250 no changes found
251 251 deleting remote bookmark foo
252 252 [1]
253 253
254 254 a bad, evil hook that prints to stdout
255 255
256 256 $ cat <<EOF > $TESTTMP/badhook
257 257 > import sys
258 258 > sys.stdout.write("KABOOM\n")
259 259 > EOF
260 260
261 261 $ echo '[hooks]' >> ../remote/.hg/hgrc
262 262 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
263 263 $ echo r > r
264 264 $ hg ci -A -m z r
265 265
266 266 push should succeed even though it has an unexpected response
267 267
268 268 $ hg push
269 269 pushing to ssh://user@dummy/remote
270 270 searching for changes
271 271 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
272 272 remote: adding changesets
273 273 remote: adding manifests
274 274 remote: adding file changes
275 275 remote: added 1 changesets with 1 changes to 1 files
276 276 remote: KABOOM
277 277 $ hg -R ../remote heads
278 278 changeset: 5:1383141674ec
279 279 tag: tip
280 280 parent: 3:a28a9d1a809c
281 281 user: test
282 282 date: Thu Jan 01 00:00:00 1970 +0000
283 283 summary: z
284 284
285 285 changeset: 4:6c0482d977a3
286 286 parent: 0:1160648e36ce
287 287 user: test
288 288 date: Thu Jan 01 00:00:00 1970 +0000
289 289 summary: z
290 290
291 291
292 292 clone bookmarks
293 293
294 294 $ hg -R ../remote bookmark test
295 295 $ hg -R ../remote bookmarks
296 296 * test 4:6c0482d977a3
297 297 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
298 298 requesting all changes
299 299 adding changesets
300 300 adding manifests
301 301 adding file changes
302 302 added 6 changesets with 5 changes to 4 files (+1 heads)
303 303 updating to branch default
304 304 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 305 $ hg -R local-bookmarks bookmarks
306 306 test 4:6c0482d977a3
307 307
308 308 passwords in ssh urls are not supported
309 309 (we use a glob here because different Python versions give different
310 310 results here)
311 311
312 312 $ hg push ssh://user:erroneouspwd@dummy/remote
313 313 pushing to ssh://user:*@dummy/remote (glob)
314 314 abort: password in URL not supported!
315 315 [255]
316 316
317 317 $ cd ..
318 318
319 319 hide outer repo
320 320 $ hg init
321 321
322 322 Test remote paths with spaces (issue2983):
323 323
324 324 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
325 325 $ touch "$TESTTMP/a repo/test"
326 326 $ hg -R 'a repo' commit -A -m "test"
327 327 adding test
328 328 $ hg -R 'a repo' tag tag
329 329 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
330 330 73649e48688a
331 331
332 332 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
333 333 abort: unknown revision 'noNoNO'!
334 334 [255]
335 335
336 336 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
337 337
338 338 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
339 339 destination directory: a repo
340 340 abort: destination 'a repo' is not empty
341 341 [255]
342 342
343 343 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
344 344 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
345 345 parameters:
346 346
347 347 $ cat > ssh.sh << EOF
348 348 > userhost="\$1"
349 349 > SSH_ORIGINAL_COMMAND="\$2"
350 350 > export SSH_ORIGINAL_COMMAND
351 351 > PYTHONPATH="$PYTHONPATH"
352 352 > export PYTHONPATH
353 353 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
354 354 > EOF
355 355
356 356 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
357 357 73649e48688a
358 358
359 359 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
360 360 remote: Illegal repository "$TESTTMP/a'repo" (glob)
361 361 abort: no suitable response from remote hg!
362 362 [255]
363 363
364 364 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
365 365 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
366 366 abort: no suitable response from remote hg!
367 367 [255]
368 368
369 369 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
370 370 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
371 371 [255]
372 372
373 373 Test hg-ssh in read-only mode:
374 374
375 375 $ cat > ssh.sh << EOF
376 376 > userhost="\$1"
377 377 > SSH_ORIGINAL_COMMAND="\$2"
378 378 > export SSH_ORIGINAL_COMMAND
379 379 > PYTHONPATH="$PYTHONPATH"
380 380 > export PYTHONPATH
381 381 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
382 382 > EOF
383 383
384 384 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
385 385 requesting all changes
386 386 adding changesets
387 387 adding manifests
388 388 adding file changes
389 389 added 6 changesets with 5 changes to 4 files (+1 heads)
390 390 updating to branch default
391 391 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 392
393 393 $ cd read-only-local
394 394 $ echo "baz" > bar
395 395 $ hg ci -A -m "unpushable commit" bar
396 396 $ hg push --ssh "sh ../ssh.sh"
397 397 pushing to ssh://user@dummy/*/remote (glob)
398 398 searching for changes
399 399 remote: Permission denied
400 400 abort: pretxnopen.hg-ssh hook failed
401 401 [255]
402 402
403 403 $ cd ..
404 404
405 405 stderr from remote commands should be printed before stdout from local code (issue4336)
406 406
407 407 $ hg clone remote stderr-ordering
408 408 updating to branch default
409 409 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 410 $ cd stderr-ordering
411 411 $ cat >> localwrite.py << EOF
412 412 > from mercurial import exchange, extensions
413 413 >
414 414 > def wrappedpush(orig, repo, *args, **kwargs):
415 415 > res = orig(repo, *args, **kwargs)
416 416 > repo.ui.write('local stdout\n')
417 417 > return res
418 418 >
419 419 > def extsetup(ui):
420 420 > extensions.wrapfunction(exchange, 'push', wrappedpush)
421 421 > EOF
422 422
423 423 $ cat >> .hg/hgrc << EOF
424 424 > [paths]
425 425 > default-push = ssh://user@dummy/remote
426 426 > [ui]
427 427 > ssh = python "$TESTDIR/dummyssh"
428 428 > [extensions]
429 429 > localwrite = localwrite.py
430 430 > EOF
431 431
432 432 $ echo localwrite > foo
433 433 $ hg commit -m 'testing localwrite'
434 434 $ hg push
435 435 pushing to ssh://user@dummy/remote
436 436 searching for changes
437 437 remote: adding changesets
438 438 remote: adding manifests
439 439 remote: adding file changes
440 440 remote: added 1 changesets with 1 changes to 1 files
441 441 remote: KABOOM
442 442 local stdout
443 443
444 444 debug output
445 445
446 446 $ hg pull --debug ssh://user@dummy/remote
447 447 pulling from ssh://user@dummy/remote
448 448 running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
449 449 sending hello command
450 450 sending between command
451 451 remote: 345
452 452 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
453 453 remote: 1
454 454 query 1; heads
455 455 sending batch command
456 456 searching for changes
457 457 all remote heads known locally
458 458 no changes found
459 459 sending getbundle command
460 460 bundle2-input-bundle: with-transaction
461 461 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
462 462 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
463 463 bundle2-input-part: total payload size 45
464 464 bundle2-input-bundle: 1 parts total
465 465 checking for updated bookmarks
466 466 preparing listkeys for "phases"
467 467 sending listkeys command
468 468 received listkey for "phases": 15 bytes
469 469
470 470 $ cd ..
471 471
472 472 $ cat dummylog
473 473 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
474 474 Got arguments 1:user@dummy 2:hg -R $TESTTMP/nonexistent serve --stdio
475 475 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
476 476 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
477 477 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
478 478 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
479 479 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
480 480 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
481 481 Got arguments 1:user@dummy 2:hg -R local serve --stdio
482 482 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
483 483 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
484 484 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
485 485 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
486 486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 488 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
489 489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 491 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 493 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
494 494 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
495 495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 496 Got arguments 1:user@dummy 2:hg init 'a repo'
497 497 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
498 498 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
499 499 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
500 500 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
501 501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 502 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
503 503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
General Comments 0
You need to be logged in to leave comments. Login now