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