##// END OF EJS Templates
Merge with stable
Martin Geisler -
r10118:333193c0 merge default
parent child Browse files
Show More
@@ -1,564 +1,566
1 1 # keyword.py - $Keyword$ expansion for Mercurial
2 2 #
3 3 # Copyright 2007-2009 Christian Ebert <blacktrash@gmx.net>
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, incorporated herein by reference.
7 7 #
8 8 # $Id$
9 9 #
10 10 # Keyword expansion hack against the grain of a DSCM
11 11 #
12 12 # There are many good reasons why this is not needed in a distributed
13 13 # SCM, still it may be useful in very small projects based on single
14 14 # files (like LaTeX packages), that are mostly addressed to an
15 15 # audience not running a version control system.
16 16 #
17 17 # For in-depth discussion refer to
18 18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
19 19 #
20 20 # Keyword expansion is based on Mercurial's changeset template mappings.
21 21 #
22 22 # Binary files are not touched.
23 23 #
24 24 # Files to act upon/ignore are specified in the [keyword] section.
25 25 # Customized keyword template mappings in the [keywordmaps] section.
26 26 #
27 27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
28 28
29 29 '''expand keywords in tracked files
30 30
31 31 This extension expands RCS/CVS-like or self-customized $Keywords$ in
32 32 tracked text files selected by your configuration.
33 33
34 34 Keywords are only expanded in local repositories and not stored in the
35 35 change history. The mechanism can be regarded as a convenience for the
36 36 current user or for archive distribution.
37 37
38 38 Configuration is done in the [keyword] and [keywordmaps] sections of
39 39 hgrc files.
40 40
41 41 Example::
42 42
43 43 [keyword]
44 44 # expand keywords in every python file except those matching "x*"
45 45 **.py =
46 46 x* = ignore
47 47
48 48 NOTE: the more specific you are in your filename patterns the less you
49 49 lose speed in huge repositories.
50 50
51 51 For [keywordmaps] template mapping and expansion demonstration and
52 52 control run "hg kwdemo". See "hg help templates" for a list of
53 53 available templates and filters.
54 54
55 55 An additional date template filter {date|utcdate} is provided. It
56 56 returns a date like "2006/09/18 15:13:13".
57 57
58 58 The default template mappings (view with "hg kwdemo -d") can be
59 59 replaced with customized keywords and templates. Again, run "hg
60 60 kwdemo" to control the results of your config changes.
61 61
62 62 Before changing/disabling active keywords, run "hg kwshrink" to avoid
63 63 the risk of inadvertently storing expanded keywords in the change
64 64 history.
65 65
66 66 To force expansion after enabling it, or a configuration change, run
67 67 "hg kwexpand".
68 68
69 69 Also, when committing with the record extension or using mq's qrecord,
70 70 be aware that keywords cannot be updated. Again, run "hg kwexpand" on
71 71 the files in question to update keyword expansions after all changes
72 72 have been checked in.
73 73
74 74 Expansions spanning more than one line and incremental expansions,
75 75 like CVS' $Log$, are not supported. A keyword template map "Log =
76 76 {desc}" expands to the first line of the changeset description.
77 77 '''
78 78
79 79 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
80 80 from mercurial import patch, localrepo, templater, templatefilters, util, match
81 81 from mercurial.hgweb import webcommands
82 82 from mercurial.lock import release
83 83 from mercurial.node import nullid
84 84 from mercurial.i18n import _
85 85 import re, shutil, tempfile
86 86
87 87 commands.optionalrepo += ' kwdemo'
88 88
89 89 # hg commands that do not act on keywords
90 90 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
91 91 ' log outgoing push rename rollback tip verify'
92 92 ' convert email glog')
93 93
94 94 # hg commands that trigger expansion only when writing to working dir,
95 95 # not when reading filelog, and unexpand when reading from working dir
96 restricted = 'merge record resolve qfold qimport qnew qpush qrefresh qrecord'
96 restricted = ('merge record resolve qfold qimport qnew qpush qrefresh qrecord'
97 ' transplant')
97 98
98 99 # provide cvs-like UTC date filter
99 100 utcdate = lambda x: util.datestr(x, '%Y/%m/%d %H:%M:%S')
100 101
101 102 # make keyword tools accessible
102 103 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
103 104
104 105
105 106 class kwtemplater(object):
106 107 '''
107 108 Sets up keyword templates, corresponding keyword regex, and
108 109 provides keyword substitution functions.
109 110 '''
110 111 templates = {
111 112 'Revision': '{node|short}',
112 113 'Author': '{author|user}',
113 114 'Date': '{date|utcdate}',
114 115 'RCSfile': '{file|basename},v',
115 116 'RCSFile': '{file|basename},v', # kept for backwards compatibility
116 117 # with hg-keyword
117 118 'Source': '{root}/{file},v',
118 119 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
119 120 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
120 121 }
121 122
122 123 def __init__(self, ui, repo):
123 124 self.ui = ui
124 125 self.repo = repo
125 126 self.match = match.match(repo.root, '', [],
126 127 kwtools['inc'], kwtools['exc'])
127 128 self.restrict = kwtools['hgcmd'] in restricted.split()
128 129
129 130 kwmaps = self.ui.configitems('keywordmaps')
130 131 if kwmaps: # override default templates
131 132 self.templates = dict((k, templater.parsestring(v, False))
132 133 for k, v in kwmaps)
133 134 escaped = map(re.escape, self.templates.keys())
134 135 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
135 136 self.re_kw = re.compile(kwpat)
136 137
137 138 templatefilters.filters['utcdate'] = utcdate
138 139 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
139 140 False, None, '', False)
140 141
141 142 def substitute(self, data, path, ctx, subfunc):
142 143 '''Replaces keywords in data with expanded template.'''
143 144 def kwsub(mobj):
144 145 kw = mobj.group(1)
145 146 self.ct.use_template(self.templates[kw])
146 147 self.ui.pushbuffer()
147 148 self.ct.show(ctx, root=self.repo.root, file=path)
148 149 ekw = templatefilters.firstline(self.ui.popbuffer())
149 150 return '$%s: %s $' % (kw, ekw)
150 151 return subfunc(kwsub, data)
151 152
152 153 def expand(self, path, node, data):
153 154 '''Returns data with keywords expanded.'''
154 155 if not self.restrict and self.match(path) and not util.binary(data):
155 156 ctx = self.repo.filectx(path, fileid=node).changectx()
156 157 return self.substitute(data, path, ctx, self.re_kw.sub)
157 158 return data
158 159
159 160 def iskwfile(self, path, flagfunc):
160 161 '''Returns true if path matches [keyword] pattern
161 162 and is not a symbolic link.
162 163 Caveat: localrepository._link fails on Windows.'''
163 164 return self.match(path) and not 'l' in flagfunc(path)
164 165
165 166 def overwrite(self, node, expand, files):
166 167 '''Overwrites selected files expanding/shrinking keywords.'''
167 168 ctx = self.repo[node]
168 169 mf = ctx.manifest()
169 170 if node is not None: # commit
170 171 files = [f for f in ctx.files() if f in mf]
171 172 notify = self.ui.debug
172 173 else: # kwexpand/kwshrink
173 174 notify = self.ui.note
174 175 candidates = [f for f in files if self.iskwfile(f, ctx.flags)]
175 176 if candidates:
176 177 self.restrict = True # do not expand when reading
177 178 msg = (expand and _('overwriting %s expanding keywords\n')
178 179 or _('overwriting %s shrinking keywords\n'))
179 180 for f in candidates:
180 181 fp = self.repo.file(f)
181 182 data = fp.read(mf[f])
182 183 if util.binary(data):
183 184 continue
184 185 if expand:
185 186 if node is None:
186 187 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
187 188 data, found = self.substitute(data, f, ctx,
188 189 self.re_kw.subn)
189 190 else:
190 191 found = self.re_kw.search(data)
191 192 if found:
192 193 notify(msg % f)
193 194 self.repo.wwrite(f, data, mf.flags(f))
194 195 if node is None:
195 196 self.repo.dirstate.normal(f)
196 197 self.restrict = False
197 198
198 199 def shrinktext(self, text):
199 200 '''Unconditionally removes all keyword substitutions from text.'''
200 201 return self.re_kw.sub(r'$\1$', text)
201 202
202 203 def shrink(self, fname, text):
203 204 '''Returns text with all keyword substitutions removed.'''
204 205 if self.match(fname) and not util.binary(text):
205 206 return self.shrinktext(text)
206 207 return text
207 208
208 209 def shrinklines(self, fname, lines):
209 210 '''Returns lines with keyword substitutions removed.'''
210 211 if self.match(fname):
211 212 text = ''.join(lines)
212 213 if not util.binary(text):
213 214 return self.shrinktext(text).splitlines(True)
214 215 return lines
215 216
216 217 def wread(self, fname, data):
217 218 '''If in restricted mode returns data read from wdir with
218 219 keyword substitutions removed.'''
219 220 return self.restrict and self.shrink(fname, data) or data
220 221
221 222 class kwfilelog(filelog.filelog):
222 223 '''
223 224 Subclass of filelog to hook into its read, add, cmp methods.
224 225 Keywords are "stored" unexpanded, and processed on reading.
225 226 '''
226 227 def __init__(self, opener, kwt, path):
227 228 super(kwfilelog, self).__init__(opener, path)
228 229 self.kwt = kwt
229 230 self.path = path
230 231
231 232 def read(self, node):
232 233 '''Expands keywords when reading filelog.'''
233 234 data = super(kwfilelog, self).read(node)
234 235 return self.kwt.expand(self.path, node, data)
235 236
236 237 def add(self, text, meta, tr, link, p1=None, p2=None):
237 238 '''Removes keyword substitutions when adding to filelog.'''
238 239 text = self.kwt.shrink(self.path, text)
239 240 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
240 241
241 242 def cmp(self, node, text):
242 243 '''Removes keyword substitutions for comparison.'''
243 244 text = self.kwt.shrink(self.path, text)
244 245 if self.renamed(node):
245 246 t2 = super(kwfilelog, self).read(node)
246 247 return t2 != text
247 248 return revlog.revlog.cmp(self, node, text)
248 249
249 250 def _status(ui, repo, kwt, *pats, **opts):
250 251 '''Bails out if [keyword] configuration is not active.
251 252 Returns status of working directory.'''
252 253 if kwt:
253 254 unknown = (opts.get('unknown') or opts.get('all')
254 255 or opts.get('untracked'))
255 256 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
256 257 unknown=unknown)
257 258 if ui.configitems('keyword'):
258 259 raise util.Abort(_('[keyword] patterns cannot match'))
259 260 raise util.Abort(_('no [keyword] patterns configured'))
260 261
261 262 def _kwfwrite(ui, repo, expand, *pats, **opts):
262 263 '''Selects files and passes them to kwtemplater.overwrite.'''
263 264 if repo.dirstate.parents()[1] != nullid:
264 265 raise util.Abort(_('outstanding uncommitted merge'))
265 266 kwt = kwtools['templater']
266 267 status = _status(ui, repo, kwt, *pats, **opts)
267 268 modified, added, removed, deleted = status[:4]
268 269 if modified or added or removed or deleted:
269 270 raise util.Abort(_('outstanding uncommitted changes'))
270 271 wlock = lock = None
271 272 try:
272 273 wlock = repo.wlock()
273 274 lock = repo.lock()
274 275 kwt.overwrite(None, expand, status[6])
275 276 finally:
276 277 release(lock, wlock)
277 278
278 279 def demo(ui, repo, *args, **opts):
279 280 '''print [keywordmaps] configuration and an expansion example
280 281
281 282 Show current, custom, or default keyword template maps and their
282 283 expansions.
283 284
284 285 Extend the current configuration by specifying maps as arguments
285 286 and using -f/--rcfile to source an external hgrc file.
286 287
287 288 Use -d/--default to disable current configuration.
288 289
289 290 See "hg help templates" for information on templates and filters.
290 291 '''
291 292 def demoitems(section, items):
292 293 ui.write('[%s]\n' % section)
293 294 for k, v in sorted(items):
294 295 ui.write('%s = %s\n' % (k, v))
295 296
296 297 msg = 'hg keyword config and expansion example'
297 298 fn = 'demo.txt'
298 299 branchname = 'demobranch'
299 300 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
300 301 ui.note(_('creating temporary repository at %s\n') % tmpdir)
301 302 repo = localrepo.localrepository(ui, tmpdir, True)
302 303 ui.setconfig('keyword', fn, '')
303 304
304 305 uikwmaps = ui.configitems('keywordmaps')
305 306 if args or opts.get('rcfile'):
306 307 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
307 308 if uikwmaps:
308 309 ui.status(_('\textending current template maps\n'))
309 310 if opts.get('default') or not uikwmaps:
310 311 ui.status(_('\toverriding default template maps\n'))
311 312 if opts.get('rcfile'):
312 313 ui.readconfig(opts.get('rcfile'))
313 314 if args:
314 315 # simulate hgrc parsing
315 316 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
316 317 fp = repo.opener('hgrc', 'w')
317 318 fp.writelines(rcmaps)
318 319 fp.close()
319 320 ui.readconfig(repo.join('hgrc'))
320 321 kwmaps = dict(ui.configitems('keywordmaps'))
321 322 elif opts.get('default'):
322 323 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
323 324 kwmaps = kwtemplater.templates
324 325 if uikwmaps:
325 326 ui.status(_('\tdisabling current template maps\n'))
326 327 for k, v in kwmaps.iteritems():
327 328 ui.setconfig('keywordmaps', k, v)
328 329 else:
329 330 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
330 331 kwmaps = dict(uikwmaps) or kwtemplater.templates
331 332
332 333 uisetup(ui)
333 334 reposetup(ui, repo)
334 335 for k, v in ui.configitems('extensions'):
335 336 if k.endswith('keyword'):
336 337 extension = '%s = %s' % (k, v)
337 338 break
338 339 ui.write('[extensions]\n%s\n' % extension)
339 340 demoitems('keyword', ui.configitems('keyword'))
340 341 demoitems('keywordmaps', kwmaps.iteritems())
341 342 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
342 343 repo.wopener(fn, 'w').write(keywords)
343 344 repo.add([fn])
344 345 path = repo.wjoin(fn)
345 346 ui.note(_('\nkeywords written to %s:\n') % path)
346 347 ui.note(keywords)
347 348 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
348 349 # silence branch command if not verbose
349 350 quiet = ui.quiet
350 351 ui.quiet = not ui.verbose
351 352 commands.branch(ui, repo, branchname)
352 353 ui.quiet = quiet
353 354 for name, cmd in ui.configitems('hooks'):
354 355 if name.split('.', 1)[0].find('commit') > -1:
355 356 repo.ui.setconfig('hooks', name, '')
356 357 ui.note(_('unhooked all commit hooks\n'))
357 358 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
358 359 repo.commit(text=msg)
359 360 ui.status(_('\n\tkeywords expanded\n'))
360 361 ui.write(repo.wread(fn))
361 362 ui.debug('\nremoving temporary repository %s\n' % tmpdir)
362 363 shutil.rmtree(tmpdir, ignore_errors=True)
363 364
364 365 def expand(ui, repo, *pats, **opts):
365 366 '''expand keywords in the working directory
366 367
367 368 Run after (re)enabling keyword expansion.
368 369
369 370 kwexpand refuses to run if given files contain local changes.
370 371 '''
371 372 # 3rd argument sets expansion to True
372 373 _kwfwrite(ui, repo, True, *pats, **opts)
373 374
374 375 def files(ui, repo, *pats, **opts):
375 376 '''show files configured for keyword expansion
376 377
377 378 List which files in the working directory are matched by the
378 379 [keyword] configuration patterns.
379 380
380 381 Useful to prevent inadvertent keyword expansion and to speed up
381 382 execution by including only files that are actual candidates for
382 383 expansion.
383 384
384 385 See "hg help keyword" on how to construct patterns both for
385 386 inclusion and exclusion of files.
386 387
387 388 With -A/--all and -v/--verbose the codes used to show the status
388 389 of files are::
389 390
390 391 K = keyword expansion candidate
391 392 k = keyword expansion candidate (not tracked)
392 393 I = ignored
393 394 i = ignored (not tracked)
394 395 '''
395 396 kwt = kwtools['templater']
396 397 status = _status(ui, repo, kwt, *pats, **opts)
397 398 cwd = pats and repo.getcwd() or ''
398 399 modified, added, removed, deleted, unknown, ignored, clean = status
399 400 files = []
400 401 if not (opts.get('unknown') or opts.get('untracked')) or opts.get('all'):
401 402 files = sorted(modified + added + clean)
402 403 wctx = repo[None]
403 404 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
404 405 kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
405 406 if not opts.get('ignore') or opts.get('all'):
406 407 showfiles = kwfiles, kwunknown
407 408 else:
408 409 showfiles = [], []
409 410 if opts.get('all') or opts.get('ignore'):
410 411 showfiles += ([f for f in files if f not in kwfiles],
411 412 [f for f in unknown if f not in kwunknown])
412 413 for char, filenames in zip('KkIi', showfiles):
413 414 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
414 415 for f in filenames:
415 416 ui.write(fmt % repo.pathto(f, cwd))
416 417
417 418 def shrink(ui, repo, *pats, **opts):
418 419 '''revert expanded keywords in the working directory
419 420
420 421 Run before changing/disabling active keywords or if you experience
421 422 problems with "hg import" or "hg merge".
422 423
423 424 kwshrink refuses to run if given files contain local changes.
424 425 '''
425 426 # 3rd argument sets expansion to False
426 427 _kwfwrite(ui, repo, False, *pats, **opts)
427 428
428 429
429 430 def uisetup(ui):
430 431 '''Collects [keyword] config in kwtools.
431 432 Monkeypatches dispatch._parse if needed.'''
432 433
433 434 for pat, opt in ui.configitems('keyword'):
434 435 if opt != 'ignore':
435 436 kwtools['inc'].append(pat)
436 437 else:
437 438 kwtools['exc'].append(pat)
438 439
439 440 if kwtools['inc']:
440 441 def kwdispatch_parse(orig, ui, args):
441 442 '''Monkeypatch dispatch._parse to obtain running hg command.'''
442 443 cmd, func, args, options, cmdoptions = orig(ui, args)
443 444 kwtools['hgcmd'] = cmd
444 445 return cmd, func, args, options, cmdoptions
445 446
446 447 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
447 448
448 449 def reposetup(ui, repo):
449 450 '''Sets up repo as kwrepo for keyword substitution.
450 451 Overrides file method to return kwfilelog instead of filelog
451 452 if file matches user configuration.
452 453 Wraps commit to overwrite configured files with updated
453 454 keyword substitutions.
454 455 Monkeypatches patch and webcommands.'''
455 456
456 457 try:
457 458 if (not repo.local() or not kwtools['inc']
458 459 or kwtools['hgcmd'] in nokwcommands.split()
459 460 or '.hg' in util.splitpath(repo.root)
460 461 or repo._url.startswith('bundle:')):
461 462 return
462 463 except AttributeError:
463 464 pass
464 465
465 466 kwtools['templater'] = kwt = kwtemplater(ui, repo)
466 467
467 468 class kwrepo(repo.__class__):
468 469 def file(self, f):
469 470 if f[0] == '/':
470 471 f = f[1:]
471 472 return kwfilelog(self.sopener, kwt, f)
472 473
473 474 def wread(self, filename):
474 475 data = super(kwrepo, self).wread(filename)
475 476 return kwt.wread(filename, data)
476 477
477 478 def commit(self, *args, **opts):
478 479 # use custom commitctx for user commands
479 480 # other extensions can still wrap repo.commitctx directly
480 481 self.commitctx = self.kwcommitctx
481 482 try:
482 483 return super(kwrepo, self).commit(*args, **opts)
483 484 finally:
484 485 del self.commitctx
485 486
486 487 def kwcommitctx(self, ctx, error=False):
487 488 wlock = lock = None
488 489 try:
489 490 wlock = self.wlock()
490 491 lock = self.lock()
491 492 # store and postpone commit hooks
492 493 commithooks = {}
493 494 for name, cmd in ui.configitems('hooks'):
494 495 if name.split('.', 1)[0] == 'commit':
495 496 commithooks[name] = cmd
496 497 ui.setconfig('hooks', name, None)
497 498 if commithooks:
498 499 # store parents for commit hooks
499 500 p1, p2 = ctx.p1(), ctx.p2()
500 501 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
501 502
502 503 n = super(kwrepo, self).commitctx(ctx, error)
503 504
504 505 kwt.overwrite(n, True, None)
505 506 if commithooks:
506 507 for name, cmd in commithooks.iteritems():
507 508 ui.setconfig('hooks', name, cmd)
508 509 self.hook('commit', node=n, parent1=xp1, parent2=xp2)
509 510 return n
510 511 finally:
511 512 release(lock, wlock)
512 513
513 514 # monkeypatches
514 515 def kwpatchfile_init(orig, self, ui, fname, opener,
515 516 missing=False, eol=None):
516 517 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
517 518 rejects or conflicts due to expanded keywords in working dir.'''
518 519 orig(self, ui, fname, opener, missing, eol)
519 520 # shrink keywords read from working dir
520 521 self.lines = kwt.shrinklines(self.fname, self.lines)
521 522
522 523 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
523 524 opts=None):
524 525 '''Monkeypatch patch.diff to avoid expansion except when
525 526 comparing against working dir.'''
526 527 if node2 is not None:
527 528 kwt.match = util.never
528 529 elif node1 is not None and node1 != repo['.'].node():
529 530 kwt.restrict = True
530 531 return orig(repo, node1, node2, match, changes, opts)
531 532
532 533 def kwweb_skip(orig, web, req, tmpl):
533 534 '''Wraps webcommands.x turning off keyword expansion.'''
534 535 kwt.match = util.never
535 536 return orig(web, req, tmpl)
536 537
537 538 repo.__class__ = kwrepo
538 539
539 540 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
541 if not kwt.restrict:
540 542 extensions.wrapfunction(patch, 'diff', kw_diff)
541 543 for c in 'annotate changeset rev filediff diff'.split():
542 544 extensions.wrapfunction(webcommands, c, kwweb_skip)
543 545
544 546 cmdtable = {
545 547 'kwdemo':
546 548 (demo,
547 549 [('d', 'default', None, _('show default keyword template maps')),
548 550 ('f', 'rcfile', '', _('read maps from rcfile'))],
549 551 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
550 552 'kwexpand': (expand, commands.walkopts,
551 553 _('hg kwexpand [OPTION]... [FILE]...')),
552 554 'kwfiles':
553 555 (files,
554 556 [('A', 'all', None, _('show keyword status flags of all files')),
555 557 ('i', 'ignore', None, _('show files excluded from expansion')),
556 558 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
557 559 ('a', 'all', None,
558 560 _('show keyword status flags of all files (DEPRECATED)')),
559 561 ('u', 'untracked', None, _('only show untracked files (DEPRECATED)')),
560 562 ] + commands.walkopts,
561 563 _('hg kwfiles [OPTION]... [FILE]...')),
562 564 'kwshrink': (shrink, commands.walkopts,
563 565 _('hg kwshrink [OPTION]... [FILE]...')),
564 566 }
@@ -1,354 +1,372
1 1 #!/bin/sh
2 2
3 3 cat <<EOF >> $HGRCPATH
4 4 [extensions]
5 5 hgext.keyword =
6 6 hgext.mq =
7 7 hgext.notify =
8 hgext.transplant =
8 9 EOF
9 10
10 11 # demo before [keyword] files are set up
11 12 # would succeed without uisetup otherwise
12 13 echo % hg kwdemo
13 14 hg --quiet kwdemo \
14 15 | sed -e 's![^ ][^ ]*demo.txt,v!/TMP/demo.txt,v!' \
15 16 -e 's/,v [a-z0-9][a-z0-9]* /,v xxxxxxxxxxxx /' \
16 17 -e '/[$]Revision/ s/: [a-z0-9][a-z0-9]* /: xxxxxxxxxxxx /' \
17 18 -e 's! 20[0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]! 2000/00/00 00:00:00!'
18 19
19 20 hg --quiet kwdemo "Branch = {branches}"
20 21
21 22 cat <<EOF >> $HGRCPATH
22 23 [keyword]
23 24 * =
24 25 b = ignore
25 26 [hooks]
26 27 commit=
27 28 commit.test=cp a hooktest
28 29 EOF
29 30
30 31 hg init Test-bndl
31 32 cd Test-bndl
32 33
33 34 echo % kwshrink should exit silently in empty/invalid repo
34 35 hg kwshrink
35 36
36 37 # Symlinks cannot be created on Windows. The bundle was made with:
37 38 #
38 39 # hg init t
39 40 # cd t
40 41 # echo a > a
41 42 # ln -s a sym
42 43 # hg add sym
43 44 # hg ci -m addsym -u mercurial
44 45 # hg bundle --base null ../test-keyword.hg
45 46 #
46 47 hg pull -u "$TESTDIR/test-keyword.hg" \
47 48 | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/'
48 49
49 50 echo 'expand $Id$' > a
50 51 echo 'do not process $Id:' >> a
51 52 echo 'xxx $' >> a
52 53 echo 'ignore $Id$' > b
53 54 echo % cat
54 55 cat a b
55 56
56 57 echo % no kwfiles
57 58 hg kwfiles
58 59 echo % untracked candidates
59 60 hg -v kwfiles --unknown
60 61
61 62 echo % addremove
62 63 hg addremove
63 64 echo % status
64 65 hg status
65 66
66 67 echo % default keyword expansion including commit hook
67 68 echo % interrupted commit should not change state or run commit hook
68 69 hg --debug commit
69 70 echo % status
70 71 hg status
71 72
72 73 echo % commit
73 74 hg --debug commit -mabsym -u 'User Name <user@example.com>'
74 75 echo % status
75 76 hg status
76 77 echo % identify
77 78 hg debugrebuildstate
78 79 hg --quiet identify
79 80 echo % cat
80 81 cat a b
81 82 echo % hg cat
82 83 hg cat sym a b
83 84
84 85 echo
85 86 echo % diff a hooktest
86 87 diff a hooktest
87 88
88 89 echo % removing commit hook from config
89 90 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nohook
90 91 mv $HGRCPATH.nohook $HGRCPATH
91 92 rm hooktest
92 93
93 94 echo % bundle
94 95 hg bundle --base null ../kw.hg
95 96
96 97 cd ..
97 98 hg init Test
98 99 cd Test
99 100
100 101 echo % notify on pull to check whether keywords stay as is in email
101 102 echo % ie. if patch.diff wrapper acts as it should
102 103
103 104 cat <<EOF >> $HGRCPATH
104 105 [hooks]
105 106 incoming.notify = python:hgext.notify.hook
106 107 [notify]
107 108 sources = pull
108 109 diffstat = False
109 110 [reposubs]
110 111 * = Test
111 112 EOF
112 113
113 114 echo % pull from bundle
114 115 hg pull -u ../kw.hg 2>&1 | sed -e '/^Content-Type:/,/^diffs (/ d'
115 116
116 117 echo % remove notify config
117 118 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nonotify
118 119 mv $HGRCPATH.nonotify $HGRCPATH
119 120
120 121 echo % touch
121 122 touch a b
122 123 echo % status
123 124 hg status
124 125
125 126 rm sym a b
126 127 echo % update
127 128 hg update -C
128 129 echo % cat
129 130 cat a b
130 131
131 132 echo % check whether expansion is filewise
132 133 echo '$Id$' > c
133 134 echo 'tests for different changenodes' >> c
134 135 echo % commit c
135 136 hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
136 137 echo % force expansion
137 138 hg -v kwexpand
138 139 echo % compare changenodes in a c
139 140 cat a c
140 141
141 142 echo % qinit -c
142 143 hg qinit -c
143 144 echo % qimport
144 145 hg qimport -r tip -n mqtest.diff
145 146 echo % qcommit
146 147 hg qcommit -mqtest
147 148 echo % keywords should not be expanded in patch
148 149 cat .hg/patches/mqtest.diff
149 150 echo % qpop
150 151 hg qpop
151 152 echo % qgoto - should imply qpush
152 153 hg qgoto mqtest.diff
153 154 echo % cat
154 155 cat c
155 156 echo % qpop and move on
156 157 hg qpop
157 158
158 159 echo % copy
159 160 hg cp a c
160 161
161 162 echo % kwfiles added
162 163 hg kwfiles
163 164
164 165 echo % commit
165 166 hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
166 167 echo % cat a c
167 168 cat a c
168 169 echo % touch copied c
169 170 touch c
170 171 echo % status
171 172 hg status
172 173
173 174 echo % kwfiles
174 175 hg kwfiles
175 176 echo % ignored files
176 177 hg -v kwfiles --ignore
177 178 echo % all files
178 179 hg kwfiles --all
179 180
180 181 echo % diff --rev
181 182 hg diff --rev 1 | grep -v 'b/c'
182 183
183 184 echo % rollback
184 185 hg rollback
185 186 echo % status
186 187 hg status
187 188 echo % update -C
188 189 hg update --clean
189 190
190 191 echo % custom keyword expansion
191 192 echo % try with kwdemo
192 193 hg --quiet kwdemo "Xinfo = {author}: {desc}"
193 194
194 195 cat <<EOF >>$HGRCPATH
195 196 [keywordmaps]
196 197 Id = {file} {node|short} {date|rfc822date} {author|user}
197 198 Xinfo = {author}: {desc}
198 199 EOF
199 200
200 201 echo % cat
201 202 cat a b
202 203 echo % hg cat
203 204 hg cat sym a b
204 205
205 206 echo
206 207 echo '$Xinfo$' >> a
207 208 cat <<EOF >> log
208 209 firstline
209 210 secondline
210 211 EOF
211 212
212 213 echo % interrupted commit should not change state
213 214 hg commit
214 215 echo % status
215 216 hg status
216 217
217 218 echo % commit
218 219 hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
219 220 rm log
220 221 echo % status
221 222 hg status
222 223 echo % verify
223 224 hg verify
224 225
225 226 echo % cat
226 227 cat a b
227 228 echo % hg cat
228 229 hg cat sym a b
229 230 echo
230 231 echo % annotate
231 232 hg annotate a
232 233
233 234 echo % remove
234 235 hg debugrebuildstate
235 236 hg remove a
236 237 hg --debug commit -m rma
237 238 echo % status
238 239 hg status
239 240 echo % rollback
240 241 hg rollback
241 242 echo % status
242 243 hg status
243 244 echo % revert a
244 245 hg revert --no-backup --rev tip a
245 246 echo % cat a
246 247 cat a
247 248
248 249 echo % clone to test incoming
249 250 cd ..
250 251 hg clone -r1 Test Test-a
251 252 cd Test-a
252 253 cat <<EOF >> .hg/hgrc
253 254 [paths]
254 255 default = ../Test
255 256 EOF
256 257 echo % incoming
257 258 # remove path to temp dir
258 259 hg incoming | sed -e 's/^\(comparing with \).*\(test-keyword.*\)/\1\2/'
259 260
260 261 sed -e 's/Id.*/& rejecttest/' a > a.new
261 262 mv a.new a
262 263 echo % commit rejecttest
263 264 hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
264 265 echo % export
265 266 hg export -o ../rejecttest.diff tip
266 267
267 268 cd ../Test
268 269 echo % import
269 270 hg import ../rejecttest.diff
270 271 echo % cat
271 272 cat a b
272 273 echo
273 274 echo % rollback
274 275 hg rollback
275 276 echo % clean update
276 277 hg update --clean
277 278
278 279 echo % kwexpand/kwshrink on selected files
279 280 mkdir x
280 281 echo % copy a x/a
281 282 hg copy a x/a
282 283 echo % kwexpand a
283 284 hg --verbose kwexpand a
284 285 echo % kwexpand x/a should abort
285 286 hg --verbose kwexpand x/a
286 287 cd x
287 288 hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
288 289 echo % cat a
289 290 cat a
290 291 echo % kwshrink a inside directory x
291 292 hg --verbose kwshrink a
292 293 echo % cat a
293 294 cat a
294 295 cd ..
295 296
296 297 echo % kwexpand nonexistent
297 298 hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/'
298 299
299 300 echo % hg serve
300 301 hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
301 302 cat hg.pid >> $DAEMON_PIDS
302 303 echo % expansion
303 304 echo % hgweb file
304 305 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/a/?style=raw')
305 306 echo % no expansion
306 307 echo % hgweb annotate
307 308 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/annotate/tip/a/?style=raw')
308 309 echo % hgweb changeset
309 310 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/tip/?style=raw')
310 311 echo % hgweb filediff
311 312 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/bb948857c743/a?style=raw')
312 313 echo % errors encountered
313 314 cat errors.log
314 315
315 316 echo % merge/resolve
316 317 echo '$Id$' > m
317 318 hg add m
318 319 hg commit -m 4kw
319 320 echo foo >> m
320 321 hg commit -m 5foo
321 322 echo % simplemerge
322 323 hg update 4
323 324 echo foo >> m
324 325 hg commit -m 6foo
325 326 hg merge
326 327 hg commit -m simplemerge
327 328 cat m
328 329 echo % conflict
329 330 hg update 4
330 331 echo bar >> m
331 332 hg commit -m 8bar
332 333 hg merge
333 334 echo % keyword stays outside conflict zone
334 335 cat m
335 336 echo % resolve to local
336 337 HGMERGE=internal:local hg resolve -a
337 338 hg commit -m localresolve
338 339 cat m
339 340
341 echo % test restricted mode with transplant -b
342 hg update 6
343 hg branch foo
344 mv a a.bak
345 echo foobranch > a
346 cat a.bak >> a
347 rm a.bak
348 hg commit -m 9foobranch
349 hg update default
350 hg -y transplant -b foo tip
351 echo % no expansion in changeset
352 hg tip -p
353 echo % expansion in file
354 head -n 2 a
355 hg -q rollback
356 hg -q update -C
357
340 358 echo % switch off expansion
341 359 echo % kwshrink with unknown file u
342 360 cp a u
343 361 hg --verbose kwshrink
344 362 echo % cat
345 363 cat a b
346 364 echo % hg cat
347 365 hg cat sym a b
348 366 echo
349 367 rm $HGRCPATH
350 368 echo % cat
351 369 cat a b
352 370 echo % hg cat
353 371 hg cat sym a b
354 372 echo
@@ -1,453 +1,480
1 1 % hg kwdemo
2 2 [extensions]
3 3 hgext.keyword =
4 4 [keyword]
5 5 demo.txt =
6 6 [keywordmaps]
7 7 Author = {author|user}
8 8 Date = {date|utcdate}
9 9 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
10 10 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
11 11 RCSFile = {file|basename},v
12 12 RCSfile = {file|basename},v
13 13 Revision = {node|short}
14 14 Source = {root}/{file},v
15 15 $Author: test $
16 16 $Date: 2000/00/00 00:00:00 $
17 17 $Header: /TMP/demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
18 18 $Id: demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
19 19 $RCSFile: demo.txt,v $
20 20 $RCSfile: demo.txt,v $
21 21 $Revision: xxxxxxxxxxxx $
22 22 $Source: /TMP/demo.txt,v $
23 23 [extensions]
24 24 hgext.keyword =
25 25 [keyword]
26 26 demo.txt =
27 27 [keywordmaps]
28 28 Branch = {branches}
29 29 $Branch: demobranch $
30 30 % kwshrink should exit silently in empty/invalid repo
31 31 pulling from test-keyword.hg
32 32 requesting all changes
33 33 adding changesets
34 34 adding manifests
35 35 adding file changes
36 36 added 1 changesets with 1 changes to 1 files
37 37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 38 % cat
39 39 expand $Id$
40 40 do not process $Id:
41 41 xxx $
42 42 ignore $Id$
43 43 % no kwfiles
44 44 % untracked candidates
45 45 k a
46 46 % addremove
47 47 adding a
48 48 adding b
49 49 % status
50 50 A a
51 51 A b
52 52 % default keyword expansion including commit hook
53 53 % interrupted commit should not change state or run commit hook
54 54 abort: empty commit message
55 55 % status
56 56 A a
57 57 A b
58 58 % commit
59 59 a
60 60 b
61 61 overwriting a expanding keywords
62 62 running hook commit.test: cp a hooktest
63 63 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
64 64 % status
65 65 ? hooktest
66 66 % identify
67 67 ef63ca68695b
68 68 % cat
69 69 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
70 70 do not process $Id:
71 71 xxx $
72 72 ignore $Id$
73 73 % hg cat
74 74 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
75 75 do not process $Id:
76 76 xxx $
77 77 ignore $Id$
78 78 a
79 79 % diff a hooktest
80 80 % removing commit hook from config
81 81 % bundle
82 82 2 changesets found
83 83 % notify on pull to check whether keywords stay as is in email
84 84 % ie. if patch.diff wrapper acts as it should
85 85 % pull from bundle
86 86 pulling from ../kw.hg
87 87 requesting all changes
88 88 adding changesets
89 89 adding manifests
90 90 adding file changes
91 91 added 2 changesets with 3 changes to 3 files
92 92
93 93 diff -r 000000000000 -r a2392c293916 sym
94 94 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95 95 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
96 96 @@ -0,0 +1,1 @@
97 97 +a
98 98 \ No newline at end of file
99 99
100 100 diff -r a2392c293916 -r ef63ca68695b a
101 101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102 102 +++ b/a Thu Jan 01 00:00:00 1970 +0000
103 103 @@ -0,0 +1,3 @@
104 104 +expand $Id$
105 105 +do not process $Id:
106 106 +xxx $
107 107 diff -r a2392c293916 -r ef63ca68695b b
108 108 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
109 109 +++ b/b Thu Jan 01 00:00:00 1970 +0000
110 110 @@ -0,0 +1,1 @@
111 111 +ignore $Id$
112 112 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 113 % remove notify config
114 114 % touch
115 115 % status
116 116 % update
117 117 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 118 % cat
119 119 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
120 120 do not process $Id:
121 121 xxx $
122 122 ignore $Id$
123 123 % check whether expansion is filewise
124 124 % commit c
125 125 adding c
126 126 % force expansion
127 127 overwriting a expanding keywords
128 128 overwriting c expanding keywords
129 129 % compare changenodes in a c
130 130 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
131 131 do not process $Id:
132 132 xxx $
133 133 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
134 134 tests for different changenodes
135 135 % qinit -c
136 136 % qimport
137 137 % qcommit
138 138 % keywords should not be expanded in patch
139 139 # HG changeset patch
140 140 # User User Name <user@example.com>
141 141 # Date 1 0
142 142 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
143 143 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
144 144 cndiff
145 145
146 146 diff -r ef63ca68695b -r 40a904bbbe4c c
147 147 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
148 148 +++ b/c Thu Jan 01 00:00:01 1970 +0000
149 149 @@ -0,0 +1,2 @@
150 150 +$Id$
151 151 +tests for different changenodes
152 152 % qpop
153 153 popping mqtest.diff
154 154 patch queue now empty
155 155 % qgoto - should imply qpush
156 156 applying mqtest.diff
157 157 now at: mqtest.diff
158 158 % cat
159 159 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
160 160 tests for different changenodes
161 161 % qpop and move on
162 162 popping mqtest.diff
163 163 patch queue now empty
164 164 % copy
165 165 % kwfiles added
166 166 a
167 167 c
168 168 % commit
169 169 c
170 170 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
171 171 overwriting c expanding keywords
172 172 committed changeset 2:e22d299ac0c2bd8897b3df5114374b9e4d4ca62f
173 173 % cat a c
174 174 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
175 175 do not process $Id:
176 176 xxx $
177 177 expand $Id: c,v e22d299ac0c2 1970/01/01 00:00:01 user $
178 178 do not process $Id:
179 179 xxx $
180 180 % touch copied c
181 181 % status
182 182 % kwfiles
183 183 a
184 184 c
185 185 % ignored files
186 186 I b
187 187 I sym
188 188 % all files
189 189 K a
190 190 K c
191 191 I b
192 192 I sym
193 193 % diff --rev
194 194 diff -r ef63ca68695b c
195 195 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
196 196 @@ -0,0 +1,3 @@
197 197 +expand $Id$
198 198 +do not process $Id:
199 199 +xxx $
200 200 % rollback
201 201 rolling back last transaction
202 202 % status
203 203 A c
204 204 % update -C
205 205 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 206 % custom keyword expansion
207 207 % try with kwdemo
208 208 [extensions]
209 209 hgext.keyword =
210 210 [keyword]
211 211 * =
212 212 b = ignore
213 213 demo.txt =
214 214 [keywordmaps]
215 215 Xinfo = {author}: {desc}
216 216 $Xinfo: test: hg keyword config and expansion example $
217 217 % cat
218 218 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
219 219 do not process $Id:
220 220 xxx $
221 221 ignore $Id$
222 222 % hg cat
223 223 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
224 224 do not process $Id:
225 225 xxx $
226 226 ignore $Id$
227 227 a
228 228 % interrupted commit should not change state
229 229 abort: empty commit message
230 230 % status
231 231 M a
232 232 ? c
233 233 ? log
234 234 % commit
235 235 a
236 236 overwriting a expanding keywords
237 237 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
238 238 % status
239 239 ? c
240 240 % verify
241 241 checking changesets
242 242 checking manifests
243 243 crosschecking files in changesets and manifests
244 244 checking files
245 245 3 files, 3 changesets, 4 total revisions
246 246 % cat
247 247 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
248 248 do not process $Id:
249 249 xxx $
250 250 $Xinfo: User Name <user@example.com>: firstline $
251 251 ignore $Id$
252 252 % hg cat
253 253 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
254 254 do not process $Id:
255 255 xxx $
256 256 $Xinfo: User Name <user@example.com>: firstline $
257 257 ignore $Id$
258 258 a
259 259 % annotate
260 260 1: expand $Id$
261 261 1: do not process $Id:
262 262 1: xxx $
263 263 2: $Xinfo$
264 264 % remove
265 265 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
266 266 % status
267 267 ? c
268 268 % rollback
269 269 rolling back last transaction
270 270 % status
271 271 R a
272 272 ? c
273 273 % revert a
274 274 % cat a
275 275 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
276 276 do not process $Id:
277 277 xxx $
278 278 $Xinfo: User Name <user@example.com>: firstline $
279 279 % clone to test incoming
280 280 requesting all changes
281 281 adding changesets
282 282 adding manifests
283 283 adding file changes
284 284 added 2 changesets with 3 changes to 3 files
285 285 updating to branch default
286 286 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 287 % incoming
288 288 comparing with test-keyword/Test
289 289 searching for changes
290 290 changeset: 2:bb948857c743
291 291 tag: tip
292 292 user: User Name <user@example.com>
293 293 date: Thu Jan 01 00:00:02 1970 +0000
294 294 summary: firstline
295 295
296 296 % commit rejecttest
297 297 a
298 298 overwriting a expanding keywords
299 299 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
300 300 % export
301 301 % import
302 302 applying ../rejecttest.diff
303 303 % cat
304 304 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
305 305 do not process $Id: rejecttest
306 306 xxx $
307 307 $Xinfo: User Name <user@example.com>: rejects? $
308 308 ignore $Id$
309 309
310 310 % rollback
311 311 rolling back last transaction
312 312 % clean update
313 313 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 314 % kwexpand/kwshrink on selected files
315 315 % copy a x/a
316 316 % kwexpand a
317 317 overwriting a expanding keywords
318 318 % kwexpand x/a should abort
319 319 abort: outstanding uncommitted changes
320 320 x/a
321 321 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
322 322 overwriting x/a expanding keywords
323 323 committed changeset 3:cfa68229c1167443337266ebac453c73b1d5d16e
324 324 % cat a
325 325 expand $Id: x/a cfa68229c116 Thu, 01 Jan 1970 00:00:03 +0000 user $
326 326 do not process $Id:
327 327 xxx $
328 328 $Xinfo: User Name <user@example.com>: xa $
329 329 % kwshrink a inside directory x
330 330 overwriting x/a shrinking keywords
331 331 % cat a
332 332 expand $Id$
333 333 do not process $Id:
334 334 xxx $
335 335 $Xinfo$
336 336 % kwexpand nonexistent
337 337 nonexistent:
338 338 % hg serve
339 339 % expansion
340 340 % hgweb file
341 341 200 Script output follows
342 342
343 343 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
344 344 do not process $Id:
345 345 xxx $
346 346 $Xinfo: User Name <user@example.com>: firstline $
347 347 % no expansion
348 348 % hgweb annotate
349 349 200 Script output follows
350 350
351 351
352 352 user@1: expand $Id$
353 353 user@1: do not process $Id:
354 354 user@1: xxx $
355 355 user@2: $Xinfo$
356 356
357 357
358 358
359 359
360 360 % hgweb changeset
361 361 200 Script output follows
362 362
363 363
364 364 # HG changeset patch
365 365 # User User Name <user@example.com>
366 366 # Date 3 0
367 367 # Node ID cfa68229c1167443337266ebac453c73b1d5d16e
368 368 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
369 369 xa
370 370
371 371 diff -r bb948857c743 -r cfa68229c116 x/a
372 372 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
373 373 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
374 374 @@ -0,0 +1,4 @@
375 375 +expand $Id$
376 376 +do not process $Id:
377 377 +xxx $
378 378 +$Xinfo$
379 379
380 380 % hgweb filediff
381 381 200 Script output follows
382 382
383 383
384 384 diff -r ef63ca68695b -r bb948857c743 a
385 385 --- a/a Thu Jan 01 00:00:00 1970 +0000
386 386 +++ b/a Thu Jan 01 00:00:02 1970 +0000
387 387 @@ -1,3 +1,4 @@
388 388 expand $Id$
389 389 do not process $Id:
390 390 xxx $
391 391 +$Xinfo$
392 392
393 393
394 394
395 395
396 396 % errors encountered
397 397 % merge/resolve
398 398 % simplemerge
399 399 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
400 400 created new head
401 401 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 402 (branch merge, don't forget to commit)
403 403 $Id: m 8731e1dadc99 Thu, 01 Jan 1970 00:00:00 +0000 test $
404 404 foo
405 405 % conflict
406 406 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
407 407 created new head
408 408 merging m
409 409 warning: conflicts during merge.
410 410 merging m failed!
411 411 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
412 412 use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
413 413 % keyword stays outside conflict zone
414 414 $Id$
415 415 <<<<<<< local
416 416 bar
417 417 =======
418 418 foo
419 419 >>>>>>> other
420 420 % resolve to local
421 421 $Id: m 43dfd2854b5b Thu, 01 Jan 1970 00:00:00 +0000 test $
422 422 bar
423 % test restricted mode with transplant -b
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 marked working directory as branch foo
426 created new head
427 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 applying 1c4378f51c4d
429 1c4378f51c4d transplanted to 7d855abcab87
430 % no expansion in changeset
431 changeset: 11:7d855abcab87
432 tag: tip
433 parent: 9:43dfd2854b5b
434 user: test
435 date: Thu Jan 01 00:00:00 1970 +0000
436 summary: 9foobranch
437
438 diff -r 43dfd2854b5b -r 7d855abcab87 a
439 --- a/a Thu Jan 01 00:00:00 1970 +0000
440 +++ b/a Thu Jan 01 00:00:00 1970 +0000
441 @@ -1,3 +1,4 @@
442 +foobranch
443 expand $Id$
444 do not process $Id:
445 xxx $
446
447 % expansion in file
448 foobranch
449 expand $Id: a 7d855abcab87 Thu, 01 Jan 1970 00:00:00 +0000 test $
423 450 % switch off expansion
424 451 % kwshrink with unknown file u
425 452 overwriting a shrinking keywords
426 453 overwriting m shrinking keywords
427 454 overwriting x/a shrinking keywords
428 455 % cat
429 456 expand $Id$
430 457 do not process $Id:
431 458 xxx $
432 459 $Xinfo$
433 460 ignore $Id$
434 461 % hg cat
435 462 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
436 463 do not process $Id:
437 464 xxx $
438 465 $Xinfo: User Name <user@example.com>: firstline $
439 466 ignore $Id$
440 467 a
441 468 % cat
442 469 expand $Id$
443 470 do not process $Id:
444 471 xxx $
445 472 $Xinfo$
446 473 ignore $Id$
447 474 % hg cat
448 475 expand $Id$
449 476 do not process $Id:
450 477 xxx $
451 478 $Xinfo$
452 479 ignore $Id$
453 480 a
General Comments 0
You need to be logged in to leave comments. Login now