##// END OF EJS Templates
template: add a `paths` field to all entry in peerurls...
marmoute -
r47955:9c4d30b0 default
parent child Browse files
Show More
@@ -1,1007 +1,1012 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Olivia Mackall <olivia@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 from .i18n import _
11 11 from .node import (
12 12 hex,
13 13 wdirrev,
14 14 )
15 15
16 16 from . import (
17 17 diffutil,
18 18 encoding,
19 19 error,
20 20 hbisect,
21 21 i18n,
22 22 obsutil,
23 23 patch,
24 24 pycompat,
25 25 registrar,
26 26 scmutil,
27 27 templateutil,
28 28 util,
29 29 )
30 30 from .utils import (
31 31 stringutil,
32 32 urlutil,
33 33 )
34 34
35 35 _hybrid = templateutil.hybrid
36 36 hybriddict = templateutil.hybriddict
37 37 hybridlist = templateutil.hybridlist
38 38 compatdict = templateutil.compatdict
39 39 compatlist = templateutil.compatlist
40 40 _showcompatlist = templateutil._showcompatlist
41 41
42 42
43 43 def getlatesttags(context, mapping, pattern=None):
44 44 '''return date, distance and name for the latest tag of rev'''
45 45 repo = context.resource(mapping, b'repo')
46 46 ctx = context.resource(mapping, b'ctx')
47 47 cache = context.resource(mapping, b'cache')
48 48
49 49 cachename = b'latesttags'
50 50 if pattern is not None:
51 51 cachename += b'-' + pattern
52 52 match = stringutil.stringmatcher(pattern)[2]
53 53 else:
54 54 match = util.always
55 55
56 56 if cachename not in cache:
57 57 # Cache mapping from rev to a tuple with tag date, tag
58 58 # distance and tag name
59 59 cache[cachename] = {-1: (0, 0, [b'null'])}
60 60 latesttags = cache[cachename]
61 61
62 62 rev = ctx.rev()
63 63 todo = [rev]
64 64 while todo:
65 65 rev = todo.pop()
66 66 if rev in latesttags:
67 67 continue
68 68 ctx = repo[rev]
69 69 tags = [
70 70 t
71 71 for t in ctx.tags()
72 72 if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t))
73 73 ]
74 74 if tags:
75 75 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
76 76 continue
77 77 try:
78 78 ptags = [latesttags[p.rev()] for p in ctx.parents()]
79 79 if len(ptags) > 1:
80 80 if ptags[0][2] == ptags[1][2]:
81 81 # The tuples are laid out so the right one can be found by
82 82 # comparison in this case.
83 83 pdate, pdist, ptag = max(ptags)
84 84 else:
85 85
86 86 def key(x):
87 87 tag = x[2][0]
88 88 if ctx.rev() is None:
89 89 # only() doesn't support wdir
90 90 prevs = [c.rev() for c in ctx.parents()]
91 91 changes = repo.revs(b'only(%ld, %s)', prevs, tag)
92 92 changessincetag = len(changes) + 1
93 93 else:
94 94 changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag)
95 95 changessincetag = len(changes)
96 96 # Smallest number of changes since tag wins. Date is
97 97 # used as tiebreaker.
98 98 return [-changessincetag, x[0]]
99 99
100 100 pdate, pdist, ptag = max(ptags, key=key)
101 101 else:
102 102 pdate, pdist, ptag = ptags[0]
103 103 except KeyError:
104 104 # Cache miss - recurse
105 105 todo.append(rev)
106 106 todo.extend(p.rev() for p in ctx.parents())
107 107 continue
108 108 latesttags[rev] = pdate, pdist + 1, ptag
109 109 return latesttags[rev]
110 110
111 111
112 112 def getlogcolumns():
113 113 """Return a dict of log column labels"""
114 114 _ = pycompat.identity # temporarily disable gettext
115 115 # i18n: column positioning for "hg log"
116 116 columns = _(
117 117 b'bookmark: %s\n'
118 118 b'branch: %s\n'
119 119 b'changeset: %s\n'
120 120 b'copies: %s\n'
121 121 b'date: %s\n'
122 122 b'extra: %s=%s\n'
123 123 b'files+: %s\n'
124 124 b'files-: %s\n'
125 125 b'files: %s\n'
126 126 b'instability: %s\n'
127 127 b'manifest: %s\n'
128 128 b'obsolete: %s\n'
129 129 b'parent: %s\n'
130 130 b'phase: %s\n'
131 131 b'summary: %s\n'
132 132 b'tag: %s\n'
133 133 b'user: %s\n'
134 134 )
135 135 return dict(
136 136 zip(
137 137 [s.split(b':', 1)[0] for s in columns.splitlines()],
138 138 i18n._(columns).splitlines(True),
139 139 )
140 140 )
141 141
142 142
143 143 # basic internal templates
144 144 _changeidtmpl = b'{rev}:{node|formatnode}'
145 145
146 146 # default templates internally used for rendering of lists
147 147 defaulttempl = {
148 148 b'parent': _changeidtmpl + b' ',
149 149 b'manifest': _changeidtmpl,
150 150 b'file_copy': b'{name} ({source})',
151 151 b'envvar': b'{key}={value}',
152 152 b'extra': b'{key}={value|stringescape}',
153 153 }
154 154 # filecopy is preserved for compatibility reasons
155 155 defaulttempl[b'filecopy'] = defaulttempl[b'file_copy']
156 156
157 157 # keywords are callables (see registrar.templatekeyword for details)
158 158 keywords = {}
159 159 templatekeyword = registrar.templatekeyword(keywords)
160 160
161 161
162 162 @templatekeyword(b'author', requires={b'ctx'})
163 163 def showauthor(context, mapping):
164 164 """Alias for ``{user}``"""
165 165 return showuser(context, mapping)
166 166
167 167
168 168 @templatekeyword(b'bisect', requires={b'repo', b'ctx'})
169 169 def showbisect(context, mapping):
170 170 """String. The changeset bisection status."""
171 171 repo = context.resource(mapping, b'repo')
172 172 ctx = context.resource(mapping, b'ctx')
173 173 return hbisect.label(repo, ctx.node())
174 174
175 175
176 176 @templatekeyword(b'branch', requires={b'ctx'})
177 177 def showbranch(context, mapping):
178 178 """String. The name of the branch on which the changeset was
179 179 committed.
180 180 """
181 181 ctx = context.resource(mapping, b'ctx')
182 182 return ctx.branch()
183 183
184 184
185 185 @templatekeyword(b'branches', requires={b'ctx'})
186 186 def showbranches(context, mapping):
187 187 """List of strings. The name of the branch on which the
188 188 changeset was committed. Will be empty if the branch name was
189 189 default. (DEPRECATED)
190 190 """
191 191 ctx = context.resource(mapping, b'ctx')
192 192 branch = ctx.branch()
193 193 if branch != b'default':
194 194 return compatlist(
195 195 context, mapping, b'branch', [branch], plural=b'branches'
196 196 )
197 197 return compatlist(context, mapping, b'branch', [], plural=b'branches')
198 198
199 199
200 200 @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'})
201 201 def showbookmarks(context, mapping):
202 202 """List of strings. Any bookmarks associated with the
203 203 changeset. Also sets 'active', the name of the active bookmark.
204 204 """
205 205 repo = context.resource(mapping, b'repo')
206 206 ctx = context.resource(mapping, b'ctx')
207 207 bookmarks = ctx.bookmarks()
208 208 active = repo._activebookmark
209 209 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active}
210 210 f = _showcompatlist(context, mapping, b'bookmark', bookmarks)
211 211 return _hybrid(f, bookmarks, makemap, pycompat.identity)
212 212
213 213
214 214 @templatekeyword(b'children', requires={b'ctx'})
215 215 def showchildren(context, mapping):
216 216 """List of strings. The children of the changeset."""
217 217 ctx = context.resource(mapping, b'ctx')
218 218 childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
219 219 return compatlist(
220 220 context, mapping, b'children', childrevs, element=b'child'
221 221 )
222 222
223 223
224 224 # Deprecated, but kept alive for help generation a purpose.
225 225 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'})
226 226 def showcurrentbookmark(context, mapping):
227 227 """String. The active bookmark, if it is associated with the changeset.
228 228 (DEPRECATED)"""
229 229 return showactivebookmark(context, mapping)
230 230
231 231
232 232 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'})
233 233 def showactivebookmark(context, mapping):
234 234 """String. The active bookmark, if it is associated with the changeset."""
235 235 repo = context.resource(mapping, b'repo')
236 236 ctx = context.resource(mapping, b'ctx')
237 237 active = repo._activebookmark
238 238 if active and active in ctx.bookmarks():
239 239 return active
240 240 return b''
241 241
242 242
243 243 @templatekeyword(b'date', requires={b'ctx'})
244 244 def showdate(context, mapping):
245 245 """Date information. The date when the changeset was committed."""
246 246 ctx = context.resource(mapping, b'ctx')
247 247 # the default string format is '<float(unixtime)><tzoffset>' because
248 248 # python-hglib splits date at decimal separator.
249 249 return templateutil.date(ctx.date(), showfmt=b'%d.0%d')
250 250
251 251
252 252 @templatekeyword(b'desc', requires={b'ctx'})
253 253 def showdescription(context, mapping):
254 254 """String. The text of the changeset description."""
255 255 ctx = context.resource(mapping, b'ctx')
256 256 s = ctx.description()
257 257 if isinstance(s, encoding.localstr):
258 258 # try hard to preserve utf-8 bytes
259 259 return encoding.tolocal(encoding.fromlocal(s).strip())
260 260 elif isinstance(s, encoding.safelocalstr):
261 261 return encoding.safelocalstr(s.strip())
262 262 else:
263 263 return s.strip()
264 264
265 265
266 266 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'})
267 267 def showdiffstat(context, mapping):
268 268 """String. Statistics of changes with the following format:
269 269 "modified files: +added/-removed lines"
270 270 """
271 271 ui = context.resource(mapping, b'ui')
272 272 ctx = context.resource(mapping, b'ctx')
273 273 diffopts = diffutil.diffallopts(ui, {b'noprefix': False})
274 274 diff = ctx.diff(opts=diffopts)
275 275 stats = patch.diffstatdata(util.iterlines(diff))
276 276 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
277 277 return b'%d: +%d/-%d' % (len(stats), adds, removes)
278 278
279 279
280 280 @templatekeyword(b'envvars', requires={b'ui'})
281 281 def showenvvars(context, mapping):
282 282 """A dictionary of environment variables. (EXPERIMENTAL)"""
283 283 ui = context.resource(mapping, b'ui')
284 284 env = ui.exportableenviron()
285 285 env = util.sortdict((k, env[k]) for k in sorted(env))
286 286 return compatdict(context, mapping, b'envvar', env, plural=b'envvars')
287 287
288 288
289 289 @templatekeyword(b'extras', requires={b'ctx'})
290 290 def showextras(context, mapping):
291 291 """List of dicts with key, value entries of the 'extras'
292 292 field of this changeset."""
293 293 ctx = context.resource(mapping, b'ctx')
294 294 extras = ctx.extra()
295 295 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
296 296 makemap = lambda k: {b'key': k, b'value': extras[k]}
297 297 c = [makemap(k) for k in extras]
298 298 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras')
299 299 return _hybrid(
300 300 f,
301 301 extras,
302 302 makemap,
303 303 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])),
304 304 )
305 305
306 306
307 307 def _getfilestatus(context, mapping, listall=False):
308 308 ctx = context.resource(mapping, b'ctx')
309 309 revcache = context.resource(mapping, b'revcache')
310 310 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall:
311 311 stat = ctx.p1().status(
312 312 ctx, listignored=listall, listclean=listall, listunknown=listall
313 313 )
314 314 revcache[b'filestatus'] = stat
315 315 revcache[b'filestatusall'] = listall
316 316 return revcache[b'filestatus']
317 317
318 318
319 319 def _getfilestatusmap(context, mapping, listall=False):
320 320 revcache = context.resource(mapping, b'revcache')
321 321 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall:
322 322 stat = _getfilestatus(context, mapping, listall=listall)
323 323 revcache[b'filestatusmap'] = statmap = {}
324 324 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat):
325 325 statmap.update((f, char) for f in files)
326 326 return revcache[b'filestatusmap'] # {path: statchar}
327 327
328 328
329 329 @templatekeyword(
330 330 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'}
331 331 )
332 332 def showfilecopies(context, mapping):
333 333 """List of strings. Files copied in this changeset with
334 334 their sources.
335 335 """
336 336 repo = context.resource(mapping, b'repo')
337 337 ctx = context.resource(mapping, b'ctx')
338 338 cache = context.resource(mapping, b'cache')
339 339 copies = context.resource(mapping, b'revcache').get(b'copies')
340 340 if copies is None:
341 341 if b'getcopies' not in cache:
342 342 cache[b'getcopies'] = scmutil.getcopiesfn(repo)
343 343 getcopies = cache[b'getcopies']
344 344 copies = getcopies(ctx)
345 345 return templateutil.compatfilecopiesdict(
346 346 context, mapping, b'file_copy', copies
347 347 )
348 348
349 349
350 350 # showfilecopiesswitch() displays file copies only if copy records are
351 351 # provided before calling the templater, usually with a --copies
352 352 # command line switch.
353 353 @templatekeyword(b'file_copies_switch', requires={b'revcache'})
354 354 def showfilecopiesswitch(context, mapping):
355 355 """List of strings. Like "file_copies" but displayed
356 356 only if the --copied switch is set.
357 357 """
358 358 copies = context.resource(mapping, b'revcache').get(b'copies') or []
359 359 return templateutil.compatfilecopiesdict(
360 360 context, mapping, b'file_copy', copies
361 361 )
362 362
363 363
364 364 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'})
365 365 def showfileadds(context, mapping):
366 366 """List of strings. Files added by this changeset."""
367 367 ctx = context.resource(mapping, b'ctx')
368 368 return templateutil.compatfileslist(
369 369 context, mapping, b'file_add', ctx.filesadded()
370 370 )
371 371
372 372
373 373 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'})
374 374 def showfiledels(context, mapping):
375 375 """List of strings. Files removed by this changeset."""
376 376 ctx = context.resource(mapping, b'ctx')
377 377 return templateutil.compatfileslist(
378 378 context, mapping, b'file_del', ctx.filesremoved()
379 379 )
380 380
381 381
382 382 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'})
383 383 def showfilemods(context, mapping):
384 384 """List of strings. Files modified by this changeset."""
385 385 ctx = context.resource(mapping, b'ctx')
386 386 return templateutil.compatfileslist(
387 387 context, mapping, b'file_mod', ctx.filesmodified()
388 388 )
389 389
390 390
391 391 @templatekeyword(b'files', requires={b'ctx'})
392 392 def showfiles(context, mapping):
393 393 """List of strings. All files modified, added, or removed by this
394 394 changeset.
395 395 """
396 396 ctx = context.resource(mapping, b'ctx')
397 397 return templateutil.compatfileslist(context, mapping, b'file', ctx.files())
398 398
399 399
400 400 @templatekeyword(b'graphnode', requires={b'repo', b'ctx', b'cache'})
401 401 def showgraphnode(context, mapping):
402 402 """String. The character representing the changeset node in an ASCII
403 403 revision graph."""
404 404 repo = context.resource(mapping, b'repo')
405 405 ctx = context.resource(mapping, b'ctx')
406 406 cache = context.resource(mapping, b'cache')
407 407 return getgraphnode(repo, ctx, cache)
408 408
409 409
410 410 def getgraphnode(repo, ctx, cache):
411 411 return getgraphnodecurrent(repo, ctx, cache) or getgraphnodesymbol(ctx)
412 412
413 413
414 414 def getgraphnodecurrent(repo, ctx, cache):
415 415 wpnodes = repo.dirstate.parents()
416 416 if wpnodes[1] == repo.nullid:
417 417 wpnodes = wpnodes[:1]
418 418 if ctx.node() in wpnodes:
419 419 return b'@'
420 420 else:
421 421 merge_nodes = cache.get(b'merge_nodes')
422 422 if merge_nodes is None:
423 423 from . import mergestate as mergestatemod
424 424
425 425 mergestate = mergestatemod.mergestate.read(repo)
426 426 if mergestate.unresolvedcount():
427 427 merge_nodes = (mergestate.local, mergestate.other)
428 428 else:
429 429 merge_nodes = ()
430 430 cache[b'merge_nodes'] = merge_nodes
431 431
432 432 if ctx.node() in merge_nodes:
433 433 return b'%'
434 434 return b''
435 435
436 436
437 437 def getgraphnodesymbol(ctx):
438 438 if ctx.obsolete():
439 439 return b'x'
440 440 elif ctx.isunstable():
441 441 return b'*'
442 442 elif ctx.closesbranch():
443 443 return b'_'
444 444 else:
445 445 return b'o'
446 446
447 447
448 448 @templatekeyword(b'graphwidth', requires=())
449 449 def showgraphwidth(context, mapping):
450 450 """Integer. The width of the graph drawn by 'log --graph' or zero."""
451 451 # just hosts documentation; should be overridden by template mapping
452 452 return 0
453 453
454 454
455 455 @templatekeyword(b'index', requires=())
456 456 def showindex(context, mapping):
457 457 """Integer. The current iteration of the loop. (0 indexed)"""
458 458 # just hosts documentation; should be overridden by template mapping
459 459 raise error.Abort(_(b"can't use index in this context"))
460 460
461 461
462 462 @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'})
463 463 def showlatesttag(context, mapping):
464 464 """List of strings. The global tags on the most recent globally
465 465 tagged ancestor of this changeset. If no such tags exist, the list
466 466 consists of the single string "null".
467 467 """
468 468 return showlatesttags(context, mapping, None)
469 469
470 470
471 471 def showlatesttags(context, mapping, pattern):
472 472 """helper method for the latesttag keyword and function"""
473 473 latesttags = getlatesttags(context, mapping, pattern)
474 474
475 475 # latesttag[0] is an implementation detail for sorting csets on different
476 476 # branches in a stable manner- it is the date the tagged cset was created,
477 477 # not the date the tag was created. Therefore it isn't made visible here.
478 478 makemap = lambda v: {
479 479 b'changes': _showchangessincetag,
480 480 b'distance': latesttags[1],
481 481 b'latesttag': v, # BC with {latesttag % '{latesttag}'}
482 482 b'tag': v,
483 483 }
484 484
485 485 tags = latesttags[2]
486 486 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':')
487 487 return _hybrid(f, tags, makemap, pycompat.identity)
488 488
489 489
490 490 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'})
491 491 def showlatesttagdistance(context, mapping):
492 492 """Integer. Longest path to the latest tag."""
493 493 return getlatesttags(context, mapping)[1]
494 494
495 495
496 496 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'})
497 497 def showchangessincelatesttag(context, mapping):
498 498 """Integer. All ancestors not in the latest tag."""
499 499 tag = getlatesttags(context, mapping)[2][0]
500 500 mapping = context.overlaymap(mapping, {b'tag': tag})
501 501 return _showchangessincetag(context, mapping)
502 502
503 503
504 504 def _showchangessincetag(context, mapping):
505 505 repo = context.resource(mapping, b'repo')
506 506 ctx = context.resource(mapping, b'ctx')
507 507 offset = 0
508 508 revs = [ctx.rev()]
509 509 tag = context.symbol(mapping, b'tag')
510 510
511 511 # The only() revset doesn't currently support wdir()
512 512 if ctx.rev() is None:
513 513 offset = 1
514 514 revs = [p.rev() for p in ctx.parents()]
515 515
516 516 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset
517 517
518 518
519 519 # teach templater latesttags.changes is switched to (context, mapping) API
520 520 _showchangessincetag._requires = {b'repo', b'ctx'}
521 521
522 522
523 523 @templatekeyword(b'manifest', requires={b'repo', b'ctx'})
524 524 def showmanifest(context, mapping):
525 525 repo = context.resource(mapping, b'repo')
526 526 ctx = context.resource(mapping, b'ctx')
527 527 mnode = ctx.manifestnode()
528 528 if mnode is None:
529 529 mnode = repo.nodeconstants.wdirid
530 530 mrev = wdirrev
531 531 mhex = repo.nodeconstants.wdirhex
532 532 else:
533 533 mrev = repo.manifestlog.rev(mnode)
534 534 mhex = hex(mnode)
535 535 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex})
536 536 f = context.process(b'manifest', mapping)
537 537 return templateutil.hybriditem(
538 538 f, None, f, lambda x: {b'rev': mrev, b'node': mhex}
539 539 )
540 540
541 541
542 542 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'})
543 543 def showobsfate(context, mapping):
544 544 # this function returns a list containing pre-formatted obsfate strings.
545 545 #
546 546 # This function will be replaced by templates fragments when we will have
547 547 # the verbosity templatekw available.
548 548 succsandmarkers = showsuccsandmarkers(context, mapping)
549 549
550 550 ui = context.resource(mapping, b'ui')
551 551 repo = context.resource(mapping, b'repo')
552 552 values = []
553 553
554 554 for x in succsandmarkers.tovalue(context, mapping):
555 555 v = obsutil.obsfateprinter(
556 556 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid
557 557 )
558 558 values.append(v)
559 559
560 560 return compatlist(context, mapping, b"fate", values)
561 561
562 562
563 563 def shownames(context, mapping, namespace):
564 564 """helper method to generate a template keyword for a namespace"""
565 565 repo = context.resource(mapping, b'repo')
566 566 ctx = context.resource(mapping, b'ctx')
567 567 ns = repo.names.get(namespace)
568 568 if ns is None:
569 569 # namespaces.addnamespace() registers new template keyword, but
570 570 # the registered namespace might not exist in the current repo.
571 571 return
572 572 names = ns.names(repo, ctx.node())
573 573 return compatlist(
574 574 context, mapping, ns.templatename, names, plural=namespace
575 575 )
576 576
577 577
578 578 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'})
579 579 def shownamespaces(context, mapping):
580 580 """Dict of lists. Names attached to this changeset per
581 581 namespace."""
582 582 repo = context.resource(mapping, b'repo')
583 583 ctx = context.resource(mapping, b'ctx')
584 584
585 585 namespaces = util.sortdict()
586 586
587 587 def makensmapfn(ns):
588 588 # 'name' for iterating over namespaces, templatename for local reference
589 589 return lambda v: {b'name': v, ns.templatename: v}
590 590
591 591 for k, ns in pycompat.iteritems(repo.names):
592 592 names = ns.names(repo, ctx.node())
593 593 f = _showcompatlist(context, mapping, b'name', names)
594 594 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
595 595
596 596 f = _showcompatlist(context, mapping, b'namespace', list(namespaces))
597 597
598 598 def makemap(ns):
599 599 return {
600 600 b'namespace': ns,
601 601 b'names': namespaces[ns],
602 602 b'builtin': repo.names[ns].builtin,
603 603 b'colorname': repo.names[ns].colorname,
604 604 }
605 605
606 606 return _hybrid(f, namespaces, makemap, pycompat.identity)
607 607
608 608
609 609 @templatekeyword(b'negrev', requires={b'repo', b'ctx'})
610 610 def shownegrev(context, mapping):
611 611 """Integer. The repository-local changeset negative revision number,
612 612 which counts in the opposite direction."""
613 613 ctx = context.resource(mapping, b'ctx')
614 614 rev = ctx.rev()
615 615 if rev is None or rev < 0: # wdir() or nullrev?
616 616 return None
617 617 repo = context.resource(mapping, b'repo')
618 618 return rev - len(repo)
619 619
620 620
621 621 @templatekeyword(b'node', requires={b'ctx'})
622 622 def shownode(context, mapping):
623 623 """String. The changeset identification hash, as a 40 hexadecimal
624 624 digit string.
625 625 """
626 626 ctx = context.resource(mapping, b'ctx')
627 627 return ctx.hex()
628 628
629 629
630 630 @templatekeyword(b'obsolete', requires={b'ctx'})
631 631 def showobsolete(context, mapping):
632 632 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
633 633 ctx = context.resource(mapping, b'ctx')
634 634 if ctx.obsolete():
635 635 return b'obsolete'
636 636 return b''
637 637
638 638
639 639 @templatekeyword(b'onelinesummary', requires={b'ui', b'ctx'})
640 640 def showonelinesummary(context, mapping):
641 641 """String. A one-line summary for the ctx (not including trailing newline).
642 642 The default template be overridden in command-templates.oneline-summary."""
643 643 # Avoid cycle:
644 644 # mercurial.cmdutil -> mercurial.templatekw -> mercurial.cmdutil
645 645 from . import cmdutil
646 646
647 647 ui = context.resource(mapping, b'ui')
648 648 ctx = context.resource(mapping, b'ctx')
649 649 return cmdutil.format_changeset_summary(ui, ctx)
650 650
651 651
652 652 @templatekeyword(b'path', requires={b'fctx'})
653 653 def showpath(context, mapping):
654 654 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
655 655 fctx = context.resource(mapping, b'fctx')
656 656 return fctx.path()
657 657
658 658
659 659 @templatekeyword(b'peerurls', requires={b'repo'})
660 660 def showpeerurls(context, mapping):
661 661 """A dictionary of repository locations defined in the [paths] section
662 662 of your configuration file."""
663 663 repo = context.resource(mapping, b'repo')
664 664 # see commands.paths() for naming of dictionary keys
665 665 paths = repo.ui.paths
666 666 all_paths = urlutil.list_paths(repo.ui)
667 667 urls = util.sortdict((k, p.rawloc) for k, p in all_paths)
668 668
669 669 def makemap(k):
670 670 p = paths[k]
671 671 d = {b'name': k, b'url': p.rawloc}
672 d.update((o, v) for o, v in sorted(pycompat.iteritems(p.suboptions)))
672 sub_opts = util.sortdict(sorted(pycompat.iteritems(p.suboptions)))
673 d.update(sub_opts)
674 path_dict = util.sortdict()
675 path_dict[b'url'] = p.rawloc
676 path_dict.update(sub_opts)
677 d[b'urls'] = [path_dict]
673 678 return d
674 679
675 680 def format_one(k):
676 681 return b'%s=%s' % (k, urls[k])
677 682
678 683 return _hybrid(None, urls, makemap, format_one)
679 684
680 685
681 686 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'})
682 687 def showpredecessors(context, mapping):
683 688 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)"""
684 689 repo = context.resource(mapping, b'repo')
685 690 ctx = context.resource(mapping, b'ctx')
686 691 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
687 692 predecessors = pycompat.maplist(hex, predecessors)
688 693
689 694 return _hybrid(
690 695 None,
691 696 predecessors,
692 697 lambda x: {b'ctx': repo[x]},
693 698 lambda x: scmutil.formatchangeid(repo[x]),
694 699 )
695 700
696 701
697 702 @templatekeyword(b'reporoot', requires={b'repo'})
698 703 def showreporoot(context, mapping):
699 704 """String. The root directory of the current repository."""
700 705 repo = context.resource(mapping, b'repo')
701 706 return repo.root
702 707
703 708
704 709 @templatekeyword(b'size', requires={b'fctx'})
705 710 def showsize(context, mapping):
706 711 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
707 712 fctx = context.resource(mapping, b'fctx')
708 713 return fctx.size()
709 714
710 715
711 716 # requires 'fctx' to denote {status} depends on (ctx, path) pair
712 717 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'})
713 718 def showstatus(context, mapping):
714 719 """String. Status code of the current file. (EXPERIMENTAL)"""
715 720 path = templateutil.runsymbol(context, mapping, b'path')
716 721 path = templateutil.stringify(context, mapping, path)
717 722 if not path:
718 723 return
719 724 statmap = _getfilestatusmap(context, mapping)
720 725 if path not in statmap:
721 726 statmap = _getfilestatusmap(context, mapping, listall=True)
722 727 return statmap.get(path)
723 728
724 729
725 730 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'})
726 731 def showsuccessorssets(context, mapping):
727 732 """Returns a string of sets of successors for a changectx. Format used
728 733 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2
729 734 while also diverged into ctx3. (EXPERIMENTAL)"""
730 735 repo = context.resource(mapping, b'repo')
731 736 ctx = context.resource(mapping, b'ctx')
732 737 data = []
733 738
734 739 if ctx.obsolete():
735 740 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
736 741 ssets = [[hex(n) for n in ss] for ss in ssets]
737 742
738 743 for ss in ssets:
739 744 h = _hybrid(
740 745 None,
741 746 ss,
742 747 lambda x: {b'ctx': repo[x]},
743 748 lambda x: scmutil.formatchangeid(repo[x]),
744 749 )
745 750 data.append(h)
746 751
747 752 # Format the successorssets
748 753 def render(d):
749 754 return templateutil.stringify(context, mapping, d)
750 755
751 756 def gen(data):
752 757 yield b"; ".join(render(d) for d in data)
753 758
754 759 return _hybrid(
755 760 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity
756 761 )
757 762
758 763
759 764 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'})
760 765 def showsuccsandmarkers(context, mapping):
761 766 """Returns a list of dict for each final successor of ctx. The dict
762 767 contains successors node id in "successors" keys and the list of
763 768 obs-markers from ctx to the set of successors in "markers".
764 769 (EXPERIMENTAL)
765 770 """
766 771 repo = context.resource(mapping, b'repo')
767 772 ctx = context.resource(mapping, b'ctx')
768 773
769 774 values = obsutil.successorsandmarkers(repo, ctx)
770 775
771 776 if values is None:
772 777 values = []
773 778
774 779 # Format successors and markers to avoid exposing binary to templates
775 780 data = []
776 781 for i in values:
777 782 # Format successors
778 783 successors = i[b'successors']
779 784
780 785 successors = [hex(n) for n in successors]
781 786 successors = _hybrid(
782 787 None,
783 788 successors,
784 789 lambda x: {b'ctx': repo[x]},
785 790 lambda x: scmutil.formatchangeid(repo[x]),
786 791 )
787 792
788 793 # Format markers
789 794 finalmarkers = []
790 795 for m in i[b'markers']:
791 796 hexprec = hex(m[0])
792 797 hexsucs = tuple(hex(n) for n in m[1])
793 798 hexparents = None
794 799 if m[5] is not None:
795 800 hexparents = tuple(hex(n) for n in m[5])
796 801 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
797 802 finalmarkers.append(newmarker)
798 803
799 804 data.append({b'successors': successors, b'markers': finalmarkers})
800 805
801 806 return templateutil.mappinglist(data)
802 807
803 808
804 809 @templatekeyword(b'p1', requires={b'ctx'})
805 810 def showp1(context, mapping):
806 811 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
807 812 number, and ``{p1.node}`` for the identification hash."""
808 813 ctx = context.resource(mapping, b'ctx')
809 814 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl)
810 815
811 816
812 817 @templatekeyword(b'p2', requires={b'ctx'})
813 818 def showp2(context, mapping):
814 819 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
815 820 number, and ``{p2.node}`` for the identification hash."""
816 821 ctx = context.resource(mapping, b'ctx')
817 822 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl)
818 823
819 824
820 825 @templatekeyword(b'p1rev', requires={b'ctx'})
821 826 def showp1rev(context, mapping):
822 827 """Integer. The repository-local revision number of the changeset's
823 828 first parent, or -1 if the changeset has no parents. (DEPRECATED)"""
824 829 ctx = context.resource(mapping, b'ctx')
825 830 return ctx.p1().rev()
826 831
827 832
828 833 @templatekeyword(b'p2rev', requires={b'ctx'})
829 834 def showp2rev(context, mapping):
830 835 """Integer. The repository-local revision number of the changeset's
831 836 second parent, or -1 if the changeset has no second parent. (DEPRECATED)"""
832 837 ctx = context.resource(mapping, b'ctx')
833 838 return ctx.p2().rev()
834 839
835 840
836 841 @templatekeyword(b'p1node', requires={b'ctx'})
837 842 def showp1node(context, mapping):
838 843 """String. The identification hash of the changeset's first parent,
839 844 as a 40 digit hexadecimal string. If the changeset has no parents, all
840 845 digits are 0. (DEPRECATED)"""
841 846 ctx = context.resource(mapping, b'ctx')
842 847 return ctx.p1().hex()
843 848
844 849
845 850 @templatekeyword(b'p2node', requires={b'ctx'})
846 851 def showp2node(context, mapping):
847 852 """String. The identification hash of the changeset's second
848 853 parent, as a 40 digit hexadecimal string. If the changeset has no second
849 854 parent, all digits are 0. (DEPRECATED)"""
850 855 ctx = context.resource(mapping, b'ctx')
851 856 return ctx.p2().hex()
852 857
853 858
854 859 @templatekeyword(b'parents', requires={b'repo', b'ctx'})
855 860 def showparents(context, mapping):
856 861 """List of strings. The parents of the changeset in "rev:node"
857 862 format. If the changeset has only one "natural" parent (the predecessor
858 863 revision) nothing is shown."""
859 864 repo = context.resource(mapping, b'repo')
860 865 ctx = context.resource(mapping, b'ctx')
861 866 pctxs = scmutil.meaningfulparents(repo, ctx)
862 867 prevs = [p.rev() for p in pctxs]
863 868 parents = [
864 869 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())]
865 870 for p in pctxs
866 871 ]
867 872 f = _showcompatlist(context, mapping, b'parent', parents)
868 873 return _hybrid(
869 874 f,
870 875 prevs,
871 876 lambda x: {b'ctx': repo[x]},
872 877 lambda x: scmutil.formatchangeid(repo[x]),
873 878 keytype=int,
874 879 )
875 880
876 881
877 882 @templatekeyword(b'phase', requires={b'ctx'})
878 883 def showphase(context, mapping):
879 884 """String. The changeset phase name."""
880 885 ctx = context.resource(mapping, b'ctx')
881 886 return ctx.phasestr()
882 887
883 888
884 889 @templatekeyword(b'phaseidx', requires={b'ctx'})
885 890 def showphaseidx(context, mapping):
886 891 """Integer. The changeset phase index. (ADVANCED)"""
887 892 ctx = context.resource(mapping, b'ctx')
888 893 return ctx.phase()
889 894
890 895
891 896 @templatekeyword(b'rev', requires={b'ctx'})
892 897 def showrev(context, mapping):
893 898 """Integer. The repository-local changeset revision number."""
894 899 ctx = context.resource(mapping, b'ctx')
895 900 return scmutil.intrev(ctx)
896 901
897 902
898 903 @templatekeyword(b'subrepos', requires={b'ctx'})
899 904 def showsubrepos(context, mapping):
900 905 """List of strings. Updated subrepositories in the changeset."""
901 906 ctx = context.resource(mapping, b'ctx')
902 907 substate = ctx.substate
903 908 if not substate:
904 909 return compatlist(context, mapping, b'subrepo', [])
905 910 psubstate = ctx.p1().substate or {}
906 911 subrepos = []
907 912 for sub in substate:
908 913 if sub not in psubstate or substate[sub] != psubstate[sub]:
909 914 subrepos.append(sub) # modified or newly added in ctx
910 915 for sub in psubstate:
911 916 if sub not in substate:
912 917 subrepos.append(sub) # removed in ctx
913 918 return compatlist(context, mapping, b'subrepo', sorted(subrepos))
914 919
915 920
916 921 # don't remove "showtags" definition, even though namespaces will put
917 922 # a helper function for "tags" keyword into "keywords" map automatically,
918 923 # because online help text is built without namespaces initialization
919 924 @templatekeyword(b'tags', requires={b'repo', b'ctx'})
920 925 def showtags(context, mapping):
921 926 """List of strings. Any tags associated with the changeset."""
922 927 return shownames(context, mapping, b'tags')
923 928
924 929
925 930 @templatekeyword(b'termwidth', requires={b'ui'})
926 931 def showtermwidth(context, mapping):
927 932 """Integer. The width of the current terminal."""
928 933 ui = context.resource(mapping, b'ui')
929 934 return ui.termwidth()
930 935
931 936
932 937 @templatekeyword(b'user', requires={b'ctx'})
933 938 def showuser(context, mapping):
934 939 """String. The unmodified author of the changeset."""
935 940 ctx = context.resource(mapping, b'ctx')
936 941 return ctx.user()
937 942
938 943
939 944 @templatekeyword(b'instabilities', requires={b'ctx'})
940 945 def showinstabilities(context, mapping):
941 946 """List of strings. Evolution instabilities affecting the changeset.
942 947 (EXPERIMENTAL)
943 948 """
944 949 ctx = context.resource(mapping, b'ctx')
945 950 return compatlist(
946 951 context,
947 952 mapping,
948 953 b'instability',
949 954 ctx.instabilities(),
950 955 plural=b'instabilities',
951 956 )
952 957
953 958
954 959 @templatekeyword(b'verbosity', requires={b'ui'})
955 960 def showverbosity(context, mapping):
956 961 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
957 962 or ''."""
958 963 ui = context.resource(mapping, b'ui')
959 964 # see logcmdutil.changesettemplater for priority of these flags
960 965 if ui.debugflag:
961 966 return b'debug'
962 967 elif ui.quiet:
963 968 return b'quiet'
964 969 elif ui.verbose:
965 970 return b'verbose'
966 971 return b''
967 972
968 973
969 974 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'})
970 975 def showwhyunstable(context, mapping):
971 976 """List of dicts explaining all instabilities of a changeset.
972 977 (EXPERIMENTAL)
973 978 """
974 979 repo = context.resource(mapping, b'repo')
975 980 ctx = context.resource(mapping, b'ctx')
976 981
977 982 def formatnode(ctx):
978 983 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
979 984
980 985 entries = obsutil.whyunstable(repo, ctx)
981 986
982 987 for entry in entries:
983 988 if entry.get(b'divergentnodes'):
984 989 dnodes = entry[b'divergentnodes']
985 990 dnhybrid = _hybrid(
986 991 None,
987 992 [dnode.hex() for dnode in dnodes],
988 993 lambda x: {b'ctx': repo[x]},
989 994 lambda x: formatnode(repo[x]),
990 995 )
991 996 entry[b'divergentnodes'] = dnhybrid
992 997
993 998 tmpl = (
994 999 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} '
995 1000 b'{reason} {node|short}'
996 1001 )
997 1002 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n')
998 1003
999 1004
1000 1005 def loadkeyword(ui, extname, registrarobj):
1001 1006 """Load template keyword from specified registrarobj"""
1002 1007 for name, func in pycompat.iteritems(registrarobj._table):
1003 1008 keywords[name] = func
1004 1009
1005 1010
1006 1011 # tell hggettext to extract docstrings from these functions:
1007 1012 i18nfunctions = keywords.values()
@@ -1,387 +1,390 b''
1 1 $ hg init a
2 2 $ hg clone a b
3 3 updating to branch default
4 4 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
5 5 $ cd a
6 6
7 7 with no paths:
8 8
9 9 $ hg paths
10 10 $ hg paths unknown
11 11 not found!
12 12 [1]
13 13 $ hg paths -Tjson
14 14 [
15 15 ]
16 16
17 17 with paths:
18 18
19 19 $ echo '[paths]' >> .hg/hgrc
20 20 $ echo 'dupe = ../b#tip' >> .hg/hgrc
21 21 $ echo 'expand = $SOMETHING/bar' >> .hg/hgrc
22 22 $ hg in dupe
23 23 comparing with $TESTTMP/b
24 24 no changes found
25 25 [1]
26 26 $ cd ..
27 27 $ hg -R a in dupe
28 28 comparing with $TESTTMP/b
29 29 no changes found
30 30 [1]
31 31 $ cd a
32 32 $ hg paths
33 33 dupe = $TESTTMP/b#tip
34 34 expand = $TESTTMP/a/$SOMETHING/bar
35 35 $ SOMETHING=foo hg paths
36 36 dupe = $TESTTMP/b#tip
37 37 expand = $TESTTMP/a/foo/bar
38 38 #if msys
39 39 $ SOMETHING=//foo hg paths
40 40 dupe = $TESTTMP/b#tip
41 41 expand = /foo/bar
42 42 #else
43 43 $ SOMETHING=/foo hg paths
44 44 dupe = $TESTTMP/b#tip
45 45 expand = /foo/bar
46 46 #endif
47 47 $ hg paths -q
48 48 dupe
49 49 expand
50 50 $ hg paths dupe
51 51 $TESTTMP/b#tip
52 52 $ hg paths -q dupe
53 53 $ hg paths unknown
54 54 not found!
55 55 [1]
56 56 $ hg paths -q unknown
57 57 [1]
58 58
59 59 formatter output with paths:
60 60
61 61 $ echo 'dupe:pushurl = https://example.com/dupe' >> .hg/hgrc
62 62 $ hg paths -Tjson | sed 's|\\\\|\\|g'
63 63 [
64 64 {
65 65 "name": "dupe",
66 66 "pushurl": "https://example.com/dupe",
67 67 "url": "$TESTTMP/b#tip"
68 68 },
69 69 {
70 70 "name": "expand",
71 71 "url": "$TESTTMP/a/$SOMETHING/bar"
72 72 }
73 73 ]
74 74 $ hg paths -Tjson dupe | sed 's|\\\\|\\|g'
75 75 [
76 76 {
77 77 "name": "dupe",
78 78 "pushurl": "https://example.com/dupe",
79 79 "url": "$TESTTMP/b#tip"
80 80 }
81 81 ]
82 82 $ hg paths -Tjson -q unknown
83 83 [
84 84 ]
85 85 [1]
86 86
87 87 log template:
88 88
89 89 (behaves as a {name: path-string} dict by default)
90 90
91 91 $ hg log -rnull -T '{peerurls}\n'
92 92 dupe=$TESTTMP/b#tip expand=$TESTTMP/a/$SOMETHING/bar
93 93 $ hg log -rnull -T '{join(peerurls, "\n")}\n'
94 94 dupe=$TESTTMP/b#tip
95 95 expand=$TESTTMP/a/$SOMETHING/bar
96 96 $ hg log -rnull -T '{peerurls % "{name}: {url}\n"}'
97 97 dupe: $TESTTMP/b#tip
98 98 expand: $TESTTMP/a/$SOMETHING/bar
99 99 $ hg log -rnull -T '{get(peerurls, "dupe")}\n'
100 100 $TESTTMP/b#tip
101 $ hg log -rnull -T '{peerurls % "{urls|json}\n"}'
102 [{"pushurl": "https://example.com/dupe", "url": "$TESTTMP/b#tip"}]
103 [{"url": "$TESTTMP/a/$SOMETHING/bar"}]
101 104
102 105 (sub options can be populated by map/dot operation)
103 106
104 107 $ hg log -rnull \
105 108 > -T '{get(peerurls, "dupe") % "url: {url}\npushurl: {pushurl}\n"}'
106 109 url: $TESTTMP/b#tip
107 110 pushurl: https://example.com/dupe
108 111 $ hg log -rnull -T '{peerurls.dupe.pushurl}\n'
109 112 https://example.com/dupe
110 113
111 114 (in JSON, it's a dict of urls)
112 115
113 116 $ hg log -rnull -T '{peerurls|json}\n' | sed 's|\\\\|/|g'
114 117 {"dupe": "$TESTTMP/b#tip", "expand": "$TESTTMP/a/$SOMETHING/bar"}
115 118
116 119 password should be masked in plain output, but not in machine-readable/template
117 120 output:
118 121
119 122 $ echo 'insecure = http://foo:insecure@example.com/' >> .hg/hgrc
120 123 $ hg paths insecure
121 124 http://foo:***@example.com/
122 125 $ hg paths -Tjson insecure
123 126 [
124 127 {
125 128 "name": "insecure",
126 129 "url": "http://foo:insecure@example.com/"
127 130 }
128 131 ]
129 132 $ hg log -rnull -T '{get(peerurls, "insecure")}\n'
130 133 http://foo:insecure@example.com/
131 134
132 135 zeroconf wraps ui.configitems(), which shouldn't crash at least:
133 136
134 137 $ hg paths --config extensions.zeroconf=
135 138 dupe = $TESTTMP/b#tip
136 139 dupe:pushurl = https://example.com/dupe
137 140 expand = $TESTTMP/a/$SOMETHING/bar
138 141 insecure = http://foo:***@example.com/
139 142
140 143 $ cd ..
141 144
142 145 sub-options for an undeclared path are ignored
143 146
144 147 $ hg init suboptions
145 148 $ cd suboptions
146 149
147 150 $ cat > .hg/hgrc << EOF
148 151 > [paths]
149 152 > path0 = https://example.com/path0
150 153 > path1:pushurl = https://example.com/path1
151 154 > EOF
152 155 $ hg paths
153 156 path0 = https://example.com/path0
154 157
155 158 unknown sub-options aren't displayed
156 159
157 160 $ cat > .hg/hgrc << EOF
158 161 > [paths]
159 162 > path0 = https://example.com/path0
160 163 > path0:foo = https://example.com/path1
161 164 > EOF
162 165
163 166 $ hg paths
164 167 path0 = https://example.com/path0
165 168
166 169 :pushurl must be a URL
167 170
168 171 $ cat > .hg/hgrc << EOF
169 172 > [paths]
170 173 > default = /path/to/nothing
171 174 > default:pushurl = /not/a/url
172 175 > EOF
173 176
174 177 $ hg paths
175 178 (paths.default:pushurl not a URL; ignoring)
176 179 default = /path/to/nothing
177 180
178 181 #fragment is not allowed in :pushurl
179 182
180 183 $ cat > .hg/hgrc << EOF
181 184 > [paths]
182 185 > default = https://example.com/repo
183 186 > invalid = https://example.com/repo
184 187 > invalid:pushurl = https://example.com/repo#branch
185 188 > EOF
186 189
187 190 $ hg paths
188 191 ("#fragment" in paths.invalid:pushurl not supported; ignoring)
189 192 default = https://example.com/repo
190 193 invalid = https://example.com/repo
191 194 invalid:pushurl = https://example.com/repo
192 195
193 196 $ cd ..
194 197
195 198 'file:' disables [paths] entries for clone destination
196 199
197 200 $ cat >> $HGRCPATH <<EOF
198 201 > [paths]
199 202 > gpath1 = http://hg.example.com
200 203 > EOF
201 204
202 205 $ hg clone a gpath1
203 206 abort: cannot create new http repository
204 207 [255]
205 208
206 209 $ hg clone a file:gpath1
207 210 updating to branch default
208 211 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 212 $ cd gpath1
210 213 $ hg -q id
211 214 000000000000
212 215
213 216 $ cd ..
214 217
215 218 Testing path referencing other paths
216 219 ====================================
217 220
218 221 basic setup
219 222 -----------
220 223
221 224 $ ls -1
222 225 a
223 226 b
224 227 gpath1
225 228 suboptions
226 229 $ hg init chained_path
227 230 $ cd chained_path
228 231 $ cat << EOF > .hg/hgrc
229 232 > [paths]
230 233 > default=../a
231 234 > other_default=path://default
232 235 > path_with_branch=../branchy#foo
233 236 > other_branch=path://path_with_branch
234 237 > other_branched=path://path_with_branch#default
235 238 > pushdest=../push-dest
236 239 > pushdest:pushrev=default
237 240 > pushdest2=path://pushdest
238 241 > pushdest-overwrite=path://pushdest
239 242 > pushdest-overwrite:pushrev=foo
240 243 > EOF
241 244
242 245 $ hg init ../branchy
243 246 $ hg init ../push-dest
244 247 $ hg debugbuilddag -R ../branchy '.:base+3<base@foo+5'
245 248 $ hg log -G -T '{branch}\n' -R ../branchy
246 249 o foo
247 250 |
248 251 o foo
249 252 |
250 253 o foo
251 254 |
252 255 o foo
253 256 |
254 257 o foo
255 258 |
256 259 | o default
257 260 | |
258 261 | o default
259 262 | |
260 263 | o default
261 264 |/
262 265 o default
263 266
264 267
265 268 $ hg paths
266 269 default = $TESTTMP/a
267 270 gpath1 = http://hg.example.com/
268 271 other_branch = $TESTTMP/branchy#foo
269 272 other_branched = $TESTTMP/branchy#default
270 273 other_default = $TESTTMP/a
271 274 path_with_branch = $TESTTMP/branchy#foo
272 275 pushdest = $TESTTMP/push-dest
273 276 pushdest:pushrev = default
274 277 pushdest-overwrite = $TESTTMP/push-dest
275 278 pushdest-overwrite:pushrev = foo
276 279 pushdest2 = $TESTTMP/push-dest
277 280 pushdest2:pushrev = default
278 281
279 282 test basic chaining
280 283 -------------------
281 284
282 285 $ hg path other_default
283 286 $TESTTMP/a
284 287 $ hg pull default
285 288 pulling from $TESTTMP/a
286 289 no changes found
287 290 $ hg pull other_default
288 291 pulling from $TESTTMP/a
289 292 no changes found
290 293
291 294 test inheritance of the #fragment part
292 295 --------------------------------------
293 296
294 297 $ hg pull path_with_branch
295 298 pulling from $TESTTMP/branchy
296 299 adding changesets
297 300 adding manifests
298 301 adding file changes
299 302 added 6 changesets with 0 changes to 0 files
300 303 new changesets 1ea73414a91b:bcebb50b77de
301 304 (run 'hg update' to get a working copy)
302 305 $ hg pull other_branch
303 306 pulling from $TESTTMP/branchy
304 307 no changes found
305 308 $ hg pull other_branched
306 309 pulling from $TESTTMP/branchy
307 310 searching for changes
308 311 adding changesets
309 312 adding manifests
310 313 adding file changes
311 314 added 3 changesets with 0 changes to 0 files (+1 heads)
312 315 new changesets 66f7d451a68b:2dc09a01254d
313 316 (run 'hg heads' to see heads)
314 317
315 318 test inheritance of the suboptions
316 319 ----------------------------------
317 320
318 321 $ hg push pushdest
319 322 pushing to $TESTTMP/push-dest
320 323 searching for changes
321 324 adding changesets
322 325 adding manifests
323 326 adding file changes
324 327 added 4 changesets with 0 changes to 0 files
325 328 $ hg push pushdest2
326 329 pushing to $TESTTMP/push-dest
327 330 searching for changes
328 331 no changes found
329 332 [1]
330 333 $ hg push pushdest-overwrite --new-branch
331 334 pushing to $TESTTMP/push-dest
332 335 searching for changes
333 336 adding changesets
334 337 adding manifests
335 338 adding file changes
336 339 added 5 changesets with 0 changes to 0 files (+1 heads)
337 340
338 341 Test chaining path:// definition
339 342 --------------------------------
340 343
341 344 This is currently unsupported, but feel free to implement the necessary
342 345 dependency detection.
343 346
344 347 $ cat << EOF >> .hg/hgrc
345 348 > chain_path=path://other_default
346 349 > EOF
347 350
348 351 $ hg id
349 352 000000000000
350 353 $ hg path
351 354 abort: cannot use `path://other_default`, "other_default" is also defined as a `path://`
352 355 [255]
353 356 $ hg pull chain_path
354 357 abort: cannot use `path://other_default`, "other_default" is also defined as a `path://`
355 358 [255]
356 359
357 360 Doing an actual circle should always be an issue
358 361
359 362 $ cat << EOF >> .hg/hgrc
360 363 > rock=path://cissors
361 364 > cissors=path://paper
362 365 > paper=://rock
363 366 > EOF
364 367
365 368 $ hg id
366 369 000000000000
367 370 $ hg path
368 371 abort: cannot use `path://other_default`, "other_default" is also defined as a `path://`
369 372 [255]
370 373 $ hg pull chain_path
371 374 abort: cannot use `path://other_default`, "other_default" is also defined as a `path://`
372 375 [255]
373 376
374 377 Test basic error cases
375 378 ----------------------
376 379
377 380 $ cat << EOF > .hg/hgrc
378 381 > [paths]
379 382 > error-missing=path://unknown
380 383 > EOF
381 384 $ hg path
382 385 abort: cannot use `path://unknown`, "unknown" is not a known path
383 386 [255]
384 387 $ hg pull error-missing
385 388 abort: cannot use `path://unknown`, "unknown" is not a known path
386 389 [255]
387 390
General Comments 0
You need to be logged in to leave comments. Login now