##// END OF EJS Templates
keyword: fix weeding of expansion candidates when recording...
Christian Ebert -
r12684:8348599c default
parent child Browse files
Show More
@@ -1,619 +1,620 b''
1 1 # keyword.py - $Keyword$ expansion for Mercurial
2 2 #
3 3 # Copyright 2007-2010 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 or any later version.
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 Keywords expand to the changeset data pertaining to the latest change
39 39 relative to the working directory parent of each file.
40 40
41 41 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
42 42 sections of hgrc files.
43 43
44 44 Example::
45 45
46 46 [keyword]
47 47 # expand keywords in every python file except those matching "x*"
48 48 **.py =
49 49 x* = ignore
50 50
51 51 [keywordset]
52 52 # prefer svn- over cvs-like default keywordmaps
53 53 svn = True
54 54
55 55 .. note::
56 56 The more specific you are in your filename patterns the less you
57 57 lose speed in huge repositories.
58 58
59 59 For [keywordmaps] template mapping and expansion demonstration and
60 60 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
61 61 available templates and filters.
62 62
63 63 Three additional date template filters are provided::
64 64
65 65 utcdate "2006/09/18 15:13:13"
66 66 svnutcdate "2006-09-18 15:13:13Z"
67 67 svnisodate "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
68 68
69 69 The default template mappings (view with :hg:`kwdemo -d`) can be
70 70 replaced with customized keywords and templates. Again, run
71 71 :hg:`kwdemo` to control the results of your config changes.
72 72
73 73 Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
74 74 the risk of inadvertently storing expanded keywords in the change
75 75 history.
76 76
77 77 To force expansion after enabling it, or a configuration change, run
78 78 :hg:`kwexpand`.
79 79
80 80 Expansions spanning more than one line and incremental expansions,
81 81 like CVS' $Log$, are not supported. A keyword template map "Log =
82 82 {desc}" expands to the first line of the changeset description.
83 83 '''
84 84
85 85 from mercurial import commands, cmdutil, dispatch, filelog, extensions
86 86 from mercurial import localrepo, match, patch, templatefilters, templater, util
87 87 from mercurial.hgweb import webcommands
88 88 from mercurial.i18n import _
89 89 import re, shutil, tempfile
90 90
91 91 commands.optionalrepo += ' kwdemo'
92 92
93 93 # hg commands that do not act on keywords
94 94 nokwcommands = ('add addremove annotate bundle export grep incoming init log'
95 95 ' outgoing push tip verify convert email glog')
96 96
97 97 # hg commands that trigger expansion only when writing to working dir,
98 98 # not when reading filelog, and unexpand when reading from working dir
99 99 restricted = 'merge kwexpand kwshrink record qrecord resolve transplant'
100 100
101 101 # names of extensions using dorecord
102 102 recordextensions = 'record'
103 103
104 104 # date like in cvs' $Date
105 105 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
106 106 # date like in svn's $Date
107 107 svnisodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
108 108 # date like in svn's $Id
109 109 svnutcdate = lambda x: util.datestr((x[0], 0), '%Y-%m-%d %H:%M:%SZ')
110 110
111 111 # make keyword tools accessible
112 112 kwtools = {'templater': None, 'hgcmd': ''}
113 113
114 114
115 115 def _defaultkwmaps(ui):
116 116 '''Returns default keywordmaps according to keywordset configuration.'''
117 117 templates = {
118 118 'Revision': '{node|short}',
119 119 'Author': '{author|user}',
120 120 }
121 121 kwsets = ({
122 122 'Date': '{date|utcdate}',
123 123 'RCSfile': '{file|basename},v',
124 124 'RCSFile': '{file|basename},v', # kept for backwards compatibility
125 125 # with hg-keyword
126 126 'Source': '{root}/{file},v',
127 127 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
128 128 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
129 129 }, {
130 130 'Date': '{date|svnisodate}',
131 131 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
132 132 'LastChangedRevision': '{node|short}',
133 133 'LastChangedBy': '{author|user}',
134 134 'LastChangedDate': '{date|svnisodate}',
135 135 })
136 136 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
137 137 return templates
138 138
139 139 def _shrinktext(text, subfunc):
140 140 '''Helper for keyword expansion removal in text.
141 141 Depending on subfunc also returns number of substitutions.'''
142 142 return subfunc(r'$\1$', text)
143 143
144 144
145 145 class kwtemplater(object):
146 146 '''
147 147 Sets up keyword templates, corresponding keyword regex, and
148 148 provides keyword substitution functions.
149 149 '''
150 150
151 151 def __init__(self, ui, repo, inc, exc):
152 152 self.ui = ui
153 153 self.repo = repo
154 154 self.match = match.match(repo.root, '', [], inc, exc)
155 155 self.restrict = kwtools['hgcmd'] in restricted.split()
156 156 self.record = False
157 157
158 158 kwmaps = self.ui.configitems('keywordmaps')
159 159 if kwmaps: # override default templates
160 160 self.templates = dict((k, templater.parsestring(v, False))
161 161 for k, v in kwmaps)
162 162 else:
163 163 self.templates = _defaultkwmaps(self.ui)
164 164 escaped = '|'.join(map(re.escape, self.templates.keys()))
165 165 self.re_kw = re.compile(r'\$(%s)\$' % escaped)
166 166 self.re_kwexp = re.compile(r'\$(%s): [^$\n\r]*? \$' % escaped)
167 167
168 168 templatefilters.filters.update({'utcdate': utcdate,
169 169 'svnisodate': svnisodate,
170 170 'svnutcdate': svnutcdate})
171 171
172 172 def substitute(self, data, path, ctx, subfunc):
173 173 '''Replaces keywords in data with expanded template.'''
174 174 def kwsub(mobj):
175 175 kw = mobj.group(1)
176 176 ct = cmdutil.changeset_templater(self.ui, self.repo,
177 177 False, None, '', False)
178 178 ct.use_template(self.templates[kw])
179 179 self.ui.pushbuffer()
180 180 ct.show(ctx, root=self.repo.root, file=path)
181 181 ekw = templatefilters.firstline(self.ui.popbuffer())
182 182 return '$%s: %s $' % (kw, ekw)
183 183 return subfunc(kwsub, data)
184 184
185 185 def expand(self, path, node, data):
186 186 '''Returns data with keywords expanded.'''
187 187 if not self.restrict and self.match(path) and not util.binary(data):
188 188 ctx = self.repo.filectx(path, fileid=node).changectx()
189 189 return self.substitute(data, path, ctx, self.re_kw.sub)
190 190 return data
191 191
192 192 def iskwfile(self, cand, ctx):
193 193 '''Returns subset of candidates which are configured for keyword
194 194 expansion are not symbolic links.'''
195 195 return [f for f in cand if self.match(f) and not 'l' in ctx.flags(f)]
196 196
197 197 def overwrite(self, ctx, candidates, lookup, expand, recsubn=None):
198 198 '''Overwrites selected files expanding/shrinking keywords.'''
199 199 if self.restrict or lookup: # exclude kw_copy
200 200 candidates = self.iskwfile(candidates, ctx)
201 201 if not candidates:
202 202 return
203 203 commit = self.restrict and not lookup
204 204 if self.restrict or expand and lookup:
205 205 mf = ctx.manifest()
206 206 fctx = ctx
207 207 subn = (self.restrict and self.re_kw.subn or
208 208 recsubn or self.re_kwexp.subn)
209 209 msg = (expand and _('overwriting %s expanding keywords\n')
210 210 or _('overwriting %s shrinking keywords\n'))
211 211 for f in candidates:
212 212 if self.restrict:
213 213 data = self.repo.file(f).read(mf[f])
214 214 else:
215 215 data = self.repo.wread(f)
216 216 if util.binary(data):
217 217 continue
218 218 if expand:
219 219 if lookup:
220 220 fctx = self.repo.filectx(f, fileid=mf[f]).changectx()
221 221 data, found = self.substitute(data, f, fctx, subn)
222 222 elif self.restrict:
223 223 found = self.re_kw.search(data)
224 224 else:
225 225 data, found = _shrinktext(data, subn)
226 226 if found:
227 227 self.ui.note(msg % f)
228 228 self.repo.wwrite(f, data, ctx.flags(f))
229 229 if commit:
230 230 self.repo.dirstate.normal(f)
231 231 elif self.record:
232 232 self.repo.dirstate.normallookup(f)
233 233
234 234 def shrink(self, fname, text):
235 235 '''Returns text with all keyword substitutions removed.'''
236 236 if self.match(fname) and not util.binary(text):
237 237 return _shrinktext(text, self.re_kwexp.sub)
238 238 return text
239 239
240 240 def shrinklines(self, fname, lines):
241 241 '''Returns lines with keyword substitutions removed.'''
242 242 if self.match(fname):
243 243 text = ''.join(lines)
244 244 if not util.binary(text):
245 245 return _shrinktext(text, self.re_kwexp.sub).splitlines(True)
246 246 return lines
247 247
248 248 def wread(self, fname, data):
249 249 '''If in restricted mode returns data read from wdir with
250 250 keyword substitutions removed.'''
251 251 return self.restrict and self.shrink(fname, data) or data
252 252
253 253 class kwfilelog(filelog.filelog):
254 254 '''
255 255 Subclass of filelog to hook into its read, add, cmp methods.
256 256 Keywords are "stored" unexpanded, and processed on reading.
257 257 '''
258 258 def __init__(self, opener, kwt, path):
259 259 super(kwfilelog, self).__init__(opener, path)
260 260 self.kwt = kwt
261 261 self.path = path
262 262
263 263 def read(self, node):
264 264 '''Expands keywords when reading filelog.'''
265 265 data = super(kwfilelog, self).read(node)
266 266 if self.renamed(node):
267 267 return data
268 268 return self.kwt.expand(self.path, node, data)
269 269
270 270 def add(self, text, meta, tr, link, p1=None, p2=None):
271 271 '''Removes keyword substitutions when adding to filelog.'''
272 272 text = self.kwt.shrink(self.path, text)
273 273 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
274 274
275 275 def cmp(self, node, text):
276 276 '''Removes keyword substitutions for comparison.'''
277 277 text = self.kwt.shrink(self.path, text)
278 278 return super(kwfilelog, self).cmp(node, text)
279 279
280 280 def _status(ui, repo, kwt, *pats, **opts):
281 281 '''Bails out if [keyword] configuration is not active.
282 282 Returns status of working directory.'''
283 283 if kwt:
284 284 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
285 285 unknown=opts.get('unknown') or opts.get('all'))
286 286 if ui.configitems('keyword'):
287 287 raise util.Abort(_('[keyword] patterns cannot match'))
288 288 raise util.Abort(_('no [keyword] patterns configured'))
289 289
290 290 def _kwfwrite(ui, repo, expand, *pats, **opts):
291 291 '''Selects files and passes them to kwtemplater.overwrite.'''
292 292 wctx = repo[None]
293 293 if len(wctx.parents()) > 1:
294 294 raise util.Abort(_('outstanding uncommitted merge'))
295 295 kwt = kwtools['templater']
296 296 wlock = repo.wlock()
297 297 try:
298 298 status = _status(ui, repo, kwt, *pats, **opts)
299 299 modified, added, removed, deleted, unknown, ignored, clean = status
300 300 if modified or added or removed or deleted:
301 301 raise util.Abort(_('outstanding uncommitted changes'))
302 302 kwt.overwrite(wctx, clean, True, expand)
303 303 finally:
304 304 wlock.release()
305 305
306 306 def demo(ui, repo, *args, **opts):
307 307 '''print [keywordmaps] configuration and an expansion example
308 308
309 309 Show current, custom, or default keyword template maps and their
310 310 expansions.
311 311
312 312 Extend the current configuration by specifying maps as arguments
313 313 and using -f/--rcfile to source an external hgrc file.
314 314
315 315 Use -d/--default to disable current configuration.
316 316
317 317 See :hg:`help templates` for information on templates and filters.
318 318 '''
319 319 def demoitems(section, items):
320 320 ui.write('[%s]\n' % section)
321 321 for k, v in sorted(items):
322 322 ui.write('%s = %s\n' % (k, v))
323 323
324 324 fn = 'demo.txt'
325 325 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
326 326 ui.note(_('creating temporary repository at %s\n') % tmpdir)
327 327 repo = localrepo.localrepository(ui, tmpdir, True)
328 328 ui.setconfig('keyword', fn, '')
329 329
330 330 uikwmaps = ui.configitems('keywordmaps')
331 331 if args or opts.get('rcfile'):
332 332 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
333 333 if uikwmaps:
334 334 ui.status(_('\textending current template maps\n'))
335 335 if opts.get('default') or not uikwmaps:
336 336 ui.status(_('\toverriding default template maps\n'))
337 337 if opts.get('rcfile'):
338 338 ui.readconfig(opts.get('rcfile'))
339 339 if args:
340 340 # simulate hgrc parsing
341 341 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
342 342 fp = repo.opener('hgrc', 'w')
343 343 fp.writelines(rcmaps)
344 344 fp.close()
345 345 ui.readconfig(repo.join('hgrc'))
346 346 kwmaps = dict(ui.configitems('keywordmaps'))
347 347 elif opts.get('default'):
348 348 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
349 349 kwmaps = _defaultkwmaps(ui)
350 350 if uikwmaps:
351 351 ui.status(_('\tdisabling current template maps\n'))
352 352 for k, v in kwmaps.iteritems():
353 353 ui.setconfig('keywordmaps', k, v)
354 354 else:
355 355 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
356 356 kwmaps = dict(uikwmaps) or _defaultkwmaps(ui)
357 357
358 358 uisetup(ui)
359 359 reposetup(ui, repo)
360 360 ui.write('[extensions]\nkeyword =\n')
361 361 demoitems('keyword', ui.configitems('keyword'))
362 362 demoitems('keywordmaps', kwmaps.iteritems())
363 363 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
364 364 repo.wopener(fn, 'w').write(keywords)
365 365 repo[None].add([fn])
366 366 ui.note(_('\nkeywords written to %s:\n') % fn)
367 367 ui.note(keywords)
368 368 repo.dirstate.setbranch('demobranch')
369 369 for name, cmd in ui.configitems('hooks'):
370 370 if name.split('.', 1)[0].find('commit') > -1:
371 371 repo.ui.setconfig('hooks', name, '')
372 372 msg = _('hg keyword configuration and expansion example')
373 373 ui.note("hg ci -m '%s'\n" % msg)
374 374 repo.commit(text=msg)
375 375 ui.status(_('\n\tkeywords expanded\n'))
376 376 ui.write(repo.wread(fn))
377 377 shutil.rmtree(tmpdir, ignore_errors=True)
378 378
379 379 def expand(ui, repo, *pats, **opts):
380 380 '''expand keywords in the working directory
381 381
382 382 Run after (re)enabling keyword expansion.
383 383
384 384 kwexpand refuses to run if given files contain local changes.
385 385 '''
386 386 # 3rd argument sets expansion to True
387 387 _kwfwrite(ui, repo, True, *pats, **opts)
388 388
389 389 def files(ui, repo, *pats, **opts):
390 390 '''show files configured for keyword expansion
391 391
392 392 List which files in the working directory are matched by the
393 393 [keyword] configuration patterns.
394 394
395 395 Useful to prevent inadvertent keyword expansion and to speed up
396 396 execution by including only files that are actual candidates for
397 397 expansion.
398 398
399 399 See :hg:`help keyword` on how to construct patterns both for
400 400 inclusion and exclusion of files.
401 401
402 402 With -A/--all and -v/--verbose the codes used to show the status
403 403 of files are::
404 404
405 405 K = keyword expansion candidate
406 406 k = keyword expansion candidate (not tracked)
407 407 I = ignored
408 408 i = ignored (not tracked)
409 409 '''
410 410 kwt = kwtools['templater']
411 411 status = _status(ui, repo, kwt, *pats, **opts)
412 412 cwd = pats and repo.getcwd() or ''
413 413 modified, added, removed, deleted, unknown, ignored, clean = status
414 414 files = []
415 415 if not opts.get('unknown') or opts.get('all'):
416 416 files = sorted(modified + added + clean)
417 417 wctx = repo[None]
418 418 kwfiles = kwt.iskwfile(files, wctx)
419 419 kwunknown = kwt.iskwfile(unknown, wctx)
420 420 if not opts.get('ignore') or opts.get('all'):
421 421 showfiles = kwfiles, kwunknown
422 422 else:
423 423 showfiles = [], []
424 424 if opts.get('all') or opts.get('ignore'):
425 425 showfiles += ([f for f in files if f not in kwfiles],
426 426 [f for f in unknown if f not in kwunknown])
427 427 for char, filenames in zip('KkIi', showfiles):
428 428 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
429 429 for f in filenames:
430 430 ui.write(fmt % repo.pathto(f, cwd))
431 431
432 432 def shrink(ui, repo, *pats, **opts):
433 433 '''revert expanded keywords in the working directory
434 434
435 435 Run before changing/disabling active keywords or if you experience
436 436 problems with :hg:`import` or :hg:`merge`.
437 437
438 438 kwshrink refuses to run if given files contain local changes.
439 439 '''
440 440 # 3rd argument sets expansion to False
441 441 _kwfwrite(ui, repo, False, *pats, **opts)
442 442
443 443
444 444 def uisetup(ui):
445 445 ''' Monkeypatches dispatch._parse to retrieve user command.'''
446 446
447 447 def kwdispatch_parse(orig, ui, args):
448 448 '''Monkeypatch dispatch._parse to obtain running hg command.'''
449 449 cmd, func, args, options, cmdoptions = orig(ui, args)
450 450 kwtools['hgcmd'] = cmd
451 451 return cmd, func, args, options, cmdoptions
452 452
453 453 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
454 454
455 455 def reposetup(ui, repo):
456 456 '''Sets up repo as kwrepo for keyword substitution.
457 457 Overrides file method to return kwfilelog instead of filelog
458 458 if file matches user configuration.
459 459 Wraps commit to overwrite configured files with updated
460 460 keyword substitutions.
461 461 Monkeypatches patch and webcommands.'''
462 462
463 463 try:
464 464 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
465 465 or '.hg' in util.splitpath(repo.root)
466 466 or repo._url.startswith('bundle:')):
467 467 return
468 468 except AttributeError:
469 469 pass
470 470
471 471 inc, exc = [], ['.hg*']
472 472 for pat, opt in ui.configitems('keyword'):
473 473 if opt != 'ignore':
474 474 inc.append(pat)
475 475 else:
476 476 exc.append(pat)
477 477 if not inc:
478 478 return
479 479
480 480 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
481 481
482 482 class kwrepo(repo.__class__):
483 483 def file(self, f):
484 484 if f[0] == '/':
485 485 f = f[1:]
486 486 return kwfilelog(self.sopener, kwt, f)
487 487
488 488 def wread(self, filename):
489 489 data = super(kwrepo, self).wread(filename)
490 490 return kwt.wread(filename, data)
491 491
492 492 def commit(self, *args, **opts):
493 493 # use custom commitctx for user commands
494 494 # other extensions can still wrap repo.commitctx directly
495 495 self.commitctx = self.kwcommitctx
496 496 try:
497 497 return super(kwrepo, self).commit(*args, **opts)
498 498 finally:
499 499 del self.commitctx
500 500
501 501 def kwcommitctx(self, ctx, error=False):
502 502 n = super(kwrepo, self).commitctx(ctx, error)
503 503 # no lock needed, only called from repo.commit() which already locks
504 504 if not kwt.record:
505 505 restrict = kwt.restrict
506 506 kwt.restrict = True
507 507 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
508 508 False, True)
509 509 kwt.restrict = restrict
510 510 return n
511 511
512 512 def rollback(self, dryrun=False):
513 513 wlock = repo.wlock()
514 514 try:
515 515 if not dryrun:
516 516 changed = self['.'].files()
517 517 ret = super(kwrepo, self).rollback(dryrun)
518 518 if not dryrun:
519 519 ctx = self['.']
520 520 modified, added = self[None].status()[:2]
521 521 modified = [f for f in modified if f in changed]
522 522 added = [f for f in added if f in changed]
523 523 kwt.overwrite(ctx, added, True, False)
524 524 kwt.overwrite(ctx, modified, True, True)
525 525 return ret
526 526 finally:
527 527 wlock.release()
528 528
529 529 # monkeypatches
530 530 def kwpatchfile_init(orig, self, ui, fname, opener,
531 531 missing=False, eolmode=None):
532 532 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
533 533 rejects or conflicts due to expanded keywords in working dir.'''
534 534 orig(self, ui, fname, opener, missing, eolmode)
535 535 # shrink keywords read from working dir
536 536 self.lines = kwt.shrinklines(self.fname, self.lines)
537 537
538 538 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
539 539 opts=None, prefix=''):
540 540 '''Monkeypatch patch.diff to avoid expansion.'''
541 541 kwt.restrict = True
542 542 return orig(repo, node1, node2, match, changes, opts, prefix)
543 543
544 544 def kwweb_skip(orig, web, req, tmpl):
545 545 '''Wraps webcommands.x turning off keyword expansion.'''
546 546 kwt.match = util.never
547 547 return orig(web, req, tmpl)
548 548
549 549 def kw_copy(orig, ui, repo, pats, opts, rename=False):
550 550 '''Wraps cmdutil.copy so that copy/rename destinations do not
551 551 contain expanded keywords.
552 552 Note that the source may also be a symlink as:
553 553 hg cp sym x -> x is symlink
554 554 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords)
555 555 '''
556 556 orig(ui, repo, pats, opts, rename)
557 557 if opts.get('dry_run'):
558 558 return
559 559 wctx = repo[None]
560 560 candidates = [f for f in repo.dirstate.copies() if
561 561 kwt.match(repo.dirstate.copied(f)) and
562 562 not 'l' in wctx.flags(f)]
563 563 kwt.overwrite(wctx, candidates, False, False)
564 564
565 565 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
566 566 '''Wraps record.dorecord expanding keywords after recording.'''
567 567 wlock = repo.wlock()
568 568 try:
569 569 # record returns 0 even when nothing has changed
570 570 # therefore compare nodes before and after
571 571 kwt.record = True
572 572 ctx = repo['.']
573 573 modified, added = repo[None].status()[:2]
574 574 ret = orig(ui, repo, commitfunc, *pats, **opts)
575 575 recctx = repo['.']
576 576 if ctx != recctx:
577 modified = [f for f in modified if f in recctx]
578 added = [f for f in added if f in recctx]
577 changed = recctx.files()
578 modified = [f for f in modified if f in changed]
579 added = [f for f in added if f in changed]
579 580 kwt.restrict = False
580 581 kwt.overwrite(recctx, modified, False, True, kwt.re_kwexp.subn)
581 582 kwt.overwrite(recctx, added, False, True, kwt.re_kw.subn)
582 583 kwt.restrict = True
583 584 return ret
584 585 finally:
585 586 wlock.release()
586 587
587 588 repo.__class__ = kwrepo
588 589
589 590 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
590 591 extensions.wrapfunction(patch, 'diff', kw_diff)
591 592 extensions.wrapfunction(cmdutil, 'copy', kw_copy)
592 593 for c in 'annotate changeset rev filediff diff'.split():
593 594 extensions.wrapfunction(webcommands, c, kwweb_skip)
594 595 for name in recordextensions.split():
595 596 try:
596 597 record = extensions.find(name)
597 598 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
598 599 except KeyError:
599 600 pass
600 601
601 602 cmdtable = {
602 603 'kwdemo':
603 604 (demo,
604 605 [('d', 'default', None, _('show default keyword template maps')),
605 606 ('f', 'rcfile', '',
606 607 _('read maps from rcfile'), _('FILE'))],
607 608 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
608 609 'kwexpand': (expand, commands.walkopts,
609 610 _('hg kwexpand [OPTION]... [FILE]...')),
610 611 'kwfiles':
611 612 (files,
612 613 [('A', 'all', None, _('show keyword status flags of all files')),
613 614 ('i', 'ignore', None, _('show files excluded from expansion')),
614 615 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
615 616 ] + commands.walkopts,
616 617 _('hg kwfiles [OPTION]... [FILE]...')),
617 618 'kwshrink': (shrink, commands.walkopts,
618 619 _('hg kwshrink [OPTION]... [FILE]...')),
619 620 }
@@ -1,1015 +1,1018 b''
1 1 $ cat <<EOF >> $HGRCPATH
2 2 > [extensions]
3 3 > keyword =
4 4 > mq =
5 5 > notify =
6 6 > record =
7 7 > transplant =
8 8 > [ui]
9 9 > interactive = true
10 10 > EOF
11 11
12 12 Run kwdemo before [keyword] files are set up
13 13 as it would succeed without uisetup otherwise
14 14
15 15 $ hg --quiet kwdemo
16 16 [extensions]
17 17 keyword =
18 18 [keyword]
19 19 demo.txt =
20 20 [keywordmaps]
21 21 Author = {author|user}
22 22 Date = {date|utcdate}
23 23 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
24 24 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
25 25 RCSFile = {file|basename},v
26 26 RCSfile = {file|basename},v
27 27 Revision = {node|short}
28 28 Source = {root}/{file},v
29 29 $Author: test $
30 30 $Date: ????/??/?? ??:??:?? $ (glob)
31 31 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
32 32 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
33 33 $RCSFile: demo.txt,v $
34 34 $RCSfile: demo.txt,v $
35 35 $Revision: ???????????? $ (glob)
36 36 $Source: */demo.txt,v $ (glob)
37 37
38 38 $ hg --quiet kwdemo "Branch = {branches}"
39 39 [extensions]
40 40 keyword =
41 41 [keyword]
42 42 demo.txt =
43 43 [keywordmaps]
44 44 Branch = {branches}
45 45 $Branch: demobranch $
46 46
47 47 $ cat <<EOF >> $HGRCPATH
48 48 > [keyword]
49 49 > ** =
50 50 > b = ignore
51 51 > i = ignore
52 52 > [hooks]
53 53 > EOF
54 54 $ cp $HGRCPATH $HGRCPATH.nohooks
55 55 > cat <<EOF >> $HGRCPATH
56 56 > commit=
57 57 > commit.test=cp a hooktest
58 58 > EOF
59 59
60 60 $ hg init Test-bndl
61 61 $ cd Test-bndl
62 62
63 63 kwshrink should exit silently in empty/invalid repo
64 64
65 65 $ hg kwshrink
66 66
67 67 Symlinks cannot be created on Windows.
68 68 A bundle to test this was made with:
69 69 hg init t
70 70 cd t
71 71 echo a > a
72 72 ln -s a sym
73 73 hg add sym
74 74 hg ci -m addsym -u mercurial
75 75 hg bundle --base null ../test-keyword.hg
76 76
77 77 $ hg pull -u "$TESTDIR"/test-keyword.hg
78 78 pulling from *test-keyword.hg (glob)
79 79 requesting all changes
80 80 adding changesets
81 81 adding manifests
82 82 adding file changes
83 83 added 1 changesets with 1 changes to 1 files
84 84 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 85
86 86 $ echo 'expand $Id$' > a
87 87 $ echo 'do not process $Id:' >> a
88 88 $ echo 'xxx $' >> a
89 89 $ echo 'ignore $Id$' > b
90 90
91 91 Output files as they were created
92 92
93 93 $ cat a b
94 94 expand $Id$
95 95 do not process $Id:
96 96 xxx $
97 97 ignore $Id$
98 98
99 99 no kwfiles
100 100
101 101 $ hg kwfiles
102 102
103 103 untracked candidates
104 104
105 105 $ hg -v kwfiles --unknown
106 106 k a
107 107
108 108 Add files and check status
109 109
110 110 $ hg addremove
111 111 adding a
112 112 adding b
113 113 $ hg status
114 114 A a
115 115 A b
116 116
117 117
118 118 Default keyword expansion including commit hook
119 119 Interrupted commit should not change state or run commit hook
120 120
121 121 $ hg --debug commit
122 122 abort: empty commit message
123 123 [255]
124 124 $ hg status
125 125 A a
126 126 A b
127 127
128 128 Commit with several checks
129 129
130 130 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
131 131 a
132 132 b
133 133 overwriting a expanding keywords
134 134 running hook commit.test: cp a hooktest
135 135 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
136 136 $ hg status
137 137 ? hooktest
138 138 $ hg debugrebuildstate
139 139 $ hg --quiet identify
140 140 ef63ca68695b
141 141
142 142 cat files in working directory with keywords expanded
143 143
144 144 $ cat a b
145 145 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
146 146 do not process $Id:
147 147 xxx $
148 148 ignore $Id$
149 149
150 150 hg cat files and symlink, no expansion
151 151
152 152 $ hg cat sym a b && echo
153 153 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
154 154 do not process $Id:
155 155 xxx $
156 156 ignore $Id$
157 157 a
158 158
159 159 Test hook execution
160 160
161 161 $ diff a hooktest
162 162
163 163 $ cp $HGRCPATH.nohooks $HGRCPATH
164 164 $ rm hooktest
165 165
166 166 bundle
167 167
168 168 $ hg bundle --base null ../kw.hg
169 169 2 changesets found
170 170 $ cd ..
171 171 $ hg init Test
172 172 $ cd Test
173 173
174 174 Notify on pull to check whether keywords stay as is in email
175 175 ie. if patch.diff wrapper acts as it should
176 176
177 177 $ cat <<EOF >> $HGRCPATH
178 178 > [hooks]
179 179 > incoming.notify = python:hgext.notify.hook
180 180 > [notify]
181 181 > sources = pull
182 182 > diffstat = False
183 183 > maxsubject = 15
184 184 > [reposubs]
185 185 > * = Test
186 186 > EOF
187 187
188 188 Pull from bundle and trigger notify
189 189
190 190 $ hg pull -u ../kw.hg
191 191 pulling from ../kw.hg
192 192 requesting all changes
193 193 adding changesets
194 194 adding manifests
195 195 adding file changes
196 196 added 2 changesets with 3 changes to 3 files
197 197 Content-Type: text/plain; charset="us-ascii"
198 198 MIME-Version: 1.0
199 199 Content-Transfer-Encoding: 7bit
200 200 Date: * (glob)
201 201 Subject: changeset in...
202 202 From: mercurial
203 203 X-Hg-Notification: changeset a2392c293916
204 204 Message-Id: <hg.a2392c293916*> (glob)
205 205 To: Test
206 206
207 207 changeset a2392c293916 in $TESTTMP/Test
208 208 details: *cmd=changeset;node=a2392c293916 (glob)
209 209 description:
210 210 addsym
211 211
212 212 diffs (6 lines):
213 213
214 214 diff -r 000000000000 -r a2392c293916 sym
215 215 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
216 216 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
217 217 @@ -0,0 +1,1 @@
218 218 +a
219 219 \ No newline at end of file
220 220 Content-Type: text/plain; charset="us-ascii"
221 221 MIME-Version: 1.0
222 222 Content-Transfer-Encoding: 7bit
223 223 Date:* (glob)
224 224 Subject: changeset in...
225 225 From: User Name <user@example.com>
226 226 X-Hg-Notification: changeset ef63ca68695b
227 227 Message-Id: <hg.ef63ca68695b*> (glob)
228 228 To: Test
229 229
230 230 changeset ef63ca68695b in $TESTTMP/Test
231 231 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
232 232 description:
233 233 absym
234 234
235 235 diffs (12 lines):
236 236
237 237 diff -r a2392c293916 -r ef63ca68695b a
238 238 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
239 239 +++ b/a Thu Jan 01 00:00:00 1970 +0000
240 240 @@ -0,0 +1,3 @@
241 241 +expand $Id$
242 242 +do not process $Id:
243 243 +xxx $
244 244 diff -r a2392c293916 -r ef63ca68695b b
245 245 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
246 246 +++ b/b Thu Jan 01 00:00:00 1970 +0000
247 247 @@ -0,0 +1,1 @@
248 248 +ignore $Id$
249 249 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
250 250
251 251 $ cp $HGRCPATH.nohooks $HGRCPATH
252 252
253 253 Touch files and check with status
254 254
255 255 $ touch a b
256 256 $ hg status
257 257
258 258 Update and expand
259 259
260 260 $ rm sym a b
261 261 $ hg update -C
262 262 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 263 $ cat a b
264 264 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
265 265 do not process $Id:
266 266 xxx $
267 267 ignore $Id$
268 268
269 269 Check whether expansion is filewise
270 270
271 271 $ echo '$Id$' > c
272 272 $ echo 'tests for different changenodes' >> c
273 273
274 274 commit file c
275 275
276 276 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
277 277 adding c
278 278
279 279 force expansion
280 280
281 281 $ hg -v kwexpand
282 282 overwriting a expanding keywords
283 283 overwriting c expanding keywords
284 284
285 285 compare changenodes in a and c
286 286
287 287 $ cat a c
288 288 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
289 289 do not process $Id:
290 290 xxx $
291 291 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
292 292 tests for different changenodes
293 293
294 record
295
296 $ echo '$Id$' > r
297 $ hg add r
298
294 299 record chunk
295 300
296 301 $ python -c \
297 302 > 'l=open("a").readlines();l.insert(1,"foo\n");l.append("bar\n");open("a","w").writelines(l);'
298 $ hg record -d '1 10' -m rectest<<EOF
303 $ hg record -d '1 10' -m rectest a<<EOF
299 304 > y
300 305 > y
301 306 > n
302 307 > EOF
303 308 diff --git a/a b/a
304 309 2 hunks, 2 lines changed
305 310 examine changes to 'a'? [Ynsfdaq?]
306 311 @@ -1,3 +1,4 @@
307 312 expand $Id$
308 313 +foo
309 314 do not process $Id:
310 315 xxx $
311 316 record change 1/2 to 'a'? [Ynsfdaq?]
312 317 @@ -2,2 +3,3 @@
313 318 do not process $Id:
314 319 xxx $
315 320 +bar
316 321 record change 2/2 to 'a'? [Ynsfdaq?]
317 322
318 323 $ hg identify
319 324 d17e03c92c97+ tip
320 325 $ hg status
321 326 M a
327 A r
322 328
323 329 Cat modified file a
324 330
325 331 $ cat a
326 332 expand $Id: a,v d17e03c92c97 1970/01/01 00:00:01 test $
327 333 foo
328 334 do not process $Id:
329 335 xxx $
330 336 bar
331 337
332 338 Diff remaining chunk
333 339
334 $ hg diff
340 $ hg diff a
335 341 diff -r d17e03c92c97 a
336 342 --- a/a Wed Dec 31 23:59:51 1969 -0000
337 343 +++ b/a * (glob)
338 344 @@ -2,3 +2,4 @@
339 345 foo
340 346 do not process $Id:
341 347 xxx $
342 348 +bar
343 349
344 350 $ hg rollback
345 351 rolling back to revision 2 (undo commit)
346 352
347 353 Record all chunks in file a
348 354
349 355 $ echo foo > msg
350 356
351 357 - do not use "hg record -m" here!
352 358
353 $ hg record -l msg -d '1 11'<<EOF
359 $ hg record -l msg -d '1 11' a<<EOF
354 360 > y
355 361 > y
356 362 > y
357 363 > EOF
358 364 diff --git a/a b/a
359 365 2 hunks, 2 lines changed
360 366 examine changes to 'a'? [Ynsfdaq?]
361 367 @@ -1,3 +1,4 @@
362 368 expand $Id$
363 369 +foo
364 370 do not process $Id:
365 371 xxx $
366 372 record change 1/2 to 'a'? [Ynsfdaq?]
367 373 @@ -2,2 +3,3 @@
368 374 do not process $Id:
369 375 xxx $
370 376 +bar
371 377 record change 2/2 to 'a'? [Ynsfdaq?]
372 378
373 379 File a should be clean
374 380
375 381 $ hg status -A a
376 382 C a
377 383
378 384 rollback and revert expansion
379 385
380 386 $ cat a
381 387 expand $Id: a,v 59f969a3b52c 1970/01/01 00:00:01 test $
382 388 foo
383 389 do not process $Id:
384 390 xxx $
385 391 bar
386 392 $ hg --verbose rollback
387 393 rolling back to revision 2 (undo commit)
388 394 overwriting a expanding keywords
389 395 $ hg status a
390 396 M a
391 397 $ cat a
392 398 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
393 399 foo
394 400 do not process $Id:
395 401 xxx $
396 402 bar
397 403 $ echo '$Id$' > y
398 404 $ echo '$Id$' > z
399 405 $ hg add y
400 406 $ hg commit -Am "rollback only" z
401 407 $ cat z
402 408 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
403 409 $ hg --verbose rollback
404 410 rolling back to revision 2 (undo commit)
405 411 overwriting z shrinking keywords
406 412
407 413 Only z should be overwritten
408 414
409 415 $ hg status a y z
410 416 M a
411 417 A y
412 418 A z
413 419 $ cat z
414 420 $Id$
415 421 $ hg forget y z
416 422 $ rm y z
417 423
418 $ hg update -C
419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 record added file alone
420 425
421 record added file
422
423 $ echo '$Id$' > r
424 $ hg add r
425 426 $ hg -v record -l msg -d '1 12' r<<EOF
426 427 > y
427 428 > EOF
428 429 diff --git a/r b/r
429 430 new file mode 100644
430 431 examine changes to 'r'? [Ynsfdaq?]
431 432 r
432 433 committed changeset 3:899491280810
433 434 overwriting r expanding keywords
434 435 $ hg --verbose rollback
435 436 rolling back to revision 2 (undo commit)
436 437 overwriting r shrinking keywords
437 438 $ hg forget r
438 439 $ rm msg r
440 $ hg update -C
441 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
439 442
440 443 Test patch queue repo
441 444
442 445 $ hg init --mq
443 446 $ hg qimport -r tip -n mqtest.diff
444 447 $ hg commit --mq -m mqtest
445 448
446 449 Keywords should not be expanded in patch
447 450
448 451 $ cat .hg/patches/mqtest.diff
449 452 # HG changeset patch
450 453 # User User Name <user@example.com>
451 454 # Date 1 0
452 455 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
453 456 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
454 457 cndiff
455 458
456 459 diff -r ef63ca68695b -r 40a904bbbe4c c
457 460 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
458 461 +++ b/c Thu Jan 01 00:00:01 1970 +0000
459 462 @@ -0,0 +1,2 @@
460 463 +$Id$
461 464 +tests for different changenodes
462 465
463 466 $ hg qpop
464 467 popping mqtest.diff
465 468 patch queue now empty
466 469
467 470 qgoto, implying qpush, should expand
468 471
469 472 $ hg qgoto mqtest.diff
470 473 applying mqtest.diff
471 474 now at: mqtest.diff
472 475 $ cat c
473 476 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
474 477 tests for different changenodes
475 478 $ hg cat c
476 479 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
477 480 tests for different changenodes
478 481
479 482 Keywords should not be expanded in filelog
480 483
481 484 $ hg --config 'extensions.keyword=!' cat c
482 485 $Id$
483 486 tests for different changenodes
484 487
485 488 qpop and move on
486 489
487 490 $ hg qpop
488 491 popping mqtest.diff
489 492 patch queue now empty
490 493
491 494 Copy and show added kwfiles
492 495
493 496 $ hg cp a c
494 497 $ hg kwfiles
495 498 a
496 499 c
497 500
498 501 Commit and show expansion in original and copy
499 502
500 503 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
501 504 c
502 505 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
503 506 overwriting c expanding keywords
504 507 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
505 508 $ cat a c
506 509 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
507 510 do not process $Id:
508 511 xxx $
509 512 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
510 513 do not process $Id:
511 514 xxx $
512 515
513 516 Touch copied c and check its status
514 517
515 518 $ touch c
516 519 $ hg status
517 520
518 521 Copy kwfile to keyword ignored file unexpanding keywords
519 522
520 523 $ hg --verbose copy a i
521 524 copying a to i
522 525 overwriting i shrinking keywords
523 526 $ head -n 1 i
524 527 expand $Id$
525 528 $ hg forget i
526 529 $ rm i
527 530
528 531 Copy ignored file to ignored file: no overwriting
529 532
530 533 $ hg --verbose copy b i
531 534 copying b to i
532 535 $ hg forget i
533 536 $ rm i
534 537
535 538 cp symlink (becomes regular file), and hg copy after
536 539
537 540 $ cp sym i
538 541 $ ls -l i
539 542 -rw-r--r--* (glob)
540 543 $ head -1 i
541 544 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
542 545 $ hg copy --after --verbose sym i
543 546 copying sym to i
544 547 overwriting i shrinking keywords
545 548 $ head -1 i
546 549 expand $Id$
547 550 $ hg forget i
548 551 $ rm i
549 552
550 553 Test different options of hg kwfiles
551 554
552 555 $ hg kwfiles
553 556 a
554 557 c
555 558 $ hg -v kwfiles --ignore
556 559 I b
557 560 I sym
558 561 $ hg kwfiles --all
559 562 K a
560 563 K c
561 564 I b
562 565 I sym
563 566
564 567 Diff specific revision
565 568
566 569 $ hg diff --rev 1
567 570 diff -r ef63ca68695b c
568 571 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
569 572 +++ b/c * (glob)
570 573 @@ -0,0 +1,3 @@
571 574 +expand $Id$
572 575 +do not process $Id:
573 576 +xxx $
574 577
575 578 Status after rollback:
576 579
577 580 $ hg rollback
578 581 rolling back to revision 1 (undo commit)
579 582 $ hg status
580 583 A c
581 584 $ hg update --clean
582 585 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 586
584 587 Custom keywordmaps as argument to kwdemo
585 588
586 589 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
587 590 [extensions]
588 591 keyword =
589 592 [keyword]
590 593 ** =
591 594 b = ignore
592 595 demo.txt =
593 596 i = ignore
594 597 [keywordmaps]
595 598 Xinfo = {author}: {desc}
596 599 $Xinfo: test: hg keyword configuration and expansion example $
597 600
598 601 Configure custom keywordmaps
599 602
600 603 $ cat <<EOF >>$HGRCPATH
601 604 > [keywordmaps]
602 605 > Id = {file} {node|short} {date|rfc822date} {author|user}
603 606 > Xinfo = {author}: {desc}
604 607 > EOF
605 608
606 609 Cat and hg cat files before custom expansion
607 610
608 611 $ cat a b
609 612 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
610 613 do not process $Id:
611 614 xxx $
612 615 ignore $Id$
613 616 $ hg cat sym a b && echo
614 617 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
615 618 do not process $Id:
616 619 xxx $
617 620 ignore $Id$
618 621 a
619 622
620 623 Write custom keyword and prepare multiline commit message
621 624
622 625 $ echo '$Xinfo$' >> a
623 626 $ cat <<EOF >> log
624 627 > firstline
625 628 > secondline
626 629 > EOF
627 630
628 631 Interrupted commit should not change state
629 632
630 633 $ hg commit
631 634 abort: empty commit message
632 635 [255]
633 636 $ hg status
634 637 M a
635 638 ? c
636 639 ? log
637 640
638 641 Commit with multiline message and custom expansion
639 642
640 643 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
641 644 a
642 645 overwriting a expanding keywords
643 646 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
644 647 $ rm log
645 648
646 649 Stat, verify and show custom expansion (firstline)
647 650
648 651 $ hg status
649 652 ? c
650 653 $ hg verify
651 654 checking changesets
652 655 checking manifests
653 656 crosschecking files in changesets and manifests
654 657 checking files
655 658 3 files, 3 changesets, 4 total revisions
656 659 $ cat a b
657 660 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
658 661 do not process $Id:
659 662 xxx $
660 663 $Xinfo: User Name <user@example.com>: firstline $
661 664 ignore $Id$
662 665 $ hg cat sym a b && echo
663 666 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
664 667 do not process $Id:
665 668 xxx $
666 669 $Xinfo: User Name <user@example.com>: firstline $
667 670 ignore $Id$
668 671 a
669 672
670 673 annotate
671 674
672 675 $ hg annotate a
673 676 1: expand $Id$
674 677 1: do not process $Id:
675 678 1: xxx $
676 679 2: $Xinfo$
677 680
678 681 remove with status checks
679 682
680 683 $ hg debugrebuildstate
681 684 $ hg remove a
682 685 $ hg --debug commit -m rma
683 686 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
684 687 $ hg status
685 688 ? c
686 689
687 690 Rollback, revert, and check expansion
688 691
689 692 $ hg rollback
690 693 rolling back to revision 2 (undo commit)
691 694 $ hg status
692 695 R a
693 696 ? c
694 697 $ hg revert --no-backup --rev tip a
695 698 $ cat a
696 699 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
697 700 do not process $Id:
698 701 xxx $
699 702 $Xinfo: User Name <user@example.com>: firstline $
700 703
701 704 Clone to test global and local configurations
702 705
703 706 $ cd ..
704 707
705 708 Expansion in destinaton with global configuration
706 709
707 710 $ hg --quiet clone Test globalconf
708 711 $ cat globalconf/a
709 712 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
710 713 do not process $Id:
711 714 xxx $
712 715 $Xinfo: User Name <user@example.com>: firstline $
713 716
714 717 No expansion in destination with local configuration in origin only
715 718
716 719 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
717 720 $ cat localconf/a
718 721 expand $Id$
719 722 do not process $Id:
720 723 xxx $
721 724 $Xinfo$
722 725
723 726 Clone to test incoming
724 727
725 728 $ hg clone -r1 Test Test-a
726 729 requesting all changes
727 730 adding changesets
728 731 adding manifests
729 732 adding file changes
730 733 added 2 changesets with 3 changes to 3 files
731 734 updating to branch default
732 735 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
733 736 $ cd Test-a
734 737 $ cat <<EOF >> .hg/hgrc
735 738 > [paths]
736 739 > default = ../Test
737 740 > EOF
738 741 $ hg incoming
739 742 comparing with $TESTTMP/Test
740 743 searching for changes
741 744 changeset: 2:bb948857c743
742 745 tag: tip
743 746 user: User Name <user@example.com>
744 747 date: Thu Jan 01 00:00:02 1970 +0000
745 748 summary: firstline
746 749
747 750 Imported patch should not be rejected
748 751
749 752 $ python -c \
750 753 > 'import re; s=re.sub("(Id.*)","\\1 rejecttest",open("a").read()); open("a","wb").write(s);'
751 754 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
752 755 a
753 756 overwriting a expanding keywords
754 757 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
755 758 $ hg export -o ../rejecttest.diff tip
756 759 $ cd ../Test
757 760 $ hg import ../rejecttest.diff
758 761 applying ../rejecttest.diff
759 762 $ cat a b
760 763 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
761 764 do not process $Id: rejecttest
762 765 xxx $
763 766 $Xinfo: User Name <user@example.com>: rejects? $
764 767 ignore $Id$
765 768
766 769 $ hg rollback
767 770 rolling back to revision 2 (undo commit)
768 771 $ hg update --clean
769 772 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
770 773
771 774 kwexpand/kwshrink on selected files
772 775
773 776 $ mkdir x
774 777 $ hg copy a x/a
775 778 $ hg --verbose kwexpand a
776 779 overwriting a expanding keywords
777 780
778 781 kwexpand x/a should abort
779 782
780 783 $ hg --verbose kwexpand x/a
781 784 abort: outstanding uncommitted changes
782 785 [255]
783 786 $ cd x
784 787 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
785 788 x/a
786 789 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
787 790 overwriting x/a expanding keywords
788 791 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
789 792 $ cat a
790 793 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
791 794 do not process $Id:
792 795 xxx $
793 796 $Xinfo: User Name <user@example.com>: xa $
794 797
795 798 kwshrink a inside directory x
796 799
797 800 $ hg --verbose kwshrink a
798 801 overwriting x/a shrinking keywords
799 802 $ cat a
800 803 expand $Id$
801 804 do not process $Id:
802 805 xxx $
803 806 $Xinfo$
804 807 $ cd ..
805 808
806 809 kwexpand nonexistent
807 810
808 811 $ hg kwexpand nonexistent
809 812 nonexistent:* (glob)
810 813
811 814
812 815 hg serve
813 816 - expand with hgweb file
814 817 - no expansion with hgweb annotate/changeset/filediff
815 818 - check errors
816 819
817 820 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
818 821 $ cat hg.pid >> $DAEMON_PIDS
819 822 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/file/tip/a/?style=raw'
820 823 200 Script output follows
821 824
822 825 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
823 826 do not process $Id:
824 827 xxx $
825 828 $Xinfo: User Name <user@example.com>: firstline $
826 829 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/annotate/tip/a/?style=raw'
827 830 200 Script output follows
828 831
829 832
830 833 user@1: expand $Id$
831 834 user@1: do not process $Id:
832 835 user@1: xxx $
833 836 user@2: $Xinfo$
834 837
835 838
836 839
837 840
838 841 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/rev/tip/?style=raw'
839 842 200 Script output follows
840 843
841 844
842 845 # HG changeset patch
843 846 # User User Name <user@example.com>
844 847 # Date 3 0
845 848 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
846 849 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
847 850 xa
848 851
849 852 diff -r bb948857c743 -r b4560182a3f9 x/a
850 853 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
851 854 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
852 855 @@ -0,0 +1,4 @@
853 856 +expand $Id$
854 857 +do not process $Id:
855 858 +xxx $
856 859 +$Xinfo$
857 860
858 861 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/diff/bb948857c743/a?style=raw'
859 862 200 Script output follows
860 863
861 864
862 865 diff -r ef63ca68695b -r bb948857c743 a
863 866 --- a/a Thu Jan 01 00:00:00 1970 +0000
864 867 +++ b/a Thu Jan 01 00:00:02 1970 +0000
865 868 @@ -1,3 +1,4 @@
866 869 expand $Id$
867 870 do not process $Id:
868 871 xxx $
869 872 +$Xinfo$
870 873
871 874
872 875
873 876
874 877 $ cat errors.log
875 878
876 879 Prepare merge and resolve tests
877 880
878 881 $ echo '$Id$' > m
879 882 $ hg add m
880 883 $ hg commit -m 4kw
881 884 $ echo foo >> m
882 885 $ hg commit -m 5foo
883 886
884 887 simplemerge
885 888
886 889 $ hg update 4
887 890 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
888 891 $ echo foo >> m
889 892 $ hg commit -m 6foo
890 893 created new head
891 894 $ hg merge
892 895 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
893 896 (branch merge, don't forget to commit)
894 897 $ hg commit -m simplemerge
895 898 $ cat m
896 899 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
897 900 foo
898 901
899 902 conflict: keyword should stay outside conflict zone
900 903
901 904 $ hg update 4
902 905 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
903 906 $ echo bar >> m
904 907 $ hg commit -m 8bar
905 908 created new head
906 909 $ hg merge
907 910 merging m
908 911 warning: conflicts during merge.
909 912 merging m failed!
910 913 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
911 914 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
912 915 [1]
913 916 $ cat m
914 917 $Id$
915 918 <<<<<<< local
916 919 bar
917 920 =======
918 921 foo
919 922 >>>>>>> other
920 923
921 924 resolve to local
922 925
923 926 $ HGMERGE=internal:local hg resolve -a
924 927 $ hg commit -m localresolve
925 928 $ cat m
926 929 $Id: m 41efa6d38e9b Thu, 01 Jan 1970 00:00:00 +0000 test $
927 930 bar
928 931
929 932 Test restricted mode with transplant -b
930 933
931 934 $ hg update 6
932 935 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
933 936 $ hg branch foo
934 937 marked working directory as branch foo
935 938 $ mv a a.bak
936 939 $ echo foobranch > a
937 940 $ cat a.bak >> a
938 941 $ rm a.bak
939 942 $ hg commit -m 9foobranch
940 943 $ hg update default
941 944 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
942 945 $ hg -y transplant -b foo tip
943 946 applying 4aa30d025d50
944 947 4aa30d025d50 transplanted to 5a4da427c162
945 948
946 949 Expansion in changeset but not in file
947 950
948 951 $ hg tip -p
949 952 changeset: 11:5a4da427c162
950 953 tag: tip
951 954 parent: 9:41efa6d38e9b
952 955 user: test
953 956 date: Thu Jan 01 00:00:00 1970 +0000
954 957 summary: 9foobranch
955 958
956 959 diff -r 41efa6d38e9b -r 5a4da427c162 a
957 960 --- a/a Thu Jan 01 00:00:00 1970 +0000
958 961 +++ b/a Thu Jan 01 00:00:00 1970 +0000
959 962 @@ -1,3 +1,4 @@
960 963 +foobranch
961 964 expand $Id$
962 965 do not process $Id:
963 966 xxx $
964 967
965 968 $ head -n 2 a
966 969 foobranch
967 970 expand $Id: a 5a4da427c162 Thu, 01 Jan 1970 00:00:00 +0000 test $
968 971
969 972 Turn off expansion
970 973
971 974 $ hg -q rollback
972 975 $ hg -q update -C
973 976
974 977 kwshrink with unknown file u
975 978
976 979 $ cp a u
977 980 $ hg --verbose kwshrink
978 981 overwriting a shrinking keywords
979 982 overwriting m shrinking keywords
980 983 overwriting x/a shrinking keywords
981 984
982 985 Keywords shrunk in working directory, but not yet disabled
983 986 - cat shows unexpanded keywords
984 987 - hg cat shows expanded keywords
985 988
986 989 $ cat a b
987 990 expand $Id$
988 991 do not process $Id:
989 992 xxx $
990 993 $Xinfo$
991 994 ignore $Id$
992 995 $ hg cat sym a b && echo
993 996 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
994 997 do not process $Id:
995 998 xxx $
996 999 $Xinfo: User Name <user@example.com>: firstline $
997 1000 ignore $Id$
998 1001 a
999 1002
1000 1003 Now disable keyword expansion
1001 1004
1002 1005 $ rm "$HGRCPATH"
1003 1006 $ cat a b
1004 1007 expand $Id$
1005 1008 do not process $Id:
1006 1009 xxx $
1007 1010 $Xinfo$
1008 1011 ignore $Id$
1009 1012 $ hg cat sym a b && echo
1010 1013 expand $Id$
1011 1014 do not process $Id:
1012 1015 xxx $
1013 1016 $Xinfo$
1014 1017 ignore $Id$
1015 1018 a
General Comments 0
You need to be logged in to leave comments. Login now