##// END OF EJS Templates
clone: don't fail with --update for non-local clones (issue3578)...
Augie Fackler -
r17342:471f30d3 stable
parent child Browse files
Show More
@@ -1,598 +1,598 b''
1 1 # hg.py - repository classes for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from i18n import _
10 10 from lock import release
11 11 from node import hex, nullid
12 12 import localrepo, bundlerepo, httppeer, sshpeer, statichttprepo, bookmarks
13 13 import lock, util, extensions, error, node, scmutil
14 14 import cmdutil, discovery
15 15 import merge as mergemod
16 16 import verify as verifymod
17 17 import errno, os, shutil
18 18
19 19 def _local(path):
20 20 path = util.expandpath(util.urllocalpath(path))
21 21 return (os.path.isfile(path) and bundlerepo or localrepo)
22 22
23 23 def addbranchrevs(lrepo, other, branches, revs):
24 24 peer = other.peer() # a courtesy to callers using a localrepo for other
25 25 hashbranch, branches = branches
26 26 if not hashbranch and not branches:
27 27 return revs or None, revs and revs[0] or None
28 28 revs = revs and list(revs) or []
29 29 if not peer.capable('branchmap'):
30 30 if branches:
31 31 raise util.Abort(_("remote branch lookup not supported"))
32 32 revs.append(hashbranch)
33 33 return revs, revs[0]
34 34 branchmap = peer.branchmap()
35 35
36 36 def primary(branch):
37 37 if branch == '.':
38 38 if not lrepo:
39 39 raise util.Abort(_("dirstate branch not accessible"))
40 40 branch = lrepo.dirstate.branch()
41 41 if branch in branchmap:
42 42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
43 43 return True
44 44 else:
45 45 return False
46 46
47 47 for branch in branches:
48 48 if not primary(branch):
49 49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
50 50 if hashbranch:
51 51 if not primary(hashbranch):
52 52 revs.append(hashbranch)
53 53 return revs, revs[0]
54 54
55 55 def parseurl(path, branches=None):
56 56 '''parse url#branch, returning (url, (branch, branches))'''
57 57
58 58 u = util.url(path)
59 59 branch = None
60 60 if u.fragment:
61 61 branch = u.fragment
62 62 u.fragment = None
63 63 return str(u), (branch, branches or [])
64 64
65 65 schemes = {
66 66 'bundle': bundlerepo,
67 67 'file': _local,
68 68 'http': httppeer,
69 69 'https': httppeer,
70 70 'ssh': sshpeer,
71 71 'static-http': statichttprepo,
72 72 }
73 73
74 74 def _peerlookup(path):
75 75 u = util.url(path)
76 76 scheme = u.scheme or 'file'
77 77 thing = schemes.get(scheme) or schemes['file']
78 78 try:
79 79 return thing(path)
80 80 except TypeError:
81 81 return thing
82 82
83 83 def islocal(repo):
84 84 '''return true if repo or path is local'''
85 85 if isinstance(repo, str):
86 86 try:
87 87 return _peerlookup(repo).islocal(repo)
88 88 except AttributeError:
89 89 return False
90 90 return repo.local()
91 91
92 92 def _peerorrepo(ui, path, create=False):
93 93 """return a repository object for the specified path"""
94 94 obj = _peerlookup(path).instance(ui, path, create)
95 95 ui = getattr(obj, "ui", ui)
96 96 for name, module in extensions.extensions():
97 97 hook = getattr(module, 'reposetup', None)
98 98 if hook:
99 99 hook(ui, obj)
100 100 return obj
101 101
102 102 def repository(ui, path='', create=False):
103 103 """return a repository object for the specified path"""
104 104 peer = _peerorrepo(ui, path, create)
105 105 repo = peer.local()
106 106 if not repo:
107 107 raise util.Abort(_("repository '%s' is not local") %
108 108 (path or peer.url()))
109 109 return repo
110 110
111 111 def peer(uiorrepo, opts, path, create=False):
112 112 '''return a repository peer for the specified path'''
113 113 rui = remoteui(uiorrepo, opts)
114 114 return _peerorrepo(rui, path, create).peer()
115 115
116 116 def defaultdest(source):
117 117 '''return default destination of clone if none is given'''
118 118 return os.path.basename(os.path.normpath(source))
119 119
120 120 def share(ui, source, dest=None, update=True):
121 121 '''create a shared repository'''
122 122
123 123 if not islocal(source):
124 124 raise util.Abort(_('can only share local repositories'))
125 125
126 126 if not dest:
127 127 dest = defaultdest(source)
128 128 else:
129 129 dest = ui.expandpath(dest)
130 130
131 131 if isinstance(source, str):
132 132 origsource = ui.expandpath(source)
133 133 source, branches = parseurl(origsource)
134 134 srcrepo = repository(ui, source)
135 135 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
136 136 else:
137 137 srcrepo = source.local()
138 138 origsource = source = srcrepo.url()
139 139 checkout = None
140 140
141 141 sharedpath = srcrepo.sharedpath # if our source is already sharing
142 142
143 143 root = os.path.realpath(dest)
144 144 roothg = os.path.join(root, '.hg')
145 145
146 146 if os.path.exists(roothg):
147 147 raise util.Abort(_('destination already exists'))
148 148
149 149 if not os.path.isdir(root):
150 150 os.mkdir(root)
151 151 util.makedir(roothg, notindexed=True)
152 152
153 153 requirements = ''
154 154 try:
155 155 requirements = srcrepo.opener.read('requires')
156 156 except IOError, inst:
157 157 if inst.errno != errno.ENOENT:
158 158 raise
159 159
160 160 requirements += 'shared\n'
161 161 util.writefile(os.path.join(roothg, 'requires'), requirements)
162 162 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
163 163
164 164 r = repository(ui, root)
165 165
166 166 default = srcrepo.ui.config('paths', 'default')
167 167 if default:
168 168 fp = r.opener("hgrc", "w", text=True)
169 169 fp.write("[paths]\n")
170 170 fp.write("default = %s\n" % default)
171 171 fp.close()
172 172
173 173 if update:
174 174 r.ui.status(_("updating working directory\n"))
175 175 if update is not True:
176 176 checkout = update
177 177 for test in (checkout, 'default', 'tip'):
178 178 if test is None:
179 179 continue
180 180 try:
181 181 uprev = r.lookup(test)
182 182 break
183 183 except error.RepoLookupError:
184 184 continue
185 185 _update(r, uprev)
186 186
187 187 def copystore(ui, srcrepo, destpath):
188 188 '''copy files from store of srcrepo in destpath
189 189
190 190 returns destlock
191 191 '''
192 192 destlock = None
193 193 try:
194 194 hardlink = None
195 195 num = 0
196 196 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
197 197 for f in srcrepo.store.copylist():
198 198 if srcpublishing and f.endswith('phaseroots'):
199 199 continue
200 200 src = os.path.join(srcrepo.sharedpath, f)
201 201 dst = os.path.join(destpath, f)
202 202 dstbase = os.path.dirname(dst)
203 203 if dstbase and not os.path.exists(dstbase):
204 204 os.mkdir(dstbase)
205 205 if os.path.exists(src):
206 206 if dst.endswith('data'):
207 207 # lock to avoid premature writing to the target
208 208 destlock = lock.lock(os.path.join(dstbase, "lock"))
209 209 hardlink, n = util.copyfiles(src, dst, hardlink)
210 210 num += n
211 211 if hardlink:
212 212 ui.debug("linked %d files\n" % num)
213 213 else:
214 214 ui.debug("copied %d files\n" % num)
215 215 return destlock
216 216 except: # re-raises
217 217 release(destlock)
218 218 raise
219 219
220 220 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
221 221 update=True, stream=False, branch=None):
222 222 """Make a copy of an existing repository.
223 223
224 224 Create a copy of an existing repository in a new directory. The
225 225 source and destination are URLs, as passed to the repository
226 226 function. Returns a pair of repository peers, the source and
227 227 newly created destination.
228 228
229 229 The location of the source is added to the new repository's
230 230 .hg/hgrc file, as the default to be used for future pulls and
231 231 pushes.
232 232
233 233 If an exception is raised, the partly cloned/updated destination
234 234 repository will be deleted.
235 235
236 236 Arguments:
237 237
238 238 source: repository object or URL
239 239
240 240 dest: URL of destination repository to create (defaults to base
241 241 name of source repository)
242 242
243 243 pull: always pull from source repository, even in local case
244 244
245 245 stream: stream raw data uncompressed from repository (fast over
246 246 LAN, slow over WAN)
247 247
248 248 rev: revision to clone up to (implies pull=True)
249 249
250 250 update: update working directory after clone completes, if
251 251 destination is local repository (True means update to default rev,
252 252 anything else is treated as a revision)
253 253
254 254 branch: branches to clone
255 255 """
256 256
257 257 if isinstance(source, str):
258 258 origsource = ui.expandpath(source)
259 259 source, branch = parseurl(origsource, branch)
260 260 srcpeer = peer(ui, peeropts, source)
261 261 else:
262 262 srcpeer = source.peer() # in case we were called with a localrepo
263 263 branch = (None, branch or [])
264 264 origsource = source = srcpeer.url()
265 265 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
266 266
267 267 if dest is None:
268 268 dest = defaultdest(source)
269 269 ui.status(_("destination directory: %s\n") % dest)
270 270 else:
271 271 dest = ui.expandpath(dest)
272 272
273 273 dest = util.urllocalpath(dest)
274 274 source = util.urllocalpath(source)
275 275
276 276 if not dest:
277 277 raise util.Abort(_("empty destination path is not valid"))
278 278 if os.path.exists(dest):
279 279 if not os.path.isdir(dest):
280 280 raise util.Abort(_("destination '%s' already exists") % dest)
281 281 elif os.listdir(dest):
282 282 raise util.Abort(_("destination '%s' is not empty") % dest)
283 283
284 284 class DirCleanup(object):
285 285 def __init__(self, dir_):
286 286 self.rmtree = shutil.rmtree
287 287 self.dir_ = dir_
288 288 def close(self):
289 289 self.dir_ = None
290 290 def cleanup(self):
291 291 if self.dir_:
292 292 self.rmtree(self.dir_, True)
293 293
294 294 srclock = destlock = dircleanup = None
295 295 srcrepo = srcpeer.local()
296 296 try:
297 297 abspath = origsource
298 298 if islocal(origsource):
299 299 abspath = os.path.abspath(util.urllocalpath(origsource))
300 300
301 301 if islocal(dest):
302 302 dircleanup = DirCleanup(dest)
303 303
304 304 copy = False
305 305 if (srcrepo and srcrepo.cancopy() and islocal(dest)
306 306 and not srcrepo.revs("secret()")):
307 307 copy = not pull and not rev
308 308
309 309 if copy:
310 310 try:
311 311 # we use a lock here because if we race with commit, we
312 312 # can end up with extra data in the cloned revlogs that's
313 313 # not pointed to by changesets, thus causing verify to
314 314 # fail
315 315 srclock = srcrepo.lock(wait=False)
316 316 except error.LockError:
317 317 copy = False
318 318
319 319 if copy:
320 320 srcrepo.hook('preoutgoing', throw=True, source='clone')
321 321 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
322 322 if not os.path.exists(dest):
323 323 os.mkdir(dest)
324 324 else:
325 325 # only clean up directories we create ourselves
326 326 dircleanup.dir_ = hgdir
327 327 try:
328 328 destpath = hgdir
329 329 util.makedir(destpath, notindexed=True)
330 330 except OSError, inst:
331 331 if inst.errno == errno.EEXIST:
332 332 dircleanup.close()
333 333 raise util.Abort(_("destination '%s' already exists")
334 334 % dest)
335 335 raise
336 336
337 337 destlock = copystore(ui, srcrepo, destpath)
338 338
339 339 # we need to re-init the repo after manually copying the data
340 340 # into it
341 341 destpeer = peer(ui, peeropts, dest)
342 342 srcrepo.hook('outgoing', source='clone',
343 343 node=node.hex(node.nullid))
344 344 else:
345 345 try:
346 346 destpeer = peer(ui, peeropts, dest, create=True)
347 347 except OSError, inst:
348 348 if inst.errno == errno.EEXIST:
349 349 dircleanup.close()
350 350 raise util.Abort(_("destination '%s' already exists")
351 351 % dest)
352 352 raise
353 353
354 354 revs = None
355 355 if rev:
356 356 if not srcpeer.capable('lookup'):
357 357 raise util.Abort(_("src repository does not support "
358 358 "revision lookup and so doesn't "
359 359 "support clone by revision"))
360 360 revs = [srcpeer.lookup(r) for r in rev]
361 361 checkout = revs[0]
362 362 if destpeer.local():
363 363 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
364 364 elif srcrepo:
365 365 srcrepo.push(destpeer, revs=revs)
366 366 else:
367 367 raise util.Abort(_("clone from remote to remote not supported"))
368 368
369 369 if dircleanup:
370 370 dircleanup.close()
371 371
372 372 # clone all bookmarks except divergent ones
373 373 destrepo = destpeer.local()
374 374 if destrepo and srcpeer.capable("pushkey"):
375 375 rb = srcpeer.listkeys('bookmarks')
376 376 for k, n in rb.iteritems():
377 377 try:
378 378 m = destrepo.lookup(n)
379 379 destrepo._bookmarks[k] = m
380 380 except error.RepoLookupError:
381 381 pass
382 382 if rb:
383 383 bookmarks.write(destrepo)
384 384 elif srcrepo and destpeer.capable("pushkey"):
385 385 for k, n in srcrepo._bookmarks.iteritems():
386 386 destpeer.pushkey('bookmarks', k, '', hex(n))
387 387
388 388 if destrepo:
389 389 fp = destrepo.opener("hgrc", "w", text=True)
390 390 fp.write("[paths]\n")
391 391 u = util.url(abspath)
392 392 u.passwd = None
393 393 defaulturl = str(u)
394 394 fp.write("default = %s\n" % defaulturl)
395 395 fp.close()
396 396
397 397 destrepo.ui.setconfig('paths', 'default', defaulturl)
398 398
399 399 if update:
400 400 if update is not True:
401 checkout = srcrepo.lookup(update)
401 checkout = srcpeer.lookup(update)
402 402 for test in (checkout, 'default', 'tip'):
403 403 if test is None:
404 404 continue
405 405 try:
406 406 uprev = destrepo.lookup(test)
407 407 break
408 408 except error.RepoLookupError:
409 409 continue
410 410 bn = destrepo[uprev].branch()
411 411 destrepo.ui.status(_("updating to branch %s\n") % bn)
412 412 _update(destrepo, uprev)
413 413
414 414 return srcpeer, destpeer
415 415 finally:
416 416 release(srclock, destlock)
417 417 if dircleanup is not None:
418 418 dircleanup.cleanup()
419 419 if srcpeer is not None:
420 420 srcpeer.close()
421 421
422 422 def _showstats(repo, stats):
423 423 repo.ui.status(_("%d files updated, %d files merged, "
424 424 "%d files removed, %d files unresolved\n") % stats)
425 425
426 426 def update(repo, node):
427 427 """update the working directory to node, merging linear changes"""
428 428 stats = mergemod.update(repo, node, False, False, None)
429 429 _showstats(repo, stats)
430 430 if stats[3]:
431 431 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
432 432 return stats[3] > 0
433 433
434 434 # naming conflict in clone()
435 435 _update = update
436 436
437 437 def clean(repo, node, show_stats=True):
438 438 """forcibly switch the working directory to node, clobbering changes"""
439 439 stats = mergemod.update(repo, node, False, True, None)
440 440 if show_stats:
441 441 _showstats(repo, stats)
442 442 return stats[3] > 0
443 443
444 444 def merge(repo, node, force=None, remind=True):
445 445 """Branch merge with node, resolving changes. Return true if any
446 446 unresolved conflicts."""
447 447 stats = mergemod.update(repo, node, True, force, False)
448 448 _showstats(repo, stats)
449 449 if stats[3]:
450 450 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
451 451 "or 'hg update -C .' to abandon\n"))
452 452 elif remind:
453 453 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
454 454 return stats[3] > 0
455 455
456 456 def _incoming(displaychlist, subreporecurse, ui, repo, source,
457 457 opts, buffered=False):
458 458 """
459 459 Helper for incoming / gincoming.
460 460 displaychlist gets called with
461 461 (remoterepo, incomingchangesetlist, displayer) parameters,
462 462 and is supposed to contain only code that can't be unified.
463 463 """
464 464 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
465 465 other = peer(repo, opts, source)
466 466 ui.status(_('comparing with %s\n') % util.hidepassword(source))
467 467 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
468 468
469 469 if revs:
470 470 revs = [other.lookup(rev) for rev in revs]
471 471 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
472 472 revs, opts["bundle"], opts["force"])
473 473 try:
474 474 if not chlist:
475 475 ui.status(_("no changes found\n"))
476 476 return subreporecurse()
477 477
478 478 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
479 479
480 480 # XXX once graphlog extension makes it into core,
481 481 # should be replaced by a if graph/else
482 482 displaychlist(other, chlist, displayer)
483 483
484 484 displayer.close()
485 485 finally:
486 486 cleanupfn()
487 487 subreporecurse()
488 488 return 0 # exit code is zero since we found incoming changes
489 489
490 490 def incoming(ui, repo, source, opts):
491 491 def subreporecurse():
492 492 ret = 1
493 493 if opts.get('subrepos'):
494 494 ctx = repo[None]
495 495 for subpath in sorted(ctx.substate):
496 496 sub = ctx.sub(subpath)
497 497 ret = min(ret, sub.incoming(ui, source, opts))
498 498 return ret
499 499
500 500 def display(other, chlist, displayer):
501 501 limit = cmdutil.loglimit(opts)
502 502 if opts.get('newest_first'):
503 503 chlist.reverse()
504 504 count = 0
505 505 for n in chlist:
506 506 if limit is not None and count >= limit:
507 507 break
508 508 parents = [p for p in other.changelog.parents(n) if p != nullid]
509 509 if opts.get('no_merges') and len(parents) == 2:
510 510 continue
511 511 count += 1
512 512 displayer.show(other[n])
513 513 return _incoming(display, subreporecurse, ui, repo, source, opts)
514 514
515 515 def _outgoing(ui, repo, dest, opts):
516 516 dest = ui.expandpath(dest or 'default-push', dest or 'default')
517 517 dest, branches = parseurl(dest, opts.get('branch'))
518 518 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
519 519 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
520 520 if revs:
521 521 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
522 522
523 523 other = peer(repo, opts, dest)
524 524 outgoing = discovery.findcommonoutgoing(repo, other, revs,
525 525 force=opts.get('force'))
526 526 o = outgoing.missing
527 527 if not o:
528 528 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
529 529 return None
530 530 return o
531 531
532 532 def outgoing(ui, repo, dest, opts):
533 533 def recurse():
534 534 ret = 1
535 535 if opts.get('subrepos'):
536 536 ctx = repo[None]
537 537 for subpath in sorted(ctx.substate):
538 538 sub = ctx.sub(subpath)
539 539 ret = min(ret, sub.outgoing(ui, dest, opts))
540 540 return ret
541 541
542 542 limit = cmdutil.loglimit(opts)
543 543 o = _outgoing(ui, repo, dest, opts)
544 544 if o is None:
545 545 return recurse()
546 546
547 547 if opts.get('newest_first'):
548 548 o.reverse()
549 549 displayer = cmdutil.show_changeset(ui, repo, opts)
550 550 count = 0
551 551 for n in o:
552 552 if limit is not None and count >= limit:
553 553 break
554 554 parents = [p for p in repo.changelog.parents(n) if p != nullid]
555 555 if opts.get('no_merges') and len(parents) == 2:
556 556 continue
557 557 count += 1
558 558 displayer.show(repo[n])
559 559 displayer.close()
560 560 recurse()
561 561 return 0 # exit code is zero since we found outgoing changes
562 562
563 563 def revert(repo, node, choose):
564 564 """revert changes to revision in node without updating dirstate"""
565 565 return mergemod.update(repo, node, False, True, choose)[3] > 0
566 566
567 567 def verify(repo):
568 568 """verify the consistency of a repository"""
569 569 return verifymod.verify(repo)
570 570
571 571 def remoteui(src, opts):
572 572 'build a remote ui from ui or repo and opts'
573 573 if util.safehasattr(src, 'baseui'): # looks like a repository
574 574 dst = src.baseui.copy() # drop repo-specific config
575 575 src = src.ui # copy target options from repo
576 576 else: # assume it's a global ui object
577 577 dst = src.copy() # keep all global options
578 578
579 579 # copy ssh-specific options
580 580 for o in 'ssh', 'remotecmd':
581 581 v = opts.get(o) or src.config('ui', o)
582 582 if v:
583 583 dst.setconfig("ui", o, v)
584 584
585 585 # copy bundle-specific options
586 586 r = src.config('bundle', 'mainreporoot')
587 587 if r:
588 588 dst.setconfig('bundle', 'mainreporoot', r)
589 589
590 590 # copy selected local settings to the remote ui
591 591 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
592 592 for key, val in src.configitems(sect):
593 593 dst.setconfig(sect, key, val)
594 594 v = src.config('web', 'cacerts')
595 595 if v:
596 596 dst.setconfig('web', 'cacerts', util.expandpath(v))
597 597
598 598 return dst
@@ -1,207 +1,225 b''
1 1 $ "$TESTDIR/hghave" serve || exit 80
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo foo>foo
6 6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
7 7 $ echo foo>foo.d/foo
8 8 $ echo bar>foo.d/bAr.hg.d/BaR
9 9 $ echo bar>foo.d/baR.d.hg/bAR
10 10 $ hg commit -A -m 1
11 11 adding foo
12 12 adding foo.d/bAr.hg.d/BaR
13 13 adding foo.d/baR.d.hg/bAR
14 14 adding foo.d/foo
15 15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
16 16 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
17 17
18 18 Test server address cannot be reused
19 19
20 20 #if windows
21 21 $ hg serve -p $HGPORT1 2>&1
22 22 abort: cannot start server at ':$HGPORT1': * (glob)
23 23 [255]
24 24 #else
25 25 $ hg serve -p $HGPORT1 2>&1
26 26 abort: cannot start server at ':$HGPORT1': Address already in use
27 27 [255]
28 28 #endif
29 29 $ cd ..
30 30 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
31 31
32 32 clone via stream
33 33
34 34 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
35 35 streaming all changes
36 36 6 files to transfer, 606 bytes of data
37 37 transferred * bytes in * seconds (*/sec) (glob)
38 38 updating to branch default
39 39 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 40 $ hg verify -R copy
41 41 checking changesets
42 42 checking manifests
43 43 crosschecking files in changesets and manifests
44 44 checking files
45 45 4 files, 1 changesets, 4 total revisions
46 46
47 47 try to clone via stream, should use pull instead
48 48
49 49 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
50 50 requesting all changes
51 51 adding changesets
52 52 adding manifests
53 53 adding file changes
54 54 added 1 changesets with 4 changes to 4 files
55 55 updating to branch default
56 56 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 57
58 58 clone via pull
59 59
60 60 $ hg clone http://localhost:$HGPORT1/ copy-pull
61 61 requesting all changes
62 62 adding changesets
63 63 adding manifests
64 64 adding file changes
65 65 added 1 changesets with 4 changes to 4 files
66 66 updating to branch default
67 67 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 68 $ hg verify -R copy-pull
69 69 checking changesets
70 70 checking manifests
71 71 crosschecking files in changesets and manifests
72 72 checking files
73 73 4 files, 1 changesets, 4 total revisions
74 74 $ cd test
75 75 $ echo bar > bar
76 76 $ hg commit -A -d '1 0' -m 2
77 77 adding bar
78 78 $ cd ..
79 79
80 clone over http with --update
81
82 $ hg clone http://localhost:$HGPORT1/ updated --update 0
83 requesting all changes
84 adding changesets
85 adding manifests
86 adding file changes
87 added 2 changesets with 5 changes to 5 files
88 updating to branch default
89 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 $ hg log -r . -R updated
91 changeset: 0:8b6053c928fe
92 user: test
93 date: Thu Jan 01 00:00:00 1970 +0000
94 summary: 1
95
96 $ rm -rf updated
97
80 98 incoming via HTTP
81 99
82 100 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
83 101 adding changesets
84 102 adding manifests
85 103 adding file changes
86 104 added 1 changesets with 4 changes to 4 files
87 105 updating to branch default
88 106 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 107 $ cd partial
90 108 $ touch LOCAL
91 109 $ hg ci -qAm LOCAL
92 110 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
93 111 comparing with http://localhost:$HGPORT1/
94 112 searching for changes
95 113 2
96 114 $ cd ..
97 115
98 116 pull
99 117
100 118 $ cd copy-pull
101 119 $ echo '[hooks]' >> .hg/hgrc
102 120 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
103 121 $ hg pull
104 122 pulling from http://localhost:$HGPORT1/
105 123 searching for changes
106 124 adding changesets
107 125 adding manifests
108 126 adding file changes
109 127 added 1 changesets with 1 changes to 1 files
110 128 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost:$HGPORT1/
111 129 (run 'hg update' to get a working copy)
112 130 $ cd ..
113 131
114 132 clone from invalid URL
115 133
116 134 $ hg clone http://localhost:$HGPORT/bad
117 135 abort: HTTP Error 404: Not Found
118 136 [255]
119 137
120 138 test http authentication
121 139 + use the same server to test server side streaming preference
122 140
123 141 $ cd test
124 142 $ cat << EOT > userpass.py
125 143 > import base64
126 144 > from mercurial.hgweb import common
127 145 > def perform_authentication(hgweb, req, op):
128 146 > auth = req.env.get('HTTP_AUTHORIZATION')
129 147 > if not auth:
130 148 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
131 149 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
132 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
150 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
133 151 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
134 152 > def extsetup():
135 153 > common.permhooks.insert(0, perform_authentication)
136 154 > EOT
137 155 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
138 156 > --config server.preferuncompressed=True
139 157 $ cat pid >> $DAEMON_PIDS
140 158
141 $ hg id http://localhost:$HGPORT2/
159 $ hg id http://localhost:$HGPORT2/
142 160 abort: http authorization required
143 161 [255]
144 $ hg id http://user@localhost:$HGPORT2/
162 $ hg id http://user@localhost:$HGPORT2/
145 163 abort: http authorization required
146 164 [255]
147 165 $ hg id http://user:pass@localhost:$HGPORT2/
148 166 5fed3813f7f5
149 $ echo '[auth]' >> .hg/hgrc
167 $ echo '[auth]' >> .hg/hgrc
150 168 $ echo 'l.schemes=http' >> .hg/hgrc
151 169 $ echo 'l.prefix=lo' >> .hg/hgrc
152 170 $ echo 'l.username=user' >> .hg/hgrc
153 171 $ echo 'l.password=pass' >> .hg/hgrc
154 $ hg id http://localhost:$HGPORT2/
172 $ hg id http://localhost:$HGPORT2/
155 173 5fed3813f7f5
156 $ hg id http://localhost:$HGPORT2/
174 $ hg id http://localhost:$HGPORT2/
157 175 5fed3813f7f5
158 $ hg id http://user@localhost:$HGPORT2/
176 $ hg id http://user@localhost:$HGPORT2/
159 177 5fed3813f7f5
160 178 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
161 179 streaming all changes
162 180 7 files to transfer, 916 bytes of data
163 181 transferred * bytes in * seconds (*/sec) (glob)
164 182 updating to branch default
165 183 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
166 184
167 $ hg id http://user2@localhost:$HGPORT2/
185 $ hg id http://user2@localhost:$HGPORT2/
168 186 abort: http authorization required
169 187 [255]
170 188 $ hg id http://user:pass2@localhost:$HGPORT2/
171 189 abort: HTTP Error 403: no
172 190 [255]
173 191
174 192 $ cd ..
175 193
176 194 clone of serve with repo in root and unserved subrepo (issue2970)
177 195
178 196 $ hg --cwd test init sub
179 197 $ echo empty > test/sub/empty
180 198 $ hg --cwd test/sub add empty
181 199 $ hg --cwd test/sub commit -qm 'add empty'
182 200 $ hg --cwd test/sub tag -r 0 something
183 201 $ echo sub = sub > test/.hgsub
184 202 $ hg --cwd test add .hgsub
185 203 $ hg --cwd test commit -qm 'add subrepo'
186 204 $ hg clone http://localhost:$HGPORT noslash-clone
187 205 requesting all changes
188 206 adding changesets
189 207 adding manifests
190 208 adding file changes
191 209 added 3 changesets with 7 changes to 7 files
192 210 updating to branch default
193 211 abort: HTTP Error 404: Not Found
194 212 [255]
195 213 $ hg clone http://localhost:$HGPORT/ slash-clone
196 214 requesting all changes
197 215 adding changesets
198 216 adding manifests
199 217 adding file changes
200 218 added 3 changesets with 7 changes to 7 files
201 219 updating to branch default
202 220 abort: HTTP Error 404: Not Found
203 221 [255]
204 222
205 223 check error log
206 224
207 225 $ cat error.log
General Comments 0
You need to be logged in to leave comments. Login now