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