##// END OF EJS Templates
keyword: handle resolve to either parent...
Christian Ebert -
r23622:cb9d8454 default
parent child Browse files
Show More
@@ -1,743 +1,752 b''
1 1 # keyword.py - $Keyword$ expansion for Mercurial
2 2 #
3 3 # Copyright 2007-2014 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 Distributed SCM
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
57 57 The more specific you are in your filename patterns the less you
58 58 lose speed in huge repositories.
59 59
60 60 For [keywordmaps] template mapping and expansion demonstration and
61 61 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
62 62 available templates and filters.
63 63
64 64 Three additional date template filters are provided:
65 65
66 66 :``utcdate``: "2006/09/18 15:13:13"
67 67 :``svnutcdate``: "2006-09-18 15:13:13Z"
68 68 :``svnisodate``: "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
69 69
70 70 The default template mappings (view with :hg:`kwdemo -d`) can be
71 71 replaced with customized keywords and templates. Again, run
72 72 :hg:`kwdemo` to control the results of your configuration changes.
73 73
74 74 Before changing/disabling active keywords, you must run :hg:`kwshrink`
75 75 to avoid storing expanded keywords in the change 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, context, cmdutil, dispatch, filelog, extensions
86 86 from mercurial import localrepo, match, patch, templatefilters, templater, util
87 87 from mercurial import scmutil, pathutil
88 88 from mercurial.hgweb import webcommands
89 89 from mercurial.i18n import _
90 90 import os, re, tempfile
91 91
92 92 cmdtable = {}
93 93 command = cmdutil.command(cmdtable)
94 94 testedwith = 'internal'
95 95
96 96 # hg commands that do not act on keywords
97 97 nokwcommands = ('add addremove annotate bundle export grep incoming init log'
98 98 ' outgoing push tip verify convert email glog')
99 99
100 100 # hg commands that trigger expansion only when writing to working dir,
101 101 # not when reading filelog, and unexpand when reading from working dir
102 102 restricted = ('merge kwexpand kwshrink record qrecord resolve transplant'
103 103 ' unshelve rebase graft backout histedit fetch')
104 104
105 105 # names of extensions using dorecord
106 106 recordextensions = 'record'
107 107
108 108 colortable = {
109 109 'kwfiles.enabled': 'green bold',
110 110 'kwfiles.deleted': 'cyan bold underline',
111 111 'kwfiles.enabledunknown': 'green',
112 112 'kwfiles.ignored': 'bold',
113 113 'kwfiles.ignoredunknown': 'none'
114 114 }
115 115
116 116 # date like in cvs' $Date
117 117 def utcdate(text):
118 118 ''':utcdate: Date. Returns a UTC-date in this format: "2009/08/18 11:00:13".
119 119 '''
120 120 return util.datestr((util.parsedate(text)[0], 0), '%Y/%m/%d %H:%M:%S')
121 121 # date like in svn's $Date
122 122 def svnisodate(text):
123 123 ''':svnisodate: Date. Returns a date in this format: "2009-08-18 13:00:13
124 124 +0200 (Tue, 18 Aug 2009)".
125 125 '''
126 126 return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
127 127 # date like in svn's $Id
128 128 def svnutcdate(text):
129 129 ''':svnutcdate: Date. Returns a UTC-date in this format: "2009-08-18
130 130 11:00:13Z".
131 131 '''
132 132 return util.datestr((util.parsedate(text)[0], 0), '%Y-%m-%d %H:%M:%SZ')
133 133
134 134 templatefilters.filters.update({'utcdate': utcdate,
135 135 'svnisodate': svnisodate,
136 136 'svnutcdate': svnutcdate})
137 137
138 138 # make keyword tools accessible
139 139 kwtools = {'templater': None, 'hgcmd': ''}
140 140
141 141 def _defaultkwmaps(ui):
142 142 '''Returns default keywordmaps according to keywordset configuration.'''
143 143 templates = {
144 144 'Revision': '{node|short}',
145 145 'Author': '{author|user}',
146 146 }
147 147 kwsets = ({
148 148 'Date': '{date|utcdate}',
149 149 'RCSfile': '{file|basename},v',
150 150 'RCSFile': '{file|basename},v', # kept for backwards compatibility
151 151 # with hg-keyword
152 152 'Source': '{root}/{file},v',
153 153 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
154 154 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
155 155 }, {
156 156 'Date': '{date|svnisodate}',
157 157 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
158 158 'LastChangedRevision': '{node|short}',
159 159 'LastChangedBy': '{author|user}',
160 160 'LastChangedDate': '{date|svnisodate}',
161 161 })
162 162 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
163 163 return templates
164 164
165 165 def _shrinktext(text, subfunc):
166 166 '''Helper for keyword expansion removal in text.
167 167 Depending on subfunc also returns number of substitutions.'''
168 168 return subfunc(r'$\1$', text)
169 169
170 170 def _preselect(wstatus, changed):
171 171 '''Retrieves modified and added files from a working directory state
172 172 and returns the subset of each contained in given changed files
173 173 retrieved from a change context.'''
174 174 modified = [f for f in wstatus.modified if f in changed]
175 175 added = [f for f in wstatus.added if f in changed]
176 176 return modified, added
177 177
178 178
179 179 class kwtemplater(object):
180 180 '''
181 181 Sets up keyword templates, corresponding keyword regex, and
182 182 provides keyword substitution functions.
183 183 '''
184 184
185 185 def __init__(self, ui, repo, inc, exc):
186 186 self.ui = ui
187 187 self.repo = repo
188 188 self.match = match.match(repo.root, '', [], inc, exc)
189 189 self.restrict = kwtools['hgcmd'] in restricted.split()
190 190 self.postcommit = False
191 191
192 192 kwmaps = self.ui.configitems('keywordmaps')
193 193 if kwmaps: # override default templates
194 194 self.templates = dict((k, templater.parsestring(v, False))
195 195 for k, v in kwmaps)
196 196 else:
197 197 self.templates = _defaultkwmaps(self.ui)
198 198
199 199 @util.propertycache
200 200 def escape(self):
201 201 '''Returns bar-separated and escaped keywords.'''
202 202 return '|'.join(map(re.escape, self.templates.keys()))
203 203
204 204 @util.propertycache
205 205 def rekw(self):
206 206 '''Returns regex for unexpanded keywords.'''
207 207 return re.compile(r'\$(%s)\$' % self.escape)
208 208
209 209 @util.propertycache
210 210 def rekwexp(self):
211 211 '''Returns regex for expanded keywords.'''
212 212 return re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape)
213 213
214 214 def substitute(self, data, path, ctx, subfunc):
215 215 '''Replaces keywords in data with expanded template.'''
216 216 def kwsub(mobj):
217 217 kw = mobj.group(1)
218 218 ct = cmdutil.changeset_templater(self.ui, self.repo, False, None,
219 219 self.templates[kw], '', False)
220 220 self.ui.pushbuffer()
221 221 ct.show(ctx, root=self.repo.root, file=path)
222 222 ekw = templatefilters.firstline(self.ui.popbuffer())
223 223 return '$%s: %s $' % (kw, ekw)
224 224 return subfunc(kwsub, data)
225 225
226 226 def linkctx(self, path, fileid):
227 227 '''Similar to filelog.linkrev, but returns a changectx.'''
228 228 return self.repo.filectx(path, fileid=fileid).changectx()
229 229
230 230 def expand(self, path, node, data):
231 231 '''Returns data with keywords expanded.'''
232 232 if not self.restrict and self.match(path) and not util.binary(data):
233 233 ctx = self.linkctx(path, node)
234 234 return self.substitute(data, path, ctx, self.rekw.sub)
235 235 return data
236 236
237 237 def iskwfile(self, cand, ctx):
238 238 '''Returns subset of candidates which are configured for keyword
239 239 expansion but are not symbolic links.'''
240 240 return [f for f in cand if self.match(f) and 'l' not in ctx.flags(f)]
241 241
242 242 def overwrite(self, ctx, candidates, lookup, expand, rekw=False):
243 243 '''Overwrites selected files expanding/shrinking keywords.'''
244 244 if self.restrict or lookup or self.postcommit: # exclude kw_copy
245 245 candidates = self.iskwfile(candidates, ctx)
246 246 if not candidates:
247 247 return
248 248 kwcmd = self.restrict and lookup # kwexpand/kwshrink
249 249 if self.restrict or expand and lookup:
250 250 mf = ctx.manifest()
251 251 if self.restrict or rekw:
252 252 re_kw = self.rekw
253 253 else:
254 254 re_kw = self.rekwexp
255 255 if expand:
256 256 msg = _('overwriting %s expanding keywords\n')
257 257 else:
258 258 msg = _('overwriting %s shrinking keywords\n')
259 259 for f in candidates:
260 260 if self.restrict:
261 261 data = self.repo.file(f).read(mf[f])
262 262 else:
263 263 data = self.repo.wread(f)
264 264 if util.binary(data):
265 265 continue
266 266 if expand:
267 parents = ctx.parents()
267 268 if lookup:
268 269 ctx = self.linkctx(f, mf[f])
270 elif self.restrict and len(parents) > 1:
271 # merge commit
272 # in case of conflict f is in modified state during
273 # merge, even if f does not differ from f in parent
274 for p in parents:
275 if f in p and not p[f].cmp(ctx[f]):
276 ctx = p[f].changectx()
277 break
269 278 data, found = self.substitute(data, f, ctx, re_kw.subn)
270 279 elif self.restrict:
271 280 found = re_kw.search(data)
272 281 else:
273 282 data, found = _shrinktext(data, re_kw.subn)
274 283 if found:
275 284 self.ui.note(msg % f)
276 285 fp = self.repo.wopener(f, "wb", atomictemp=True)
277 286 fp.write(data)
278 287 fp.close()
279 288 if kwcmd:
280 289 self.repo.dirstate.normal(f)
281 290 elif self.postcommit:
282 291 self.repo.dirstate.normallookup(f)
283 292
284 293 def shrink(self, fname, text):
285 294 '''Returns text with all keyword substitutions removed.'''
286 295 if self.match(fname) and not util.binary(text):
287 296 return _shrinktext(text, self.rekwexp.sub)
288 297 return text
289 298
290 299 def shrinklines(self, fname, lines):
291 300 '''Returns lines with keyword substitutions removed.'''
292 301 if self.match(fname):
293 302 text = ''.join(lines)
294 303 if not util.binary(text):
295 304 return _shrinktext(text, self.rekwexp.sub).splitlines(True)
296 305 return lines
297 306
298 307 def wread(self, fname, data):
299 308 '''If in restricted mode returns data read from wdir with
300 309 keyword substitutions removed.'''
301 310 if self.restrict:
302 311 return self.shrink(fname, data)
303 312 return data
304 313
305 314 class kwfilelog(filelog.filelog):
306 315 '''
307 316 Subclass of filelog to hook into its read, add, cmp methods.
308 317 Keywords are "stored" unexpanded, and processed on reading.
309 318 '''
310 319 def __init__(self, opener, kwt, path):
311 320 super(kwfilelog, self).__init__(opener, path)
312 321 self.kwt = kwt
313 322 self.path = path
314 323
315 324 def read(self, node):
316 325 '''Expands keywords when reading filelog.'''
317 326 data = super(kwfilelog, self).read(node)
318 327 if self.renamed(node):
319 328 return data
320 329 return self.kwt.expand(self.path, node, data)
321 330
322 331 def add(self, text, meta, tr, link, p1=None, p2=None):
323 332 '''Removes keyword substitutions when adding to filelog.'''
324 333 text = self.kwt.shrink(self.path, text)
325 334 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
326 335
327 336 def cmp(self, node, text):
328 337 '''Removes keyword substitutions for comparison.'''
329 338 text = self.kwt.shrink(self.path, text)
330 339 return super(kwfilelog, self).cmp(node, text)
331 340
332 341 def _status(ui, repo, wctx, kwt, *pats, **opts):
333 342 '''Bails out if [keyword] configuration is not active.
334 343 Returns status of working directory.'''
335 344 if kwt:
336 345 return repo.status(match=scmutil.match(wctx, pats, opts), clean=True,
337 346 unknown=opts.get('unknown') or opts.get('all'))
338 347 if ui.configitems('keyword'):
339 348 raise util.Abort(_('[keyword] patterns cannot match'))
340 349 raise util.Abort(_('no [keyword] patterns configured'))
341 350
342 351 def _kwfwrite(ui, repo, expand, *pats, **opts):
343 352 '''Selects files and passes them to kwtemplater.overwrite.'''
344 353 wctx = repo[None]
345 354 if len(wctx.parents()) > 1:
346 355 raise util.Abort(_('outstanding uncommitted merge'))
347 356 kwt = kwtools['templater']
348 357 wlock = repo.wlock()
349 358 try:
350 359 status = _status(ui, repo, wctx, kwt, *pats, **opts)
351 360 if status.modified or status.added or status.removed or status.deleted:
352 361 raise util.Abort(_('outstanding uncommitted changes'))
353 362 kwt.overwrite(wctx, status.clean, True, expand)
354 363 finally:
355 364 wlock.release()
356 365
357 366 @command('kwdemo',
358 367 [('d', 'default', None, _('show default keyword template maps')),
359 368 ('f', 'rcfile', '',
360 369 _('read maps from rcfile'), _('FILE'))],
361 370 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...'),
362 371 optionalrepo=True)
363 372 def demo(ui, repo, *args, **opts):
364 373 '''print [keywordmaps] configuration and an expansion example
365 374
366 375 Show current, custom, or default keyword template maps and their
367 376 expansions.
368 377
369 378 Extend the current configuration by specifying maps as arguments
370 379 and using -f/--rcfile to source an external hgrc file.
371 380
372 381 Use -d/--default to disable current configuration.
373 382
374 383 See :hg:`help templates` for information on templates and filters.
375 384 '''
376 385 def demoitems(section, items):
377 386 ui.write('[%s]\n' % section)
378 387 for k, v in sorted(items):
379 388 ui.write('%s = %s\n' % (k, v))
380 389
381 390 fn = 'demo.txt'
382 391 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
383 392 ui.note(_('creating temporary repository at %s\n') % tmpdir)
384 393 repo = localrepo.localrepository(repo.baseui, tmpdir, True)
385 394 ui.setconfig('keyword', fn, '', 'keyword')
386 395 svn = ui.configbool('keywordset', 'svn')
387 396 # explicitly set keywordset for demo output
388 397 ui.setconfig('keywordset', 'svn', svn, 'keyword')
389 398
390 399 uikwmaps = ui.configitems('keywordmaps')
391 400 if args or opts.get('rcfile'):
392 401 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
393 402 if uikwmaps:
394 403 ui.status(_('\textending current template maps\n'))
395 404 if opts.get('default') or not uikwmaps:
396 405 if svn:
397 406 ui.status(_('\toverriding default svn keywordset\n'))
398 407 else:
399 408 ui.status(_('\toverriding default cvs keywordset\n'))
400 409 if opts.get('rcfile'):
401 410 ui.readconfig(opts.get('rcfile'))
402 411 if args:
403 412 # simulate hgrc parsing
404 413 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
405 414 fp = repo.opener('hgrc', 'w')
406 415 fp.writelines(rcmaps)
407 416 fp.close()
408 417 ui.readconfig(repo.join('hgrc'))
409 418 kwmaps = dict(ui.configitems('keywordmaps'))
410 419 elif opts.get('default'):
411 420 if svn:
412 421 ui.status(_('\n\tconfiguration using default svn keywordset\n'))
413 422 else:
414 423 ui.status(_('\n\tconfiguration using default cvs keywordset\n'))
415 424 kwmaps = _defaultkwmaps(ui)
416 425 if uikwmaps:
417 426 ui.status(_('\tdisabling current template maps\n'))
418 427 for k, v in kwmaps.iteritems():
419 428 ui.setconfig('keywordmaps', k, v, 'keyword')
420 429 else:
421 430 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
422 431 if uikwmaps:
423 432 kwmaps = dict(uikwmaps)
424 433 else:
425 434 kwmaps = _defaultkwmaps(ui)
426 435
427 436 uisetup(ui)
428 437 reposetup(ui, repo)
429 438 ui.write('[extensions]\nkeyword =\n')
430 439 demoitems('keyword', ui.configitems('keyword'))
431 440 demoitems('keywordset', ui.configitems('keywordset'))
432 441 demoitems('keywordmaps', kwmaps.iteritems())
433 442 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
434 443 repo.wopener.write(fn, keywords)
435 444 repo[None].add([fn])
436 445 ui.note(_('\nkeywords written to %s:\n') % fn)
437 446 ui.note(keywords)
438 447 wlock = repo.wlock()
439 448 try:
440 449 repo.dirstate.setbranch('demobranch')
441 450 finally:
442 451 wlock.release()
443 452 for name, cmd in ui.configitems('hooks'):
444 453 if name.split('.', 1)[0].find('commit') > -1:
445 454 repo.ui.setconfig('hooks', name, '', 'keyword')
446 455 msg = _('hg keyword configuration and expansion example')
447 456 ui.note(("hg ci -m '%s'\n" % msg))
448 457 repo.commit(text=msg)
449 458 ui.status(_('\n\tkeywords expanded\n'))
450 459 ui.write(repo.wread(fn))
451 460 for root, dirs, files in os.walk(tmpdir, topdown=False):
452 461 for f in files:
453 462 util.unlink(os.path.join(root, f))
454 463 for d in dirs:
455 464 os.rmdir(os.path.join(root, d))
456 465 os.rmdir(tmpdir)
457 466
458 467 @command('kwexpand',
459 468 commands.walkopts,
460 469 _('hg kwexpand [OPTION]... [FILE]...'),
461 470 inferrepo=True)
462 471 def expand(ui, repo, *pats, **opts):
463 472 '''expand keywords in the working directory
464 473
465 474 Run after (re)enabling keyword expansion.
466 475
467 476 kwexpand refuses to run if given files contain local changes.
468 477 '''
469 478 # 3rd argument sets expansion to True
470 479 _kwfwrite(ui, repo, True, *pats, **opts)
471 480
472 481 @command('kwfiles',
473 482 [('A', 'all', None, _('show keyword status flags of all files')),
474 483 ('i', 'ignore', None, _('show files excluded from expansion')),
475 484 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
476 485 ] + commands.walkopts,
477 486 _('hg kwfiles [OPTION]... [FILE]...'),
478 487 inferrepo=True)
479 488 def files(ui, repo, *pats, **opts):
480 489 '''show files configured for keyword expansion
481 490
482 491 List which files in the working directory are matched by the
483 492 [keyword] configuration patterns.
484 493
485 494 Useful to prevent inadvertent keyword expansion and to speed up
486 495 execution by including only files that are actual candidates for
487 496 expansion.
488 497
489 498 See :hg:`help keyword` on how to construct patterns both for
490 499 inclusion and exclusion of files.
491 500
492 501 With -A/--all and -v/--verbose the codes used to show the status
493 502 of files are::
494 503
495 504 K = keyword expansion candidate
496 505 k = keyword expansion candidate (not tracked)
497 506 I = ignored
498 507 i = ignored (not tracked)
499 508 '''
500 509 kwt = kwtools['templater']
501 510 wctx = repo[None]
502 511 status = _status(ui, repo, wctx, kwt, *pats, **opts)
503 512 cwd = pats and repo.getcwd() or ''
504 513 files = []
505 514 if not opts.get('unknown') or opts.get('all'):
506 515 files = sorted(status.modified + status.added + status.clean)
507 516 kwfiles = kwt.iskwfile(files, wctx)
508 517 kwdeleted = kwt.iskwfile(status.deleted, wctx)
509 518 kwunknown = kwt.iskwfile(status.unknown, wctx)
510 519 if not opts.get('ignore') or opts.get('all'):
511 520 showfiles = kwfiles, kwdeleted, kwunknown
512 521 else:
513 522 showfiles = [], [], []
514 523 if opts.get('all') or opts.get('ignore'):
515 524 showfiles += ([f for f in files if f not in kwfiles],
516 525 [f for f in status.unknown if f not in kwunknown])
517 526 kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split()
518 527 kwstates = zip(kwlabels, 'K!kIi', showfiles)
519 528 fm = ui.formatter('kwfiles', opts)
520 529 fmt = '%.0s%s\n'
521 530 if opts.get('all') or ui.verbose:
522 531 fmt = '%s %s\n'
523 532 for kwstate, char, filenames in kwstates:
524 533 label = 'kwfiles.' + kwstate
525 534 for f in filenames:
526 535 fm.startitem()
527 536 fm.write('kwstatus path', fmt, char,
528 537 repo.pathto(f, cwd), label=label)
529 538 fm.end()
530 539
531 540 @command('kwshrink',
532 541 commands.walkopts,
533 542 _('hg kwshrink [OPTION]... [FILE]...'),
534 543 inferrepo=True)
535 544 def shrink(ui, repo, *pats, **opts):
536 545 '''revert expanded keywords in the working directory
537 546
538 547 Must be run before changing/disabling active keywords.
539 548
540 549 kwshrink refuses to run if given files contain local changes.
541 550 '''
542 551 # 3rd argument sets expansion to False
543 552 _kwfwrite(ui, repo, False, *pats, **opts)
544 553
545 554
546 555 def uisetup(ui):
547 556 ''' Monkeypatches dispatch._parse to retrieve user command.'''
548 557
549 558 def kwdispatch_parse(orig, ui, args):
550 559 '''Monkeypatch dispatch._parse to obtain running hg command.'''
551 560 cmd, func, args, options, cmdoptions = orig(ui, args)
552 561 kwtools['hgcmd'] = cmd
553 562 return cmd, func, args, options, cmdoptions
554 563
555 564 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
556 565
557 566 def reposetup(ui, repo):
558 567 '''Sets up repo as kwrepo for keyword substitution.
559 568 Overrides file method to return kwfilelog instead of filelog
560 569 if file matches user configuration.
561 570 Wraps commit to overwrite configured files with updated
562 571 keyword substitutions.
563 572 Monkeypatches patch and webcommands.'''
564 573
565 574 try:
566 575 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
567 576 or '.hg' in util.splitpath(repo.root)
568 577 or repo._url.startswith('bundle:')):
569 578 return
570 579 except AttributeError:
571 580 pass
572 581
573 582 inc, exc = [], ['.hg*']
574 583 for pat, opt in ui.configitems('keyword'):
575 584 if opt != 'ignore':
576 585 inc.append(pat)
577 586 else:
578 587 exc.append(pat)
579 588 if not inc:
580 589 return
581 590
582 591 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
583 592
584 593 class kwrepo(repo.__class__):
585 594 def file(self, f):
586 595 if f[0] == '/':
587 596 f = f[1:]
588 597 return kwfilelog(self.sopener, kwt, f)
589 598
590 599 def wread(self, filename):
591 600 data = super(kwrepo, self).wread(filename)
592 601 return kwt.wread(filename, data)
593 602
594 603 def commit(self, *args, **opts):
595 604 # use custom commitctx for user commands
596 605 # other extensions can still wrap repo.commitctx directly
597 606 self.commitctx = self.kwcommitctx
598 607 try:
599 608 return super(kwrepo, self).commit(*args, **opts)
600 609 finally:
601 610 del self.commitctx
602 611
603 612 def kwcommitctx(self, ctx, error=False):
604 613 n = super(kwrepo, self).commitctx(ctx, error)
605 614 # no lock needed, only called from repo.commit() which already locks
606 615 if not kwt.postcommit:
607 616 restrict = kwt.restrict
608 617 kwt.restrict = True
609 618 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
610 619 False, True)
611 620 kwt.restrict = restrict
612 621 return n
613 622
614 623 def rollback(self, dryrun=False, force=False):
615 624 wlock = self.wlock()
616 625 try:
617 626 if not dryrun:
618 627 changed = self['.'].files()
619 628 ret = super(kwrepo, self).rollback(dryrun, force)
620 629 if not dryrun:
621 630 ctx = self['.']
622 631 modified, added = _preselect(ctx.status(), changed)
623 632 kwt.overwrite(ctx, modified, True, True)
624 633 kwt.overwrite(ctx, added, True, False)
625 634 return ret
626 635 finally:
627 636 wlock.release()
628 637
629 638 # monkeypatches
630 639 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
631 640 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
632 641 rejects or conflicts due to expanded keywords in working dir.'''
633 642 orig(self, ui, gp, backend, store, eolmode)
634 643 # shrink keywords read from working dir
635 644 self.lines = kwt.shrinklines(self.fname, self.lines)
636 645
637 646 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
638 647 opts=None, prefix=''):
639 648 '''Monkeypatch patch.diff to avoid expansion.'''
640 649 kwt.restrict = True
641 650 return orig(repo, node1, node2, match, changes, opts, prefix)
642 651
643 652 def kwweb_skip(orig, web, req, tmpl):
644 653 '''Wraps webcommands.x turning off keyword expansion.'''
645 654 kwt.match = util.never
646 655 return orig(web, req, tmpl)
647 656
648 657 def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts):
649 658 '''Wraps cmdutil.amend expanding keywords after amend.'''
650 659 wlock = repo.wlock()
651 660 try:
652 661 kwt.postcommit = True
653 662 newid = orig(ui, repo, commitfunc, old, extra, pats, opts)
654 663 if newid != old.node():
655 664 ctx = repo[newid]
656 665 kwt.restrict = True
657 666 kwt.overwrite(ctx, ctx.files(), False, True)
658 667 kwt.restrict = False
659 668 return newid
660 669 finally:
661 670 wlock.release()
662 671
663 672 def kw_copy(orig, ui, repo, pats, opts, rename=False):
664 673 '''Wraps cmdutil.copy so that copy/rename destinations do not
665 674 contain expanded keywords.
666 675 Note that the source of a regular file destination may also be a
667 676 symlink:
668 677 hg cp sym x -> x is symlink
669 678 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords)
670 679 For the latter we have to follow the symlink to find out whether its
671 680 target is configured for expansion and we therefore must unexpand the
672 681 keywords in the destination.'''
673 682 wlock = repo.wlock()
674 683 try:
675 684 orig(ui, repo, pats, opts, rename)
676 685 if opts.get('dry_run'):
677 686 return
678 687 wctx = repo[None]
679 688 cwd = repo.getcwd()
680 689
681 690 def haskwsource(dest):
682 691 '''Returns true if dest is a regular file and configured for
683 692 expansion or a symlink which points to a file configured for
684 693 expansion. '''
685 694 source = repo.dirstate.copied(dest)
686 695 if 'l' in wctx.flags(source):
687 696 source = pathutil.canonpath(repo.root, cwd,
688 697 os.path.realpath(source))
689 698 return kwt.match(source)
690 699
691 700 candidates = [f for f in repo.dirstate.copies() if
692 701 'l' not in wctx.flags(f) and haskwsource(f)]
693 702 kwt.overwrite(wctx, candidates, False, False)
694 703 finally:
695 704 wlock.release()
696 705
697 706 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
698 707 '''Wraps record.dorecord expanding keywords after recording.'''
699 708 wlock = repo.wlock()
700 709 try:
701 710 # record returns 0 even when nothing has changed
702 711 # therefore compare nodes before and after
703 712 kwt.postcommit = True
704 713 ctx = repo['.']
705 714 wstatus = ctx.status()
706 715 ret = orig(ui, repo, commitfunc, *pats, **opts)
707 716 recctx = repo['.']
708 717 if ctx != recctx:
709 718 modified, added = _preselect(wstatus, recctx.files())
710 719 kwt.restrict = False
711 720 kwt.overwrite(recctx, modified, False, True)
712 721 kwt.overwrite(recctx, added, False, True, True)
713 722 kwt.restrict = True
714 723 return ret
715 724 finally:
716 725 wlock.release()
717 726
718 727 def kwfilectx_cmp(orig, self, fctx):
719 728 # keyword affects data size, comparing wdir and filelog size does
720 729 # not make sense
721 730 if (fctx._filerev is None and
722 731 (self._repo._encodefilterpats or
723 732 kwt.match(fctx.path()) and 'l' not in fctx.flags() or
724 733 self.size() - 4 == fctx.size()) or
725 734 self.size() == fctx.size()):
726 735 return self._filelog.cmp(self._filenode, fctx.data())
727 736 return True
728 737
729 738 extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp)
730 739 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
731 740 extensions.wrapfunction(patch, 'diff', kw_diff)
732 741 extensions.wrapfunction(cmdutil, 'amend', kw_amend)
733 742 extensions.wrapfunction(cmdutil, 'copy', kw_copy)
734 743 for c in 'annotate changeset rev filediff diff'.split():
735 744 extensions.wrapfunction(webcommands, c, kwweb_skip)
736 745 for name in recordextensions.split():
737 746 try:
738 747 record = extensions.find(name)
739 748 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
740 749 except KeyError:
741 750 pass
742 751
743 752 repo.__class__ = kwrepo
@@ -1,1318 +1,1318 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 hide outer repo
13 13 $ hg init
14 14
15 15 Run kwdemo before [keyword] files are set up
16 16 as it would succeed without uisetup otherwise
17 17
18 18 $ hg --quiet kwdemo
19 19 [extensions]
20 20 keyword =
21 21 [keyword]
22 22 demo.txt =
23 23 [keywordset]
24 24 svn = False
25 25 [keywordmaps]
26 26 Author = {author|user}
27 27 Date = {date|utcdate}
28 28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
29 29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
30 30 RCSFile = {file|basename},v
31 31 RCSfile = {file|basename},v
32 32 Revision = {node|short}
33 33 Source = {root}/{file},v
34 34 $Author: test $
35 35 $Date: ????/??/?? ??:??:?? $ (glob)
36 36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
38 38 $RCSFile: demo.txt,v $
39 39 $RCSfile: demo.txt,v $
40 40 $Revision: ???????????? $ (glob)
41 41 $Source: */demo.txt,v $ (glob)
42 42
43 43 $ hg --quiet kwdemo "Branch = {branches}"
44 44 [extensions]
45 45 keyword =
46 46 [keyword]
47 47 demo.txt =
48 48 [keywordset]
49 49 svn = False
50 50 [keywordmaps]
51 51 Branch = {branches}
52 52 $Branch: demobranch $
53 53
54 54 $ cat <<EOF >> $HGRCPATH
55 55 > [keyword]
56 56 > ** =
57 57 > b = ignore
58 58 > i = ignore
59 59 > [hooks]
60 60 > EOF
61 61 $ cp $HGRCPATH $HGRCPATH.nohooks
62 62 > cat <<EOF >> $HGRCPATH
63 63 > commit=
64 64 > commit.test=cp a hooktest
65 65 > EOF
66 66
67 67 $ hg init Test-bndl
68 68 $ cd Test-bndl
69 69
70 70 kwshrink should exit silently in empty/invalid repo
71 71
72 72 $ hg kwshrink
73 73
74 74 Symlinks cannot be created on Windows.
75 75 A bundle to test this was made with:
76 76 hg init t
77 77 cd t
78 78 echo a > a
79 79 ln -s a sym
80 80 hg add sym
81 81 hg ci -m addsym -u mercurial
82 82 hg bundle --base null ../test-keyword.hg
83 83
84 84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
85 85 pulling from *test-keyword.hg (glob)
86 86 requesting all changes
87 87 adding changesets
88 88 adding manifests
89 89 adding file changes
90 90 added 1 changesets with 1 changes to 1 files
91 91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 92
93 93 $ echo 'expand $Id$' > a
94 94 $ echo 'do not process $Id:' >> a
95 95 $ echo 'xxx $' >> a
96 96 $ echo 'ignore $Id$' > b
97 97
98 98 Output files as they were created
99 99
100 100 $ cat a b
101 101 expand $Id$
102 102 do not process $Id:
103 103 xxx $
104 104 ignore $Id$
105 105
106 106 no kwfiles
107 107
108 108 $ hg kwfiles
109 109
110 110 untracked candidates
111 111
112 112 $ hg -v kwfiles --unknown
113 113 k a
114 114
115 115 Add files and check status
116 116
117 117 $ hg addremove
118 118 adding a
119 119 adding b
120 120 $ hg status
121 121 A a
122 122 A b
123 123
124 124
125 125 Default keyword expansion including commit hook
126 126 Interrupted commit should not change state or run commit hook
127 127
128 128 $ hg --debug commit
129 129 abort: empty commit message
130 130 [255]
131 131 $ hg status
132 132 A a
133 133 A b
134 134
135 135 Commit with several checks
136 136
137 137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
138 138 a
139 139 b
140 140 overwriting a expanding keywords
141 141 running hook commit.test: cp a hooktest
142 142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
143 143 $ hg status
144 144 ? hooktest
145 145 $ hg debugrebuildstate
146 146 $ hg --quiet identify
147 147 ef63ca68695b
148 148
149 149 cat files in working directory with keywords expanded
150 150
151 151 $ cat a b
152 152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
153 153 do not process $Id:
154 154 xxx $
155 155 ignore $Id$
156 156
157 157 hg cat files and symlink, no expansion
158 158
159 159 $ hg cat sym a b && echo
160 160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
161 161 do not process $Id:
162 162 xxx $
163 163 ignore $Id$
164 164 a
165 165
166 166 $ diff a hooktest
167 167
168 168 $ cp $HGRCPATH.nohooks $HGRCPATH
169 169 $ rm hooktest
170 170
171 171 hg status of kw-ignored binary file starting with '\1\n'
172 172
173 173 >>> open("i", "wb").write("\1\nfoo")
174 174 $ hg -q commit -Am metasep i
175 175 $ hg status
176 176 >>> open("i", "wb").write("\1\nbar")
177 177 $ hg status
178 178 M i
179 179 $ hg -q commit -m "modify metasep" i
180 180 $ hg status --rev 2:3
181 181 M i
182 182 $ touch empty
183 183 $ hg -q commit -A -m "another file"
184 184 $ hg status -A --rev 3:4 i
185 185 C i
186 186
187 187 $ hg -q strip --no-backup 2
188 188
189 189 Test hook execution
190 190
191 191 bundle
192 192
193 193 $ hg bundle --base null ../kw.hg
194 194 2 changesets found
195 195 $ cd ..
196 196 $ hg init Test
197 197 $ cd Test
198 198
199 199 Notify on pull to check whether keywords stay as is in email
200 200 ie. if patch.diff wrapper acts as it should
201 201
202 202 $ cat <<EOF >> $HGRCPATH
203 203 > [hooks]
204 204 > incoming.notify = python:hgext.notify.hook
205 205 > [notify]
206 206 > sources = pull
207 207 > diffstat = False
208 208 > maxsubject = 15
209 209 > [reposubs]
210 210 > * = Test
211 211 > EOF
212 212
213 213 Pull from bundle and trigger notify
214 214
215 215 $ hg pull -u ../kw.hg
216 216 pulling from ../kw.hg
217 217 requesting all changes
218 218 adding changesets
219 219 adding manifests
220 220 adding file changes
221 221 added 2 changesets with 3 changes to 3 files
222 222 Content-Type: text/plain; charset="us-ascii"
223 223 MIME-Version: 1.0
224 224 Content-Transfer-Encoding: 7bit
225 225 Date: * (glob)
226 226 Subject: changeset in...
227 227 From: mercurial
228 228 X-Hg-Notification: changeset a2392c293916
229 229 Message-Id: <hg.a2392c293916*> (glob)
230 230 To: Test
231 231
232 232 changeset a2392c293916 in $TESTTMP/Test (glob)
233 233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
234 234 description:
235 235 addsym
236 236
237 237 diffs (6 lines):
238 238
239 239 diff -r 000000000000 -r a2392c293916 sym
240 240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241 241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
242 242 @@ -0,0 +1,1 @@
243 243 +a
244 244 \ No newline at end of file
245 245 Content-Type: text/plain; charset="us-ascii"
246 246 MIME-Version: 1.0
247 247 Content-Transfer-Encoding: 7bit
248 248 Date:* (glob)
249 249 Subject: changeset in...
250 250 From: User Name <user@example.com>
251 251 X-Hg-Notification: changeset ef63ca68695b
252 252 Message-Id: <hg.ef63ca68695b*> (glob)
253 253 To: Test
254 254
255 255 changeset ef63ca68695b in $TESTTMP/Test (glob)
256 256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
257 257 description:
258 258 absym
259 259
260 260 diffs (12 lines):
261 261
262 262 diff -r a2392c293916 -r ef63ca68695b a
263 263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
264 264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
265 265 @@ -0,0 +1,3 @@
266 266 +expand $Id$
267 267 +do not process $Id:
268 268 +xxx $
269 269 diff -r a2392c293916 -r ef63ca68695b b
270 270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271 271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
272 272 @@ -0,0 +1,1 @@
273 273 +ignore $Id$
274 274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 275
276 276 $ cp $HGRCPATH.nohooks $HGRCPATH
277 277
278 278 Touch files and check with status
279 279
280 280 $ touch a b
281 281 $ hg status
282 282
283 283 Update and expand
284 284
285 285 $ rm sym a b
286 286 $ hg update -C
287 287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 288 $ cat a b
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 ignore $Id$
293 293
294 294 Check whether expansion is filewise and file mode is preserved
295 295
296 296 $ echo '$Id$' > c
297 297 $ echo 'tests for different changenodes' >> c
298 298 #if unix-permissions
299 299 $ chmod 600 c
300 300 $ ls -l c | cut -b 1-10
301 301 -rw-------
302 302 #endif
303 303
304 304 commit file c
305 305
306 306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
307 307 adding c
308 308 #if unix-permissions
309 309 $ ls -l c | cut -b 1-10
310 310 -rw-------
311 311 #endif
312 312
313 313 force expansion
314 314
315 315 $ hg -v kwexpand
316 316 overwriting a expanding keywords
317 317 overwriting c expanding keywords
318 318
319 319 compare changenodes in a and c
320 320
321 321 $ cat a c
322 322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
323 323 do not process $Id:
324 324 xxx $
325 325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
326 326 tests for different changenodes
327 327
328 328 record
329 329
330 330 $ echo '$Id$' > r
331 331 $ hg add r
332 332
333 333 record chunk
334 334
335 335 >>> lines = open('a', 'rb').readlines()
336 336 >>> lines.insert(1, 'foo\n')
337 337 >>> lines.append('bar\n')
338 338 >>> open('a', 'wb').writelines(lines)
339 339 $ hg record -d '10 1' -m rectest a<<EOF
340 340 > y
341 341 > y
342 342 > n
343 343 > EOF
344 344 diff --git a/a b/a
345 345 2 hunks, 2 lines changed
346 346 examine changes to 'a'? [Ynesfdaq?] y
347 347
348 348 @@ -1,3 +1,4 @@
349 349 expand $Id$
350 350 +foo
351 351 do not process $Id:
352 352 xxx $
353 353 record change 1/2 to 'a'? [Ynesfdaq?] y
354 354
355 355 @@ -2,2 +3,3 @@
356 356 do not process $Id:
357 357 xxx $
358 358 +bar
359 359 record change 2/2 to 'a'? [Ynesfdaq?] n
360 360
361 361
362 362 $ hg identify
363 363 5f5eb23505c3+ tip
364 364 $ hg status
365 365 M a
366 366 A r
367 367
368 368 Cat modified file a
369 369
370 370 $ cat a
371 371 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
372 372 foo
373 373 do not process $Id:
374 374 xxx $
375 375 bar
376 376
377 377 Diff remaining chunk
378 378
379 379 $ hg diff a
380 380 diff -r 5f5eb23505c3 a
381 381 --- a/a Thu Jan 01 00:00:09 1970 -0000
382 382 +++ b/a * (glob)
383 383 @@ -2,3 +2,4 @@
384 384 foo
385 385 do not process $Id:
386 386 xxx $
387 387 +bar
388 388
389 389 $ hg rollback
390 390 repository tip rolled back to revision 2 (undo commit)
391 391 working directory now based on revision 2
392 392
393 393 Record all chunks in file a
394 394
395 395 $ echo foo > msg
396 396
397 397 - do not use "hg record -m" here!
398 398
399 399 $ hg record -l msg -d '11 1' a<<EOF
400 400 > y
401 401 > y
402 402 > y
403 403 > EOF
404 404 diff --git a/a b/a
405 405 2 hunks, 2 lines changed
406 406 examine changes to 'a'? [Ynesfdaq?] y
407 407
408 408 @@ -1,3 +1,4 @@
409 409 expand $Id$
410 410 +foo
411 411 do not process $Id:
412 412 xxx $
413 413 record change 1/2 to 'a'? [Ynesfdaq?] y
414 414
415 415 @@ -2,2 +3,3 @@
416 416 do not process $Id:
417 417 xxx $
418 418 +bar
419 419 record change 2/2 to 'a'? [Ynesfdaq?] y
420 420
421 421
422 422 File a should be clean
423 423
424 424 $ hg status -A a
425 425 C a
426 426
427 427 rollback and revert expansion
428 428
429 429 $ cat a
430 430 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
431 431 foo
432 432 do not process $Id:
433 433 xxx $
434 434 bar
435 435 $ hg --verbose rollback
436 436 repository tip rolled back to revision 2 (undo commit)
437 437 working directory now based on revision 2
438 438 overwriting a expanding keywords
439 439 $ hg status a
440 440 M a
441 441 $ cat a
442 442 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
443 443 foo
444 444 do not process $Id:
445 445 xxx $
446 446 bar
447 447 $ echo '$Id$' > y
448 448 $ echo '$Id$' > z
449 449 $ hg add y
450 450 $ hg commit -Am "rollback only" z
451 451 $ cat z
452 452 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
453 453 $ hg --verbose rollback
454 454 repository tip rolled back to revision 2 (undo commit)
455 455 working directory now based on revision 2
456 456 overwriting z shrinking keywords
457 457
458 458 Only z should be overwritten
459 459
460 460 $ hg status a y z
461 461 M a
462 462 A y
463 463 A z
464 464 $ cat z
465 465 $Id$
466 466 $ hg forget y z
467 467 $ rm y z
468 468
469 469 record added file alone
470 470
471 471 $ hg -v record -l msg -d '12 2' r<<EOF
472 472 > y
473 473 > EOF
474 474 diff --git a/r b/r
475 475 new file mode 100644
476 476 examine changes to 'r'? [Ynesfdaq?] y
477 477
478 478 r
479 479 committed changeset 3:82a2f715724d
480 480 overwriting r expanding keywords
481 481 - status call required for dirstate.normallookup() check
482 482 $ hg status r
483 483 $ hg --verbose rollback
484 484 repository tip rolled back to revision 2 (undo commit)
485 485 working directory now based on revision 2
486 486 overwriting r shrinking keywords
487 487 $ hg forget r
488 488 $ rm msg r
489 489 $ hg update -C
490 490 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
491 491
492 492 record added keyword ignored file
493 493
494 494 $ echo '$Id$' > i
495 495 $ hg add i
496 496 $ hg --verbose record -d '13 1' -m recignored<<EOF
497 497 > y
498 498 > EOF
499 499 diff --git a/i b/i
500 500 new file mode 100644
501 501 examine changes to 'i'? [Ynesfdaq?] y
502 502
503 503 i
504 504 committed changeset 3:9f40ceb5a072
505 505 $ cat i
506 506 $Id$
507 507 $ hg -q rollback
508 508 $ hg forget i
509 509 $ rm i
510 510
511 511 amend
512 512
513 513 $ echo amend >> a
514 514 $ echo amend >> b
515 515 $ hg -q commit -d '14 1' -m 'prepare amend'
516 516
517 517 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
518 518 overwriting a expanding keywords
519 519 $ hg -q id
520 520 67d8c481a6be
521 521 $ head -1 a
522 522 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
523 523
524 524 $ hg -q strip --no-backup tip
525 525
526 526 Test patch queue repo
527 527
528 528 $ hg init --mq
529 529 $ hg qimport -r tip -n mqtest.diff
530 530 $ hg commit --mq -m mqtest
531 531
532 532 Keywords should not be expanded in patch
533 533
534 534 $ cat .hg/patches/mqtest.diff
535 535 # HG changeset patch
536 536 # User User Name <user@example.com>
537 537 # Date 1 0
538 538 # Thu Jan 01 00:00:01 1970 +0000
539 539 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
540 540 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
541 541 cndiff
542 542
543 543 diff -r ef63ca68695b -r 40a904bbbe4c c
544 544 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
545 545 +++ b/c Thu Jan 01 00:00:01 1970 +0000
546 546 @@ -0,0 +1,2 @@
547 547 +$Id$
548 548 +tests for different changenodes
549 549
550 550 $ hg qpop
551 551 popping mqtest.diff
552 552 patch queue now empty
553 553
554 554 qgoto, implying qpush, should expand
555 555
556 556 $ hg qgoto mqtest.diff
557 557 applying mqtest.diff
558 558 now at: mqtest.diff
559 559 $ cat c
560 560 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
561 561 tests for different changenodes
562 562 $ hg cat c
563 563 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
564 564 tests for different changenodes
565 565
566 566 Keywords should not be expanded in filelog
567 567
568 568 $ hg --config 'extensions.keyword=!' cat c
569 569 $Id$
570 570 tests for different changenodes
571 571
572 572 qpop and move on
573 573
574 574 $ hg qpop
575 575 popping mqtest.diff
576 576 patch queue now empty
577 577
578 578 Copy and show added kwfiles
579 579
580 580 $ hg cp a c
581 581 $ hg kwfiles
582 582 a
583 583 c
584 584
585 585 Commit and show expansion in original and copy
586 586
587 587 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
588 588 invalid branchheads cache (served): tip differs
589 589 c
590 590 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
591 591 invalid branchheads cache (served): tip differs
592 592 overwriting c expanding keywords
593 593 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
594 594 $ cat a c
595 595 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
596 596 do not process $Id:
597 597 xxx $
598 598 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
599 599 do not process $Id:
600 600 xxx $
601 601
602 602 Touch copied c and check its status
603 603
604 604 $ touch c
605 605 $ hg status
606 606
607 607 Copy kwfile to keyword ignored file unexpanding keywords
608 608
609 609 $ hg --verbose copy a i
610 610 copying a to i
611 611 overwriting i shrinking keywords
612 612 $ head -n 1 i
613 613 expand $Id$
614 614 $ hg forget i
615 615 $ rm i
616 616
617 617 Copy ignored file to ignored file: no overwriting
618 618
619 619 $ hg --verbose copy b i
620 620 copying b to i
621 621 $ hg forget i
622 622 $ rm i
623 623
624 624 cp symlink file; hg cp -A symlink file (part1)
625 625 - copied symlink points to kwfile: overwrite
626 626
627 627 #if symlink
628 628 $ cp sym i
629 629 $ ls -l i
630 630 -rw-r--r--* (glob)
631 631 $ head -1 i
632 632 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
633 633 $ hg copy --after --verbose sym i
634 634 copying sym to i
635 635 overwriting i shrinking keywords
636 636 $ head -1 i
637 637 expand $Id$
638 638 $ hg forget i
639 639 $ rm i
640 640 #endif
641 641
642 642 Test different options of hg kwfiles
643 643
644 644 $ hg kwfiles
645 645 a
646 646 c
647 647 $ hg -v kwfiles --ignore
648 648 I b
649 649 I sym
650 650 $ hg kwfiles --all
651 651 K a
652 652 K c
653 653 I b
654 654 I sym
655 655
656 656 Diff specific revision
657 657
658 658 $ hg diff --rev 1
659 659 diff -r ef63ca68695b c
660 660 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
661 661 +++ b/c * (glob)
662 662 @@ -0,0 +1,3 @@
663 663 +expand $Id$
664 664 +do not process $Id:
665 665 +xxx $
666 666
667 667 Status after rollback:
668 668
669 669 $ hg rollback
670 670 repository tip rolled back to revision 1 (undo commit)
671 671 working directory now based on revision 1
672 672 $ hg status
673 673 A c
674 674 $ hg update --clean
675 675 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
676 676
677 677 #if symlink
678 678
679 679 cp symlink file; hg cp -A symlink file (part2)
680 680 - copied symlink points to kw ignored file: do not overwrite
681 681
682 682 $ cat a > i
683 683 $ ln -s i symignored
684 684 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
685 685 $ cp symignored x
686 686 $ hg copy --after --verbose symignored x
687 687 copying symignored to x
688 688 $ head -n 1 x
689 689 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
690 690 $ hg forget x
691 691 $ rm x
692 692
693 693 $ hg rollback
694 694 repository tip rolled back to revision 1 (undo commit)
695 695 working directory now based on revision 1
696 696 $ hg update --clean
697 697 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
698 698 $ rm i symignored
699 699
700 700 #endif
701 701
702 702 Custom keywordmaps as argument to kwdemo
703 703
704 704 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
705 705 [extensions]
706 706 keyword =
707 707 [keyword]
708 708 ** =
709 709 b = ignore
710 710 demo.txt =
711 711 i = ignore
712 712 [keywordset]
713 713 svn = False
714 714 [keywordmaps]
715 715 Xinfo = {author}: {desc}
716 716 $Xinfo: test: hg keyword configuration and expansion example $
717 717
718 718 Configure custom keywordmaps
719 719
720 720 $ cat <<EOF >>$HGRCPATH
721 721 > [keywordmaps]
722 722 > Id = {file} {node|short} {date|rfc822date} {author|user}
723 723 > Xinfo = {author}: {desc}
724 724 > EOF
725 725
726 726 Cat and hg cat files before custom expansion
727 727
728 728 $ cat a b
729 729 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
730 730 do not process $Id:
731 731 xxx $
732 732 ignore $Id$
733 733 $ hg cat sym a b && echo
734 734 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
735 735 do not process $Id:
736 736 xxx $
737 737 ignore $Id$
738 738 a
739 739
740 740 Write custom keyword and prepare multi-line commit message
741 741
742 742 $ echo '$Xinfo$' >> a
743 743 $ cat <<EOF >> log
744 744 > firstline
745 745 > secondline
746 746 > EOF
747 747
748 748 Interrupted commit should not change state
749 749
750 750 $ hg commit
751 751 abort: empty commit message
752 752 [255]
753 753 $ hg status
754 754 M a
755 755 ? c
756 756 ? log
757 757
758 758 Commit with multi-line message and custom expansion
759 759
760 760 |Note:
761 761 |
762 762 | After the last rollback, the "served" branchheads cache became invalid, but
763 763 | all changesets in the repo were public. For filtering this means:
764 764 | "immutable" == "served" == ΓΈ.
765 765 |
766 766 | As the "served" cache is invalid, we fall back to the "immutable" cache. But
767 767 | no update is needed between "immutable" and "served" and the "served" cache
768 768 | is not updated on disk. The on-disk version therefore stays invalid for some
769 769 | time. This explains why the "served" branchheads cache is detected as
770 770 | invalid here.
771 771
772 772 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
773 773 invalid branchheads cache (served): tip differs
774 774 a
775 775 invalid branchheads cache (served): tip differs
776 776 overwriting a expanding keywords
777 777 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
778 778 $ rm log
779 779
780 780 Stat, verify and show custom expansion (firstline)
781 781
782 782 $ hg status
783 783 ? c
784 784 $ hg verify
785 785 checking changesets
786 786 checking manifests
787 787 crosschecking files in changesets and manifests
788 788 checking files
789 789 3 files, 3 changesets, 4 total revisions
790 790 $ cat a b
791 791 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
792 792 do not process $Id:
793 793 xxx $
794 794 $Xinfo: User Name <user@example.com>: firstline $
795 795 ignore $Id$
796 796 $ hg cat sym a b && echo
797 797 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
798 798 do not process $Id:
799 799 xxx $
800 800 $Xinfo: User Name <user@example.com>: firstline $
801 801 ignore $Id$
802 802 a
803 803
804 804 annotate
805 805
806 806 $ hg annotate a
807 807 1: expand $Id$
808 808 1: do not process $Id:
809 809 1: xxx $
810 810 2: $Xinfo$
811 811
812 812 remove with status checks
813 813
814 814 $ hg debugrebuildstate
815 815 $ hg remove a
816 816 $ hg --debug commit -m rma
817 817 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
818 818 $ hg status
819 819 ? c
820 820
821 821 Rollback, revert, and check expansion
822 822
823 823 $ hg rollback
824 824 repository tip rolled back to revision 2 (undo commit)
825 825 working directory now based on revision 2
826 826 $ hg status
827 827 R a
828 828 ? c
829 829 $ hg revert --no-backup --rev tip a
830 830 $ cat a
831 831 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
832 832 do not process $Id:
833 833 xxx $
834 834 $Xinfo: User Name <user@example.com>: firstline $
835 835
836 836 Clone to test global and local configurations
837 837
838 838 $ cd ..
839 839
840 840 Expansion in destination with global configuration
841 841
842 842 $ hg --quiet clone Test globalconf
843 843 $ cat globalconf/a
844 844 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
845 845 do not process $Id:
846 846 xxx $
847 847 $Xinfo: User Name <user@example.com>: firstline $
848 848
849 849 No expansion in destination with local configuration in origin only
850 850
851 851 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
852 852 $ cat localconf/a
853 853 expand $Id$
854 854 do not process $Id:
855 855 xxx $
856 856 $Xinfo$
857 857
858 858 Clone to test incoming
859 859
860 860 $ hg clone -r1 Test Test-a
861 861 adding changesets
862 862 adding manifests
863 863 adding file changes
864 864 added 2 changesets with 3 changes to 3 files
865 865 updating to branch default
866 866 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
867 867 $ cd Test-a
868 868 $ cat <<EOF >> .hg/hgrc
869 869 > [paths]
870 870 > default = ../Test
871 871 > EOF
872 872 $ hg incoming
873 873 comparing with $TESTTMP/Test (glob)
874 874 searching for changes
875 875 changeset: 2:bb948857c743
876 876 tag: tip
877 877 user: User Name <user@example.com>
878 878 date: Thu Jan 01 00:00:02 1970 +0000
879 879 summary: firstline
880 880
881 881 Imported patch should not be rejected
882 882
883 883 >>> import re
884 884 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
885 885 >>> open('a', 'wb').write(text)
886 886 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
887 887 a
888 888 overwriting a expanding keywords
889 889 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
890 890 $ hg export -o ../rejecttest.diff tip
891 891 $ cd ../Test
892 892 $ hg import ../rejecttest.diff
893 893 applying ../rejecttest.diff
894 894 $ cat a b
895 895 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
896 896 do not process $Id: rejecttest
897 897 xxx $
898 898 $Xinfo: User Name <user@example.com>: rejects? $
899 899 ignore $Id$
900 900
901 901 $ hg rollback
902 902 repository tip rolled back to revision 2 (undo import)
903 903 working directory now based on revision 2
904 904 $ hg update --clean
905 905 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
906 906
907 907 kwexpand/kwshrink on selected files
908 908
909 909 $ mkdir x
910 910 $ hg copy a x/a
911 911 $ hg --verbose kwshrink a
912 912 overwriting a shrinking keywords
913 913 - sleep required for dirstate.normal() check
914 914 $ sleep 1
915 915 $ hg status a
916 916 $ hg --verbose kwexpand a
917 917 overwriting a expanding keywords
918 918 $ hg status a
919 919
920 920 kwexpand x/a should abort
921 921
922 922 $ hg --verbose kwexpand x/a
923 923 abort: outstanding uncommitted changes
924 924 [255]
925 925 $ cd x
926 926 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
927 927 x/a
928 928 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
929 929 overwriting x/a expanding keywords
930 930 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
931 931 $ cat a
932 932 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
933 933 do not process $Id:
934 934 xxx $
935 935 $Xinfo: User Name <user@example.com>: xa $
936 936
937 937 kwshrink a inside directory x
938 938
939 939 $ hg --verbose kwshrink a
940 940 overwriting x/a shrinking keywords
941 941 $ cat a
942 942 expand $Id$
943 943 do not process $Id:
944 944 xxx $
945 945 $Xinfo$
946 946 $ cd ..
947 947
948 948 kwexpand nonexistent
949 949
950 950 $ hg kwexpand nonexistent
951 951 nonexistent:* (glob)
952 952
953 953
954 954 #if serve
955 955 hg serve
956 956 - expand with hgweb file
957 957 - no expansion with hgweb annotate/changeset/filediff
958 958 - check errors
959 959
960 960 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
961 961 $ cat hg.pid >> $DAEMON_PIDS
962 962 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
963 963 200 Script output follows
964 964
965 965 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
966 966 do not process $Id:
967 967 xxx $
968 968 $Xinfo: User Name <user@example.com>: firstline $
969 969 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
970 970 200 Script output follows
971 971
972 972
973 973 user@1: expand $Id$
974 974 user@1: do not process $Id:
975 975 user@1: xxx $
976 976 user@2: $Xinfo$
977 977
978 978
979 979
980 980
981 981 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
982 982 200 Script output follows
983 983
984 984
985 985 # HG changeset patch
986 986 # User User Name <user@example.com>
987 987 # Date 3 0
988 988 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
989 989 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
990 990 xa
991 991
992 992 diff -r bb948857c743 -r b4560182a3f9 x/a
993 993 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
994 994 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
995 995 @@ -0,0 +1,4 @@
996 996 +expand $Id$
997 997 +do not process $Id:
998 998 +xxx $
999 999 +$Xinfo$
1000 1000
1001 1001 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
1002 1002 200 Script output follows
1003 1003
1004 1004
1005 1005 diff -r ef63ca68695b -r bb948857c743 a
1006 1006 --- a/a Thu Jan 01 00:00:00 1970 +0000
1007 1007 +++ b/a Thu Jan 01 00:00:02 1970 +0000
1008 1008 @@ -1,3 +1,4 @@
1009 1009 expand $Id$
1010 1010 do not process $Id:
1011 1011 xxx $
1012 1012 +$Xinfo$
1013 1013
1014 1014
1015 1015
1016 1016
1017 1017 $ cat errors.log
1018 1018 #endif
1019 1019
1020 1020 Prepare merge and resolve tests
1021 1021
1022 1022 $ echo '$Id$' > m
1023 1023 $ hg add m
1024 1024 $ hg commit -m 4kw
1025 1025 $ echo foo >> m
1026 1026 $ hg commit -m 5foo
1027 1027
1028 1028 simplemerge
1029 1029
1030 1030 $ hg update 4
1031 1031 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1032 1032 $ echo foo >> m
1033 1033 $ hg commit -m 6foo
1034 1034 created new head
1035 1035 $ hg merge
1036 1036 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1037 1037 (branch merge, don't forget to commit)
1038 1038 $ hg commit -m simplemerge
1039 1039 $ cat m
1040 1040 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1041 1041 foo
1042 1042
1043 1043 conflict: keyword should stay outside conflict zone
1044 1044
1045 1045 $ hg update 4
1046 1046 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1047 1047 $ echo bar >> m
1048 1048 $ hg commit -m 8bar
1049 1049 created new head
1050 1050 $ hg merge
1051 1051 merging m
1052 1052 warning: conflicts during merge.
1053 1053 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1054 1054 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1055 1055 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1056 1056 [1]
1057 1057 $ cat m
1058 1058 $Id$
1059 1059 <<<<<<< local: 88a80c8d172e - test: 8bar
1060 1060 bar
1061 1061 =======
1062 1062 foo
1063 1063 >>>>>>> other: 85d2d2d732a5 - test: simplemerge
1064 1064
1065 resolve to local
1065 resolve to local, m must contain hash of last change (local parent)
1066 1066
1067 1067 $ hg resolve -t internal:local -a
1068 1068 (no more unresolved files)
1069 1069 $ hg commit -m localresolve
1070 1070 $ cat m
1071 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1071 $Id: m 88a80c8d172e Thu, 01 Jan 1970 00:00:00 +0000 test $
1072 1072 bar
1073 1073
1074 1074 Test restricted mode with transplant -b
1075 1075
1076 1076 $ hg update 6
1077 1077 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1078 1078 $ hg branch foo
1079 1079 marked working directory as branch foo
1080 1080 (branches are permanent and global, did you want a bookmark?)
1081 1081 $ mv a a.bak
1082 1082 $ echo foobranch > a
1083 1083 $ cat a.bak >> a
1084 1084 $ rm a.bak
1085 1085 $ hg commit -m 9foobranch
1086 1086 $ hg update default
1087 1087 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1088 1088 $ hg -y transplant -b foo tip
1089 1089 applying 4aa30d025d50
1090 1090 4aa30d025d50 transplanted to e00abbf63521
1091 1091
1092 1092 Expansion in changeset but not in file
1093 1093
1094 1094 $ hg tip -p
1095 1095 changeset: 11:e00abbf63521
1096 1096 tag: tip
1097 1097 parent: 9:800511b3a22d
1098 1098 user: test
1099 1099 date: Thu Jan 01 00:00:00 1970 +0000
1100 1100 summary: 9foobranch
1101 1101
1102 1102 diff -r 800511b3a22d -r e00abbf63521 a
1103 1103 --- a/a Thu Jan 01 00:00:00 1970 +0000
1104 1104 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1105 1105 @@ -1,3 +1,4 @@
1106 1106 +foobranch
1107 1107 expand $Id$
1108 1108 do not process $Id:
1109 1109 xxx $
1110 1110
1111 1111 $ head -n 2 a
1112 1112 foobranch
1113 1113 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1114 1114
1115 1115 Turn off expansion
1116 1116
1117 1117 $ hg -q rollback
1118 1118 $ hg -q update -C
1119 1119
1120 1120 kwshrink with unknown file u
1121 1121
1122 1122 $ cp a u
1123 1123 $ hg --verbose kwshrink
1124 1124 overwriting a shrinking keywords
1125 1125 overwriting m shrinking keywords
1126 1126 overwriting x/a shrinking keywords
1127 1127
1128 1128 Keywords shrunk in working directory, but not yet disabled
1129 1129 - cat shows unexpanded keywords
1130 1130 - hg cat shows expanded keywords
1131 1131
1132 1132 $ cat a b
1133 1133 expand $Id$
1134 1134 do not process $Id:
1135 1135 xxx $
1136 1136 $Xinfo$
1137 1137 ignore $Id$
1138 1138 $ hg cat sym a b && echo
1139 1139 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1140 1140 do not process $Id:
1141 1141 xxx $
1142 1142 $Xinfo: User Name <user@example.com>: firstline $
1143 1143 ignore $Id$
1144 1144 a
1145 1145
1146 1146 Now disable keyword expansion
1147 1147
1148 1148 $ cp $HGRCPATH $HGRCPATH.backup
1149 1149 $ rm "$HGRCPATH"
1150 1150 $ cat a b
1151 1151 expand $Id$
1152 1152 do not process $Id:
1153 1153 xxx $
1154 1154 $Xinfo$
1155 1155 ignore $Id$
1156 1156 $ hg cat sym a b && echo
1157 1157 expand $Id$
1158 1158 do not process $Id:
1159 1159 xxx $
1160 1160 $Xinfo$
1161 1161 ignore $Id$
1162 1162 a
1163 1163
1164 1164 enable keyword expansion again
1165 1165
1166 1166 $ cat $HGRCPATH.backup >> $HGRCPATH
1167 1167
1168 1168 Test restricted mode with unshelve
1169 1169
1170 1170 $ cat <<EOF >> $HGRCPATH
1171 1171 > [extensions]
1172 1172 > shelve =
1173 1173 > EOF
1174 1174
1175 1175 $ echo xxxx >> a
1176 1176 $ hg diff
1177 1177 diff -r 800511b3a22d a
1178 1178 --- a/a Thu Jan 01 00:00:00 1970 +0000
1179 1179 +++ b/a * (glob)
1180 1180 @@ -2,3 +2,4 @@
1181 1181 do not process $Id:
1182 1182 xxx $
1183 1183 $Xinfo$
1184 1184 +xxxx
1185 1185 $ hg shelve -q --name tmp
1186 1186 $ hg shelve --list --patch
1187 1187 tmp (*) changes to 'localresolve' (glob)
1188 1188
1189 1189 diff --git a/a b/a
1190 1190 --- a/a
1191 1191 +++ b/a
1192 1192 @@ -2,3 +2,4 @@
1193 1193 do not process $Id:
1194 1194 xxx $
1195 1195 $Xinfo$
1196 1196 +xxxx
1197 1197
1198 1198 $ hg update -q -C 10
1199 1199 $ hg unshelve -q tmp
1200 1200 $ hg diff
1201 1201 diff -r 4aa30d025d50 a
1202 1202 --- a/a Thu Jan 01 00:00:00 1970 +0000
1203 1203 +++ b/a * (glob)
1204 1204 @@ -3,3 +3,4 @@
1205 1205 do not process $Id:
1206 1206 xxx $
1207 1207 $Xinfo$
1208 1208 +xxxx
1209 1209
1210 1210 Test restricted mode with rebase
1211 1211
1212 1212 $ cat <<EOF >> $HGRCPATH
1213 1213 > [extensions]
1214 1214 > rebase =
1215 1215 > EOF
1216 1216
1217 1217 $ hg update -q -C 9
1218 1218
1219 1219 $ echo xxxx >> a
1220 1220 $ hg commit -m '#11'
1221 1221 $ hg diff -c 11
1222 1222 diff -r 800511b3a22d -r b07670694489 a
1223 1223 --- a/a Thu Jan 01 00:00:00 1970 +0000
1224 1224 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1225 1225 @@ -2,3 +2,4 @@
1226 1226 do not process $Id:
1227 1227 xxx $
1228 1228 $Xinfo$
1229 1229 +xxxx
1230 1230
1231 1231 $ hg diff -c 10
1232 1232 diff -r 27d48ee14f67 -r 4aa30d025d50 a
1233 1233 --- a/a Thu Jan 01 00:00:00 1970 +0000
1234 1234 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1235 1235 @@ -1,3 +1,4 @@
1236 1236 +foobranch
1237 1237 expand $Id$
1238 1238 do not process $Id:
1239 1239 xxx $
1240 1240
1241 1241 $ hg rebase -q -s 10 -d 11 --keep
1242 1242 $ hg diff -r 9 -r 12 a
1243 1243 diff -r 800511b3a22d -r 1939b927726c a
1244 1244 --- a/a Thu Jan 01 00:00:00 1970 +0000
1245 1245 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1246 1246 @@ -1,4 +1,6 @@
1247 1247 +foobranch
1248 1248 expand $Id$
1249 1249 do not process $Id:
1250 1250 xxx $
1251 1251 $Xinfo$
1252 1252 +xxxx
1253 1253
1254 1254 Test restricted mode with graft
1255 1255
1256 1256 $ hg graft -q 10
1257 1257 $ hg diff -r 9 -r 13 a
1258 1258 diff -r 800511b3a22d -r 01a68de1003a a
1259 1259 --- a/a Thu Jan 01 00:00:00 1970 +0000
1260 1260 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1261 1261 @@ -1,4 +1,6 @@
1262 1262 +foobranch
1263 1263 expand $Id$
1264 1264 do not process $Id:
1265 1265 xxx $
1266 1266 $Xinfo$
1267 1267 +xxxx
1268 1268
1269 1269 Test restricted mode with backout
1270 1270
1271 1271 $ hg backout -q 11
1272 1272 $ hg diff a
1273 1273 diff -r 01a68de1003a a
1274 1274 --- a/a Thu Jan 01 00:00:00 1970 +0000
1275 1275 +++ b/a * (glob)
1276 1276 @@ -3,4 +3,3 @@
1277 1277 do not process $Id:
1278 1278 xxx $
1279 1279 $Xinfo$
1280 1280 -xxxx
1281 1281
1282 1282 Test restricted mode with histedit
1283 1283
1284 1284 $ cat <<EOF >> $HGRCPATH
1285 1285 > [extensions]
1286 1286 > histedit =
1287 1287 > EOF
1288 1288
1289 1289 $ hg commit -m 'backout #11'
1290 1290 $ hg histedit -q --command - 13 <<EOF
1291 1291 > pick 49f5f2d940c3 14 backout #11
1292 1292 > pick 01a68de1003a 13 9foobranch
1293 1293 > EOF
1294 1294
1295 1295 Test restricted mode with fetch (with merge)
1296 1296
1297 1297 $ cat <<EOF >> $HGRCPATH
1298 1298 > [extensions]
1299 1299 > fetch =
1300 1300 > EOF
1301 1301
1302 1302 $ hg clone -q -r 9 . ../fetch-merge
1303 1303 $ cd ../fetch-merge
1304 1304 $ hg -R ../Test export 10 | hg import -q -
1305 1305 $ hg fetch -q -r 11
1306 1306 $ hg diff -r 9 a
1307 1307 diff -r 800511b3a22d a
1308 1308 --- a/a Thu Jan 01 00:00:00 1970 +0000
1309 1309 +++ b/a * (glob)
1310 1310 @@ -1,4 +1,6 @@
1311 1311 +foobranch
1312 1312 expand $Id$
1313 1313 do not process $Id:
1314 1314 xxx $
1315 1315 $Xinfo$
1316 1316 +xxxx
1317 1317
1318 1318 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now