1 # keyword.py - $Keyword$ expansion for Mercurial |
1 # keyword.py - $Keyword$ expansion for Mercurial |
2 # |
2 # |
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net> |
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net> |
4 # |
4 # |
5 # This software may be used and distributed according to the terms |
5 # This software may be used and distributed according to the terms of the |
6 # of the GNU General Public License, incorporated herein by reference. |
6 # GNU General Public License version 2, incorporated herein by reference. |
7 # |
7 # |
8 # $Id$ |
8 # $Id$ |
9 # |
9 # |
10 # Keyword expansion hack against the grain of a DSCM |
10 # Keyword expansion hack against the grain of a DSCM |
11 # |
11 # |
12 # There are many good reasons why this is not needed in a distributed |
12 # There are many good reasons why this is not needed in a distributed |
13 # SCM, still it may be useful in very small projects based on single |
13 # SCM, still it may be useful in very small projects based on single |
14 # files (like LaTeX packages), that are mostly addressed to an audience |
14 # files (like LaTeX packages), that are mostly addressed to an |
15 # not running a version control system. |
15 # audience not running a version control system. |
16 # |
16 # |
17 # For in-depth discussion refer to |
17 # For in-depth discussion refer to |
18 # <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>. |
18 # <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>. |
19 # |
19 # |
20 # Keyword expansion is based on Mercurial's changeset template mappings. |
20 # Keyword expansion is based on Mercurial's changeset template mappings. |
34 # |
34 # |
35 # Run "hg help keyword" and "hg kwdemo" to get info on configuration. |
35 # Run "hg help keyword" and "hg kwdemo" to get info on configuration. |
36 |
36 |
37 '''keyword expansion in local repositories |
37 '''keyword expansion in local repositories |
38 |
38 |
39 This extension expands RCS/CVS-like or self-customized $Keywords$ |
39 This extension expands RCS/CVS-like or self-customized $Keywords$ in |
40 in tracked text files selected by your configuration. |
40 tracked text files selected by your configuration. |
41 |
41 |
42 Keywords are only expanded in local repositories and not stored in |
42 Keywords are only expanded in local repositories and not stored in the |
43 the change history. The mechanism can be regarded as a convenience |
43 change history. The mechanism can be regarded as a convenience for the |
44 for the current user or for archive distribution. |
44 current user or for archive distribution. |
45 |
45 |
46 Configuration is done in the [keyword] and [keywordmaps] sections |
46 Configuration is done in the [keyword] and [keywordmaps] sections of |
47 of hgrc files. |
47 hgrc files. |
48 |
48 |
49 Example: |
49 Example: |
50 |
50 |
51 [keyword] |
51 [keyword] |
52 # expand keywords in every python file except those matching "x*" |
52 # expand keywords in every python file except those matching "x*" |
53 **.py = |
53 **.py = |
54 x* = ignore |
54 x* = ignore |
55 |
55 |
56 Note: the more specific you are in your filename patterns |
56 Note: the more specific you are in your filename patterns |
57 the less you lose speed in huge repos. |
57 the less you lose speed in huge repositories. |
58 |
58 |
59 For [keywordmaps] template mapping and expansion demonstration and |
59 For [keywordmaps] template mapping and expansion demonstration and |
60 control run "hg kwdemo". |
60 control run "hg kwdemo". |
61 |
61 |
62 An additional date template filter {date|utcdate} is provided. |
62 An additional date template filter {date|utcdate} is provided. |
63 |
63 |
64 The default template mappings (view with "hg kwdemo -d") can be replaced |
64 The default template mappings (view with "hg kwdemo -d") can be |
65 with customized keywords and templates. |
65 replaced with customized keywords and templates. Again, run "hg |
66 Again, run "hg kwdemo" to control the results of your config changes. |
66 kwdemo" to control the results of your config changes. |
67 |
67 |
68 Before changing/disabling active keywords, run "hg kwshrink" to avoid |
68 Before changing/disabling active keywords, run "hg kwshrink" to avoid |
69 the risk of inadvertedly storing expanded keywords in the change history. |
69 the risk of inadvertently storing expanded keywords in the change |
|
70 history. |
70 |
71 |
71 To force expansion after enabling it, or a configuration change, run |
72 To force expansion after enabling it, or a configuration change, run |
72 "hg kwexpand". |
73 "hg kwexpand". |
73 |
74 |
74 Also, when committing with the record extension or using mq's qrecord, be aware |
75 Also, when committing with the record extension or using mq's qrecord, |
75 that keywords cannot be updated. Again, run "hg kwexpand" on the files in |
76 be aware that keywords cannot be updated. Again, run "hg kwexpand" on |
76 question to update keyword expansions after all changes have been checked in. |
77 the files in question to update keyword expansions after all changes |
|
78 have been checked in. |
77 |
79 |
78 Expansions spanning more than one line and incremental expansions, |
80 Expansions spanning more than one line and incremental expansions, |
79 like CVS' $Log$, are not supported. A keyword template map |
81 like CVS' $Log$, are not supported. A keyword template map |
80 "Log = {desc}" expands to the first line of the changeset description. |
82 "Log = {desc}" expands to the first line of the changeset description. |
81 |
83 |
444 |
446 |
445 |
447 |
446 def demo(ui, repo, *args, **opts): |
448 def demo(ui, repo, *args, **opts): |
447 '''print [keywordmaps] configuration and an expansion example |
449 '''print [keywordmaps] configuration and an expansion example |
448 |
450 |
449 Show current, custom, or default keyword template maps |
451 Show current, custom, or default keyword template maps and their |
450 and their expansions. |
452 expansions. |
451 |
453 |
452 Extend current configuration by specifying maps as arguments |
454 Extend current configuration by specifying maps as arguments and |
453 and optionally by reading from an additional hgrc file. |
455 optionally by reading from an additional hgrc file. |
454 |
456 |
455 Override current keyword template maps with "default" option. |
457 Override current keyword template maps with "default" option. |
456 ''' |
458 ''' |
457 def demostatus(stat): |
459 def demostatus(stat): |
458 ui.status(_('\n\t%s\n') % stat) |
460 ui.status(_('\n\t%s\n') % stat) |
465 msg = 'hg keyword config and expansion example' |
467 msg = 'hg keyword config and expansion example' |
466 kwstatus = 'current' |
468 kwstatus = 'current' |
467 fn = 'demo.txt' |
469 fn = 'demo.txt' |
468 branchname = 'demobranch' |
470 branchname = 'demobranch' |
469 tmpdir = tempfile.mkdtemp('', 'kwdemo.') |
471 tmpdir = tempfile.mkdtemp('', 'kwdemo.') |
470 ui.note(_('creating temporary repo at %s\n') % tmpdir) |
472 ui.note(_('creating temporary repository at %s\n') % tmpdir) |
471 repo = localrepo.localrepository(ui, tmpdir, True) |
473 repo = localrepo.localrepository(ui, tmpdir, True) |
472 ui.setconfig('keyword', fn, '') |
474 ui.setconfig('keyword', fn, '') |
473 if args or opts.get('rcfile'): |
475 if args or opts.get('rcfile'): |
474 kwstatus = 'custom' |
476 kwstatus = 'custom' |
475 if opts.get('rcfile'): |
477 if opts.get('rcfile'): |
518 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg)) |
520 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg)) |
519 repo.commit(text=msg) |
521 repo.commit(text=msg) |
520 fmt = ui.verbose and ' in %s' % path or '' |
522 fmt = ui.verbose and ' in %s' % path or '' |
521 demostatus('%s keywords expanded%s' % (kwstatus, fmt)) |
523 demostatus('%s keywords expanded%s' % (kwstatus, fmt)) |
522 ui.write(repo.wread(fn)) |
524 ui.write(repo.wread(fn)) |
523 ui.debug(_('\nremoving temporary repo %s\n') % tmpdir) |
525 ui.debug(_('\nremoving temporary repository %s\n') % tmpdir) |
524 shutil.rmtree(tmpdir, ignore_errors=True) |
526 shutil.rmtree(tmpdir, ignore_errors=True) |
525 |
527 |
526 def expand(ui, repo, *pats, **opts): |
528 def expand(ui, repo, *pats, **opts): |
527 '''expand keywords in the working directory |
529 '''expand keywords in the working directory |
528 |
530 |
534 _kwfwrite(ui, repo, True, *pats, **opts) |
536 _kwfwrite(ui, repo, True, *pats, **opts) |
535 |
537 |
536 def files(ui, repo, *pats, **opts): |
538 def files(ui, repo, *pats, **opts): |
537 '''print files currently configured for keyword expansion |
539 '''print files currently configured for keyword expansion |
538 |
540 |
539 Crosscheck which files in working directory are potential targets for |
541 Crosscheck which files in working directory are potential targets |
540 keyword expansion. |
542 for keyword expansion. That is, files matched by [keyword] config |
541 That is, files matched by [keyword] config patterns but not symlinks. |
543 patterns but not symlinks. |
542 ''' |
544 ''' |
543 kwt = kwtools['templater'] |
545 kwt = kwtools['templater'] |
544 status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts) |
546 status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts) |
545 modified, added, removed, deleted, unknown, ignored, clean = status |
547 modified, added, removed, deleted, unknown, ignored, clean = status |
546 try: |
548 try: |
574 ui.write(fmt % _pathto(repo, f, cwd)) |
576 ui.write(fmt % _pathto(repo, f, cwd)) |
575 |
577 |
576 def shrink(ui, repo, *pats, **opts): |
578 def shrink(ui, repo, *pats, **opts): |
577 '''revert expanded keywords in the working directory |
579 '''revert expanded keywords in the working directory |
578 |
580 |
579 Run before changing/disabling active keywords |
581 Run before changing/disabling active keywords or if you experience |
580 or if you experience problems with "hg import" or "hg merge". |
582 problems with "hg import" or "hg merge". |
581 |
583 |
582 kwshrink refuses to run if given files contain local changes. |
584 kwshrink refuses to run if given files contain local changes. |
583 ''' |
585 ''' |
584 # 3rd argument sets expansion to False |
586 # 3rd argument sets expansion to False |
585 _kwfwrite(ui, repo, False, *pats, **opts) |
587 _kwfwrite(ui, repo, False, *pats, **opts) |
589 '''Sets up repo as kwrepo for keyword substitution. |
591 '''Sets up repo as kwrepo for keyword substitution. |
590 Overrides file method to return kwfilelog instead of filelog |
592 Overrides file method to return kwfilelog instead of filelog |
591 if file matches user configuration. |
593 if file matches user configuration. |
592 Wraps commit to overwrite configured files with updated |
594 Wraps commit to overwrite configured files with updated |
593 keyword substitutions. |
595 keyword substitutions. |
594 This is done for local repos only, and only if there are |
596 Monkeypatches patch and webcommands.''' |
595 files configured at all for keyword substitution.''' |
|
596 |
597 |
597 try: |
598 try: |
598 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() |
599 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() |
599 or '.hg' in repo.root.split(os.sep) |
600 or '.hg' in repo.root.split(os.sep) |
600 or repo._url.startswith('bundle:')): |
601 or repo._url.startswith('bundle:')): |