##// END OF EJS Templates
hg: rearrange peer scheme lookup...
Matt Mackall -
r14605:9f1139cf default
parent child Browse files
Show More
@@ -1,98 +1,98 b''
1 1 # Copyright 2009, Alexander Solovyov <piranha@piranha.org.ua>
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6 """extend schemes with shortcuts to repository swarms
7 7
8 8 This extension allows you to specify shortcuts for parent URLs with a
9 9 lot of repositories to act like a scheme, for example::
10 10
11 11 [schemes]
12 12 py = http://code.python.org/hg/
13 13
14 14 After that you can use it like::
15 15
16 16 hg clone py://trunk/
17 17
18 18 Additionally there is support for some more complex schemas, for
19 19 example used by Google Code::
20 20
21 21 [schemes]
22 22 gcode = http://{1}.googlecode.com/hg/
23 23
24 24 The syntax is taken from Mercurial templates, and you have unlimited
25 25 number of variables, starting with ``{1}`` and continuing with
26 26 ``{2}``, ``{3}`` and so on. This variables will receive parts of URL
27 27 supplied, split by ``/``. Anything not specified as ``{part}`` will be
28 28 just appended to an URL.
29 29
30 30 For convenience, the extension adds these schemes by default::
31 31
32 32 [schemes]
33 33 py = http://hg.python.org/
34 34 bb = https://bitbucket.org/
35 35 bb+ssh = ssh://hg@bitbucket.org/
36 36 gcode = https://{1}.googlecode.com/hg/
37 37 kiln = https://{1}.kilnhg.com/Repo/
38 38
39 39 You can override a predefined scheme by defining a new scheme with the
40 40 same name.
41 41 """
42 42
43 43 import os, re
44 44 from mercurial import extensions, hg, templater, util
45 45 from mercurial.i18n import _
46 46
47 47
48 48 class ShortRepository(object):
49 49 def __init__(self, url, scheme, templater):
50 50 self.scheme = scheme
51 51 self.templater = templater
52 52 self.url = url
53 53 try:
54 54 self.parts = max(map(int, re.findall(r'\{(\d+)\}', self.url)))
55 55 except ValueError:
56 56 self.parts = 0
57 57
58 58 def __repr__(self):
59 59 return '<ShortRepository: %s>' % self.scheme
60 60
61 61 def instance(self, ui, url, create):
62 62 # Should this use urlmod.url(), or is manual parsing better?
63 63 url = url.split('://', 1)[1]
64 64 parts = url.split('/', self.parts)
65 65 if len(parts) > self.parts:
66 66 tail = parts[-1]
67 67 parts = parts[:-1]
68 68 else:
69 69 tail = ''
70 70 context = dict((str(i + 1), v) for i, v in enumerate(parts))
71 71 url = ''.join(self.templater.process(self.url, context)) + tail
72 72 return hg._peerlookup(url).instance(ui, url, create)
73 73
74 74 def hasdriveletter(orig, path):
75 75 for scheme in schemes:
76 76 if path.startswith(scheme + ':'):
77 77 return False
78 78 return orig(path)
79 79
80 80 schemes = {
81 81 'py': 'http://hg.python.org/',
82 82 'bb': 'https://bitbucket.org/',
83 83 'bb+ssh': 'ssh://hg@bitbucket.org/',
84 84 'gcode': 'https://{1}.googlecode.com/hg/',
85 85 'kiln': 'https://{1}.kilnhg.com/Repo/'
86 86 }
87 87
88 88 def extsetup(ui):
89 89 schemes.update(dict(ui.configitems('schemes')))
90 90 t = templater.engine(lambda x: x)
91 91 for scheme, url in schemes.items():
92 92 if (os.name == 'nt' and len(scheme) == 1 and scheme.isalpha()
93 93 and os.path.exists('%s:\\' % scheme)):
94 94 raise util.Abort(_('custom scheme %s:// conflicts with drive '
95 95 'letter %s:\\\n') % (scheme, scheme.upper()))
96 hg._peerschemes[scheme] = ShortRepository(url, scheme, t)
96 hg.peerschemes[scheme] = ShortRepository(url, scheme, t)
97 97
98 98 extensions.wrapfunction(util, 'hasdriveletter', hasdriveletter)
@@ -1,582 +1,564 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, httprepo, sshrepo, statichttprepo, bookmarks
13 13 import lock, util, extensions, error, node
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.localpath(path))
21 21 return (os.path.isfile(path) and bundlerepo or localrepo)
22 22
23 23 def addbranchrevs(lrepo, repo, branches, revs):
24 24 hashbranch, branches = branches
25 25 if not hashbranch and not branches:
26 26 return revs or None, revs and revs[0] or None
27 27 revs = revs and list(revs) or []
28 28 if not repo.capable('branchmap'):
29 29 if branches:
30 30 raise util.Abort(_("remote branch lookup not supported"))
31 31 revs.append(hashbranch)
32 32 return revs, revs[0]
33 33 branchmap = repo.branchmap()
34 34
35 35 def primary(branch):
36 36 if branch == '.':
37 37 if not lrepo or not lrepo.local():
38 38 raise util.Abort(_("dirstate branch not accessible"))
39 39 branch = lrepo.dirstate.branch()
40 40 if branch in branchmap:
41 41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
42 42 return True
43 43 else:
44 44 return False
45 45
46 46 for branch in branches:
47 47 if not primary(branch):
48 48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 49 if hashbranch:
50 50 if not primary(hashbranch):
51 51 revs.append(hashbranch)
52 52 return revs, revs[0]
53 53
54 54 def parseurl(path, branches=None):
55 55 '''parse url#branch, returning (url, (branch, branches))'''
56 56
57 57 u = util.url(path)
58 58 branch = None
59 59 if u.fragment:
60 60 branch = u.fragment
61 61 u.fragment = None
62 62 return str(u), (branch, branches or [])
63 63
64 _reposchemes = {
65 'bundle': bundlerepo,
66 'file': _local,
67 'http': httprepo,
68 'https': httprepo,
69 'ssh': sshrepo,
70 'static-http': statichttprepo,
71 }
72
73 def _repolookup(path):
74 u = util.url(path)
75 scheme = u.scheme or 'file'
76 thing = _reposchemes.get(scheme) or _reposchemes['file']
77 try:
78 return thing(path)
79 except TypeError:
80 return thing
81
82 def islocal(repo):
83 '''return true if repo or path is local'''
84 if isinstance(repo, str):
85 try:
86 return _repolookup(repo).islocal(repo)
87 except AttributeError:
88 return False
89 return repo.local()
90
91 def repository(ui, path='', create=False):
92 """return a repository object for the specified path"""
93 repo = _repolookup(path).instance(ui, path, create)
94 ui = getattr(repo, "ui", ui)
95 for name, module in extensions.extensions():
96 hook = getattr(module, 'reposetup', None)
97 if hook:
98 hook(ui, repo)
99 return repo
100
101 _peerschemes = {
64 peerschemes = {
102 65 'bundle': bundlerepo,
103 66 'file': _local,
104 67 'http': httprepo,
105 68 'https': httprepo,
106 69 'ssh': sshrepo,
107 70 'static-http': statichttprepo,
108 71 }
109 72
110 73 def _peerlookup(path):
111 74 u = util.url(path)
112 75 scheme = u.scheme or 'file'
113 thing = _peerschemes.get(scheme) or _peerschemes['file']
76 thing = peerschemes.get(scheme) or peerschemes['file']
114 77 try:
115 78 return thing(path)
116 79 except TypeError:
117 80 return thing
118 81
82 def islocal(repo):
83 '''return true if repo or path is local'''
84 if isinstance(repo, str):
85 try:
86 return _peerlookup(repo).islocal(repo)
87 except AttributeError:
88 return False
89 return repo.local()
90
91 def repository(ui, path='', create=False):
92 """return a repository object for the specified path"""
93 repo = _peerlookup(path).instance(ui, path, create)
94 ui = getattr(repo, "ui", ui)
95 for name, module in extensions.extensions():
96 hook = getattr(module, 'reposetup', None)
97 if hook:
98 hook(ui, repo)
99 return repo
100
119 101 def peer(ui, opts, path, create=False):
120 102 '''return a repository peer for the specified path'''
121 103 rui = remoteui(ui, opts)
122 104 return _peerlookup(path).instance(rui, path, create)
123 105
124 106 def defaultdest(source):
125 107 '''return default destination of clone if none is given'''
126 108 return os.path.basename(os.path.normpath(source))
127 109
128 110 def share(ui, source, dest=None, update=True):
129 111 '''create a shared repository'''
130 112
131 113 if not islocal(source):
132 114 raise util.Abort(_('can only share local repositories'))
133 115
134 116 if not dest:
135 117 dest = defaultdest(source)
136 118 else:
137 119 dest = ui.expandpath(dest)
138 120
139 121 if isinstance(source, str):
140 122 origsource = ui.expandpath(source)
141 123 source, branches = parseurl(origsource)
142 124 srcrepo = repository(ui, source)
143 125 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
144 126 else:
145 127 srcrepo = source
146 128 origsource = source = srcrepo.url()
147 129 checkout = None
148 130
149 131 sharedpath = srcrepo.sharedpath # if our source is already sharing
150 132
151 133 root = os.path.realpath(dest)
152 134 roothg = os.path.join(root, '.hg')
153 135
154 136 if os.path.exists(roothg):
155 137 raise util.Abort(_('destination already exists'))
156 138
157 139 if not os.path.isdir(root):
158 140 os.mkdir(root)
159 141 util.makedir(roothg, notindexed=True)
160 142
161 143 requirements = ''
162 144 try:
163 145 requirements = srcrepo.opener.read('requires')
164 146 except IOError, inst:
165 147 if inst.errno != errno.ENOENT:
166 148 raise
167 149
168 150 requirements += 'shared\n'
169 151 util.writefile(os.path.join(roothg, 'requires'), requirements)
170 152 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
171 153
172 154 r = repository(ui, root)
173 155
174 156 default = srcrepo.ui.config('paths', 'default')
175 157 if default:
176 158 fp = r.opener("hgrc", "w", text=True)
177 159 fp.write("[paths]\n")
178 160 fp.write("default = %s\n" % default)
179 161 fp.close()
180 162
181 163 if update:
182 164 r.ui.status(_("updating working directory\n"))
183 165 if update is not True:
184 166 checkout = update
185 167 for test in (checkout, 'default', 'tip'):
186 168 if test is None:
187 169 continue
188 170 try:
189 171 uprev = r.lookup(test)
190 172 break
191 173 except error.RepoLookupError:
192 174 continue
193 175 _update(r, uprev)
194 176
195 177 def clone(ui, opts, source, dest=None, pull=False, rev=None, update=True,
196 178 stream=False, branch=None):
197 179 """Make a copy of an existing repository.
198 180
199 181 Create a copy of an existing repository in a new directory. The
200 182 source and destination are URLs, as passed to the repository
201 183 function. Returns a pair of repository objects, the source and
202 184 newly created destination.
203 185
204 186 The location of the source is added to the new repository's
205 187 .hg/hgrc file, as the default to be used for future pulls and
206 188 pushes.
207 189
208 190 If an exception is raised, the partly cloned/updated destination
209 191 repository will be deleted.
210 192
211 193 Arguments:
212 194
213 195 source: repository object or URL
214 196
215 197 dest: URL of destination repository to create (defaults to base
216 198 name of source repository)
217 199
218 200 pull: always pull from source repository, even in local case
219 201
220 202 stream: stream raw data uncompressed from repository (fast over
221 203 LAN, slow over WAN)
222 204
223 205 rev: revision to clone up to (implies pull=True)
224 206
225 207 update: update working directory after clone completes, if
226 208 destination is local repository (True means update to default rev,
227 209 anything else is treated as a revision)
228 210
229 211 branch: branches to clone
230 212 """
231 213
232 214 if isinstance(source, str):
233 215 origsource = ui.expandpath(source)
234 216 source, branch = parseurl(origsource, branch)
235 217 srcrepo = repository(remoteui(ui, opts), source)
236 218 else:
237 219 srcrepo = source
238 220 branch = (None, branch or [])
239 221 origsource = source = srcrepo.url()
240 222 rev, checkout = addbranchrevs(srcrepo, srcrepo, branch, rev)
241 223
242 224 if dest is None:
243 225 dest = defaultdest(source)
244 226 ui.status(_("destination directory: %s\n") % dest)
245 227 else:
246 228 dest = ui.expandpath(dest)
247 229
248 230 dest = util.localpath(dest)
249 231 source = util.localpath(source)
250 232
251 233 if os.path.exists(dest):
252 234 if not os.path.isdir(dest):
253 235 raise util.Abort(_("destination '%s' already exists") % dest)
254 236 elif os.listdir(dest):
255 237 raise util.Abort(_("destination '%s' is not empty") % dest)
256 238
257 239 class DirCleanup(object):
258 240 def __init__(self, dir_):
259 241 self.rmtree = shutil.rmtree
260 242 self.dir_ = dir_
261 243 def close(self):
262 244 self.dir_ = None
263 245 def cleanup(self):
264 246 if self.dir_:
265 247 self.rmtree(self.dir_, True)
266 248
267 249 srclock = destlock = dircleanup = None
268 250 try:
269 251 abspath = origsource
270 252 if islocal(origsource):
271 253 abspath = os.path.abspath(util.localpath(origsource))
272 254
273 255 if islocal(dest):
274 256 dircleanup = DirCleanup(dest)
275 257
276 258 copy = False
277 259 if srcrepo.cancopy() and islocal(dest):
278 260 copy = not pull and not rev
279 261
280 262 if copy:
281 263 try:
282 264 # we use a lock here because if we race with commit, we
283 265 # can end up with extra data in the cloned revlogs that's
284 266 # not pointed to by changesets, thus causing verify to
285 267 # fail
286 268 srclock = srcrepo.lock(wait=False)
287 269 except error.LockError:
288 270 copy = False
289 271
290 272 if copy:
291 273 srcrepo.hook('preoutgoing', throw=True, source='clone')
292 274 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
293 275 if not os.path.exists(dest):
294 276 os.mkdir(dest)
295 277 else:
296 278 # only clean up directories we create ourselves
297 279 dircleanup.dir_ = hgdir
298 280 try:
299 281 destpath = hgdir
300 282 util.makedir(destpath, notindexed=True)
301 283 except OSError, inst:
302 284 if inst.errno == errno.EEXIST:
303 285 dircleanup.close()
304 286 raise util.Abort(_("destination '%s' already exists")
305 287 % dest)
306 288 raise
307 289
308 290 hardlink = None
309 291 num = 0
310 292 for f in srcrepo.store.copylist():
311 293 src = os.path.join(srcrepo.sharedpath, f)
312 294 dst = os.path.join(destpath, f)
313 295 dstbase = os.path.dirname(dst)
314 296 if dstbase and not os.path.exists(dstbase):
315 297 os.mkdir(dstbase)
316 298 if os.path.exists(src):
317 299 if dst.endswith('data'):
318 300 # lock to avoid premature writing to the target
319 301 destlock = lock.lock(os.path.join(dstbase, "lock"))
320 302 hardlink, n = util.copyfiles(src, dst, hardlink)
321 303 num += n
322 304 if hardlink:
323 305 ui.debug("linked %d files\n" % num)
324 306 else:
325 307 ui.debug("copied %d files\n" % num)
326 308
327 309 # we need to re-init the repo after manually copying the data
328 310 # into it
329 311 destrepo = repository(remoteui(ui, opts), dest)
330 312 srcrepo.hook('outgoing', source='clone',
331 313 node=node.hex(node.nullid))
332 314 else:
333 315 try:
334 316 destrepo = repository(remoteui(ui, opts), dest, create=True)
335 317 except OSError, inst:
336 318 if inst.errno == errno.EEXIST:
337 319 dircleanup.close()
338 320 raise util.Abort(_("destination '%s' already exists")
339 321 % dest)
340 322 raise
341 323
342 324 revs = None
343 325 if rev:
344 326 if not srcrepo.capable('lookup'):
345 327 raise util.Abort(_("src repository does not support "
346 328 "revision lookup and so doesn't "
347 329 "support clone by revision"))
348 330 revs = [srcrepo.lookup(r) for r in rev]
349 331 checkout = revs[0]
350 332 if destrepo.local():
351 333 destrepo.clone(srcrepo, heads=revs, stream=stream)
352 334 elif srcrepo.local():
353 335 srcrepo.push(destrepo, revs=revs)
354 336 else:
355 337 raise util.Abort(_("clone from remote to remote not supported"))
356 338
357 339 if dircleanup:
358 340 dircleanup.close()
359 341
360 342 if destrepo.local():
361 343 fp = destrepo.opener("hgrc", "w", text=True)
362 344 fp.write("[paths]\n")
363 345 fp.write("default = %s\n" % abspath)
364 346 fp.close()
365 347
366 348 destrepo.ui.setconfig('paths', 'default', abspath)
367 349
368 350 if update:
369 351 if update is not True:
370 352 checkout = update
371 353 if srcrepo.local():
372 354 checkout = srcrepo.lookup(update)
373 355 for test in (checkout, 'default', 'tip'):
374 356 if test is None:
375 357 continue
376 358 try:
377 359 uprev = destrepo.lookup(test)
378 360 break
379 361 except error.RepoLookupError:
380 362 continue
381 363 bn = destrepo[uprev].branch()
382 364 destrepo.ui.status(_("updating to branch %s\n") % bn)
383 365 _update(destrepo, uprev)
384 366
385 367 # clone all bookmarks
386 368 if destrepo.local() and srcrepo.capable("pushkey"):
387 369 rb = srcrepo.listkeys('bookmarks')
388 370 for k, n in rb.iteritems():
389 371 try:
390 372 m = destrepo.lookup(n)
391 373 destrepo._bookmarks[k] = m
392 374 except error.RepoLookupError:
393 375 pass
394 376 if rb:
395 377 bookmarks.write(destrepo)
396 378 elif srcrepo.local() and destrepo.capable("pushkey"):
397 379 for k, n in srcrepo._bookmarks.iteritems():
398 380 destrepo.pushkey('bookmarks', k, '', hex(n))
399 381
400 382 return srcrepo, destrepo
401 383 finally:
402 384 release(srclock, destlock)
403 385 if dircleanup is not None:
404 386 dircleanup.cleanup()
405 387
406 388 def _showstats(repo, stats):
407 389 repo.ui.status(_("%d files updated, %d files merged, "
408 390 "%d files removed, %d files unresolved\n") % stats)
409 391
410 392 def update(repo, node):
411 393 """update the working directory to node, merging linear changes"""
412 394 stats = mergemod.update(repo, node, False, False, None)
413 395 _showstats(repo, stats)
414 396 if stats[3]:
415 397 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
416 398 return stats[3] > 0
417 399
418 400 # naming conflict in clone()
419 401 _update = update
420 402
421 403 def clean(repo, node, show_stats=True):
422 404 """forcibly switch the working directory to node, clobbering changes"""
423 405 stats = mergemod.update(repo, node, False, True, None)
424 406 if show_stats:
425 407 _showstats(repo, stats)
426 408 return stats[3] > 0
427 409
428 410 def merge(repo, node, force=None, remind=True):
429 411 """Branch merge with node, resolving changes. Return true if any
430 412 unresolved conflicts."""
431 413 stats = mergemod.update(repo, node, True, force, False)
432 414 _showstats(repo, stats)
433 415 if stats[3]:
434 416 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
435 417 "or 'hg update -C .' to abandon\n"))
436 418 elif remind:
437 419 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
438 420 return stats[3] > 0
439 421
440 422 def _incoming(displaychlist, subreporecurse, ui, repo, source,
441 423 opts, buffered=False):
442 424 """
443 425 Helper for incoming / gincoming.
444 426 displaychlist gets called with
445 427 (remoterepo, incomingchangesetlist, displayer) parameters,
446 428 and is supposed to contain only code that can't be unified.
447 429 """
448 430 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
449 431 other = peer(repo, opts, source)
450 432 ui.status(_('comparing with %s\n') % util.hidepassword(source))
451 433 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
452 434
453 435 if revs:
454 436 revs = [other.lookup(rev) for rev in revs]
455 437 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
456 438 revs, opts["bundle"], opts["force"])
457 439 try:
458 440 if not chlist:
459 441 ui.status(_("no changes found\n"))
460 442 return subreporecurse()
461 443
462 444 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
463 445
464 446 # XXX once graphlog extension makes it into core,
465 447 # should be replaced by a if graph/else
466 448 displaychlist(other, chlist, displayer)
467 449
468 450 displayer.close()
469 451 finally:
470 452 cleanupfn()
471 453 subreporecurse()
472 454 return 0 # exit code is zero since we found incoming changes
473 455
474 456 def incoming(ui, repo, source, opts):
475 457 def subreporecurse():
476 458 ret = 1
477 459 if opts.get('subrepos'):
478 460 ctx = repo[None]
479 461 for subpath in sorted(ctx.substate):
480 462 sub = ctx.sub(subpath)
481 463 ret = min(ret, sub.incoming(ui, source, opts))
482 464 return ret
483 465
484 466 def display(other, chlist, displayer):
485 467 limit = cmdutil.loglimit(opts)
486 468 if opts.get('newest_first'):
487 469 chlist.reverse()
488 470 count = 0
489 471 for n in chlist:
490 472 if limit is not None and count >= limit:
491 473 break
492 474 parents = [p for p in other.changelog.parents(n) if p != nullid]
493 475 if opts.get('no_merges') and len(parents) == 2:
494 476 continue
495 477 count += 1
496 478 displayer.show(other[n])
497 479 return _incoming(display, subreporecurse, ui, repo, source, opts)
498 480
499 481 def _outgoing(ui, repo, dest, opts):
500 482 dest = ui.expandpath(dest or 'default-push', dest or 'default')
501 483 dest, branches = parseurl(dest, opts.get('branch'))
502 484 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
503 485 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
504 486 if revs:
505 487 revs = [repo.lookup(rev) for rev in revs]
506 488
507 489 other = peer(repo, opts, dest)
508 490 common, outheads = discovery.findcommonoutgoing(repo, other, revs,
509 491 force=opts.get('force'))
510 492 o = repo.changelog.findmissing(common, outheads)
511 493 if not o:
512 494 ui.status(_("no changes found\n"))
513 495 return None
514 496 return o
515 497
516 498 def outgoing(ui, repo, dest, opts):
517 499 def recurse():
518 500 ret = 1
519 501 if opts.get('subrepos'):
520 502 ctx = repo[None]
521 503 for subpath in sorted(ctx.substate):
522 504 sub = ctx.sub(subpath)
523 505 ret = min(ret, sub.outgoing(ui, dest, opts))
524 506 return ret
525 507
526 508 limit = cmdutil.loglimit(opts)
527 509 o = _outgoing(ui, repo, dest, opts)
528 510 if o is None:
529 511 return recurse()
530 512
531 513 if opts.get('newest_first'):
532 514 o.reverse()
533 515 displayer = cmdutil.show_changeset(ui, repo, opts)
534 516 count = 0
535 517 for n in o:
536 518 if limit is not None and count >= limit:
537 519 break
538 520 parents = [p for p in repo.changelog.parents(n) if p != nullid]
539 521 if opts.get('no_merges') and len(parents) == 2:
540 522 continue
541 523 count += 1
542 524 displayer.show(repo[n])
543 525 displayer.close()
544 526 recurse()
545 527 return 0 # exit code is zero since we found outgoing changes
546 528
547 529 def revert(repo, node, choose):
548 530 """revert changes to revision in node without updating dirstate"""
549 531 return mergemod.update(repo, node, False, True, choose)[3] > 0
550 532
551 533 def verify(repo):
552 534 """verify the consistency of a repository"""
553 535 return verifymod.verify(repo)
554 536
555 537 def remoteui(src, opts):
556 538 'build a remote ui from ui or repo and opts'
557 539 if hasattr(src, 'baseui'): # looks like a repository
558 540 dst = src.baseui.copy() # drop repo-specific config
559 541 src = src.ui # copy target options from repo
560 542 else: # assume it's a global ui object
561 543 dst = src.copy() # keep all global options
562 544
563 545 # copy ssh-specific options
564 546 for o in 'ssh', 'remotecmd':
565 547 v = opts.get(o) or src.config('ui', o)
566 548 if v:
567 549 dst.setconfig("ui", o, v)
568 550
569 551 # copy bundle-specific options
570 552 r = src.config('bundle', 'mainreporoot')
571 553 if r:
572 554 dst.setconfig('bundle', 'mainreporoot', r)
573 555
574 556 # copy selected local settings to the remote ui
575 557 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
576 558 for key, val in src.configitems(sect):
577 559 dst.setconfig(sect, key, val)
578 560 v = src.config('web', 'cacerts')
579 561 if v:
580 562 dst.setconfig('web', 'cacerts', util.expandpath(v))
581 563
582 564 return dst
General Comments 0
You need to be logged in to leave comments. Login now