hgkw/keyword.py
author Christian Ebert <blacktrash@gmx.net>
Thu, 18 Jan 2007 01:50:18 +0100
branchkwmap-templates
changeset 110 b0b85b383f36
parent 109 b2cc6a8d4a18
child 111 94315baadcaf
permissions -rw-r--r--
Move all that can be done only once per repo into reposetup Actually kwrepo is not set up if there aren't any files configured for keyword substitution. Stuff that now is done at reposetup and not at every filelog init or hook: 1) filename matching function 2) compilation of keyword regex 3) templates and changeset templater kwtemplater as an appended class should prevent namespace conflicts.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     1
# keyword.py - keyword expansion for mercurial
82
9bf0f7db5928 Add keyword; comment backwards compatible import
Christian Ebert <blacktrash@gmx.net>
parents: 81
diff changeset
     2
# $Id$
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     3
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     4
'''keyword expansion hack against the grain of a DSCM
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     5
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     6
This extension lets you expand RCS/CVS-like keywords in a Mercurial
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     7
repository.
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     8
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
     9
There are many good reasons why this is not needed in a distributed
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    10
SCM, still it may be useful in very small projects based on single
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    11
files (like LaTeX packages), that are mostly addressed to an audience
52
7783eb22de30 Make inheritance clearer in size() and add()
Christian Ebert <blacktrash@gmx.net>
parents: 51
diff changeset
    12
not running a version control system.
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    13
102
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
    14
For in-depth discussion refer to
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
    15
<http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>.
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
    16
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    17
You can either use the default cvs-like keywords or provide your
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    18
own in hgrc.
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    19
108
25dac950a1f0 Document reposetup; recommend loading on per-repo basis
Christian Ebert <blacktrash@gmx.net>
parents: 107
diff changeset
    20
It is recommended to enable this extension on a per-repo basis only.
25dac950a1f0 Document reposetup; recommend loading on per-repo basis
Christian Ebert <blacktrash@gmx.net>
parents: 107
diff changeset
    21
You can still configure keywordmaps globally.
25dac950a1f0 Document reposetup; recommend loading on per-repo basis
Christian Ebert <blacktrash@gmx.net>
parents: 107
diff changeset
    22
103
e086f7eb0198 Emergency brake against multiline expansion
Christian Ebert <blacktrash@gmx.net>
parents: 102
diff changeset
    23
Expansions spanning more than one line are truncated to their first line.
e086f7eb0198 Emergency brake against multiline expansion
Christian Ebert <blacktrash@gmx.net>
parents: 102
diff changeset
    24
Incremental expansion (like CVS' $Log$) is not supported.
e086f7eb0198 Emergency brake against multiline expansion
Christian Ebert <blacktrash@gmx.net>
parents: 102
diff changeset
    25
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    26
Default $keywords$ and their $keyword: substition $ are:
69
4c5d9635b517 Pure extension by inserting keyword expansion localrepo.localrepository.commit
Christian Ebert <blacktrash@gmx.net>
parents: 68
diff changeset
    27
    Revision: changeset id
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    28
    Author:   username
90
2e930f842242 Very CVS-like format
Christian Ebert <blacktrash@gmx.net>
parents: 89
diff changeset
    29
    Date:     %Y/%m/%d %H:%M:%S [UTC]
69
4c5d9635b517 Pure extension by inserting keyword expansion localrepo.localrepository.commit
Christian Ebert <blacktrash@gmx.net>
parents: 68
diff changeset
    30
    RCSFile:  basename,v
4c5d9635b517 Pure extension by inserting keyword expansion localrepo.localrepository.commit
Christian Ebert <blacktrash@gmx.net>
parents: 68
diff changeset
    31
    Source:   /path/to/basename,v
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    32
    Id:       basename,v csetid %Y/%m/%d %H:%M:%S username
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    33
    Header:   /path/to/basename,v csetid %Y/%m/%d %H:%M:%S username
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    34
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    35
Simple setup in hgrc:
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    36
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    37
    # enable extension
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    38
    hgext.keyword = /full/path/to/script
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    39
    # or, if script in hgext folder:
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    40
    # hgext.keyword =
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    41
    
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    42
    # filename patterns for expansion are configured in this section
107
fe4a0495eca8 Implement configurable exclusion of files from expansion
Christian Ebert <blacktrash@gmx.net>
parents: 106
diff changeset
    43
    # files matching patterns with value 'ignore' are ignored
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    44
    [keyword]
107
fe4a0495eca8 Implement configurable exclusion of files from expansion
Christian Ebert <blacktrash@gmx.net>
parents: 106
diff changeset
    45
    **.py =
fe4a0495eca8 Implement configurable exclusion of files from expansion
Christian Ebert <blacktrash@gmx.net>
parents: 106
diff changeset
    46
    x* = ignore
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    47
    ...
102
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
    48
    # in case you prefer your own keyword maps over the cvs-like defaults:
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    49
    [keywordmaps]
102
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
    50
    HGdate = {date|rfc822date}
103
e086f7eb0198 Emergency brake against multiline expansion
Christian Ebert <blacktrash@gmx.net>
parents: 102
diff changeset
    51
    lastlog = {desc} ## same as {desc|firstline} in this context
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    52
    checked in by = {author}
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    53
    ...
48
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    54
'''
59fedb6b41da add header and start documentation
Christian Ebert <blacktrash@gmx.net>
parents: 47
diff changeset
    55
105
2a8b0a71c2ec Use full power of util.matcher for kwfmatches()
Christian Ebert <blacktrash@gmx.net>
parents: 104
diff changeset
    56
from mercurial.i18n import gettext as _
2a8b0a71c2ec Use full power of util.matcher for kwfmatches()
Christian Ebert <blacktrash@gmx.net>
parents: 104
diff changeset
    57
# above line for backwards compatibility; can be changed to
2a8b0a71c2ec Use full power of util.matcher for kwfmatches()
Christian Ebert <blacktrash@gmx.net>
parents: 104
diff changeset
    58
#   from mercurial.i18n import _
2a8b0a71c2ec Use full power of util.matcher for kwfmatches()
Christian Ebert <blacktrash@gmx.net>
parents: 104
diff changeset
    59
# some day
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    60
from mercurial import context, filelog, revlog
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    61
from mercurial import commands, cmdutil, templater, util
100
4f1129ddbdb8 Just re-bin the node kwarg of the hook, instead of using changelog
Christian Ebert <blacktrash@gmx.net>
parents: 99
diff changeset
    62
from mercurial.node import *
90
2e930f842242 Very CVS-like format
Christian Ebert <blacktrash@gmx.net>
parents: 89
diff changeset
    63
import os.path, re, sys, time
47
0617e7d497f6 Branch standalone extension, including pretxncommit hook function
Christian Ebert <blacktrash@gmx.net>
parents: 44
diff changeset
    64
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    65
deftemplates = {
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    66
        'Revision': '{node|short}',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    67
        'Author': '{author|user}',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    68
        'Date': '{date|utcdate}',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    69
        'RCSFile': '{file|basename},v',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    70
        'Source': '{root}/{file},v',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    71
        'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    72
        'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    73
        }
59
94b26168791d Only 1 all-purpose regex, compiled at load
Christian Ebert <blacktrash@gmx.net>
parents: 58
diff changeset
    74
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    75
def utcdate(date):
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    76
    '''Returns hgdate in cvs-like UTC format.'''
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    77
    return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    78
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    79
def getkwconfig(ui, repo):
107
fe4a0495eca8 Implement configurable exclusion of files from expansion
Christian Ebert <blacktrash@gmx.net>
parents: 106
diff changeset
    80
    inc = [pat for pat, opt in ui.configitems('keyword') if opt != 'ignore']
fe4a0495eca8 Implement configurable exclusion of files from expansion
Christian Ebert <blacktrash@gmx.net>
parents: 106
diff changeset
    81
    if not inc:
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    82
        ui.warn(_('keyword: no filename globs for substitution\n'))
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    83
        return None, None
107
fe4a0495eca8 Implement configurable exclusion of files from expansion
Christian Ebert <blacktrash@gmx.net>
parents: 106
diff changeset
    84
    exc = [pat for pat, opt in ui.configitems('keyword') if opt == 'ignore']
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    85
    return inc, exc
65
188849659487 Unify obtaining filename matchers; only debug messages
Christian Ebert <blacktrash@gmx.net>
parents: 64
diff changeset
    86
92
3c7c187e4001 Init context.filectx only once per file with class kwfilectx
Christian Ebert <blacktrash@gmx.net>
parents: 90
diff changeset
    87
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    88
class kwtemplater(object):
92
3c7c187e4001 Init context.filectx only once per file with class kwfilectx
Christian Ebert <blacktrash@gmx.net>
parents: 90
diff changeset
    89
    '''
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    90
    Sets up keyword templates, corresponding keyword regex, and
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    91
    provides keyword expansion function.
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    92
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    93
    If a repo is configured for keyword substitution, this class
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
    94
    will be set as an (appendix) attribute to the repo.
92
3c7c187e4001 Init context.filectx only once per file with class kwfilectx
Christian Ebert <blacktrash@gmx.net>
parents: 90
diff changeset
    95
    '''
101
98a65d978098 No need to read changelog in show(); node mandatory arg for expand()
Christian Ebert <blacktrash@gmx.net>
parents: 100
diff changeset
    96
    def __init__(self, ui, repo):
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    97
        self.ui = ui
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
    98
        self.repo = repo
106
61afa140949e Only initialize kwtemplater in kwfilelog if needed
Christian Ebert <blacktrash@gmx.net>
parents: 105
diff changeset
    99
        self.templates = dict(ui.configitems('keywordmaps')) or deftemplates
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   100
        self.re_kw = re.compile(r'\$(%s)[^$]*?\$' %
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   101
                '|'.join(re.escape(k) for k in self.templates.keys()))
109
b2cc6a8d4a18 Extend templater.common_filters in kwtemplater
Christian Ebert <blacktrash@gmx.net>
parents: 108
diff changeset
   102
        templater.common_filters['utcdate'] = utcdate
106
61afa140949e Only initialize kwtemplater in kwfilelog if needed
Christian Ebert <blacktrash@gmx.net>
parents: 105
diff changeset
   103
        self.t = cmdutil.changeset_templater(ui, repo, False, '', False)
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   104
101
98a65d978098 No need to read changelog in show(); node mandatory arg for expand()
Christian Ebert <blacktrash@gmx.net>
parents: 100
diff changeset
   105
    def expand(self, mobj, path, node):
102
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
   106
        '''Expands keyword with corresponding template.'''
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   107
        kw = mobj.group(1)
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   108
        template = templater.parsestring(self.templates[kw], quoted=False)
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   109
        self.t.use_template(template)
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   110
        self.ui.pushbuffer()
101
98a65d978098 No need to read changelog in show(); node mandatory arg for expand()
Christian Ebert <blacktrash@gmx.net>
parents: 100
diff changeset
   111
        self.t.show(changenode=node, root=self.repo.root, file=path)
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   112
        kwsub = templater.firstline(self.ui.popbuffer())
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   113
        return '$%s: %s $' % (kw, kwsub)
92
3c7c187e4001 Init context.filectx only once per file with class kwfilectx
Christian Ebert <blacktrash@gmx.net>
parents: 90
diff changeset
   114
42
ba000e29ecf3 Implement near CVS compability with more than one keyword
Christian Ebert <blacktrash@gmx.net>
parents: 41
diff changeset
   115
33
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   116
def reposetup(ui, repo):
108
25dac950a1f0 Document reposetup; recommend loading on per-repo basis
Christian Ebert <blacktrash@gmx.net>
parents: 107
diff changeset
   117
    '''Sets up repo, and filelog especially, as kwrepo and kwfilelog
25dac950a1f0 Document reposetup; recommend loading on per-repo basis
Christian Ebert <blacktrash@gmx.net>
parents: 107
diff changeset
   118
    for keyword substitution.  This is done for local repos only.'''
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   119
    if not repo.local():
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   120
        return
108
25dac950a1f0 Document reposetup; recommend loading on per-repo basis
Christian Ebert <blacktrash@gmx.net>
parents: 107
diff changeset
   121
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   122
    inc, exc = getkwconfig(ui, repo)
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   123
    if not inc:
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   124
        # no files configured for keyword substitution:
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   125
        # no need to burden repo with extra ballast
33
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   126
        return
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   127
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   128
    class kwrepo(repo.__class__):
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   129
        def file(self, f):
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   130
            if f[0] == '/':
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   131
                f = f[1:]
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   132
            return filelog.filelog(self.sopener, f, self, self.revlogversion)
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   133
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   134
    class kwfilelog(filelog.filelog):
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   135
        '''
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   136
        Superclass over filelog to customize it's read, add, cmp methods.
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   137
        Keywords are "stored" unexpanded, and expanded on reading.
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   138
        '''
33
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   139
        def __init__(self, opener, path, repo,
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   140
                     defversion=revlog.REVLOG_DEFAULT_VERSION):
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   141
            super(kwfilelog, self).__init__(opener, path, defversion)
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   142
            self._repo = repo
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   143
            self._path = path
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   144
            # check at init if file configured for keyword substition
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   145
            if not isinstance(repo, int) and repo.kwfmatcher(path):
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   146
                self.kwsub = True
106
61afa140949e Only initialize kwtemplater in kwfilelog if needed
Christian Ebert <blacktrash@gmx.net>
parents: 105
diff changeset
   147
            else:
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   148
                self.kwsub = False
36
b3ace8cc5a33 Change config opt "expand" to accept filename patterns
Christian Ebert <blacktrash@gmx.net>
parents: 34
diff changeset
   149
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   150
        def iskwcandidate(self, data):
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   151
            '''Decides whether to act on keywords.'''
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   152
            return self.kwsub and not util.binary(data)
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   153
33
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   154
        def read(self, node):
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   155
            '''Substitutes keywords when reading filelog.'''
42
ba000e29ecf3 Implement near CVS compability with more than one keyword
Christian Ebert <blacktrash@gmx.net>
parents: 41
diff changeset
   156
            data = super(kwfilelog, self).read(node)
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   157
            if self.iskwcandidate(data):
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   158
                c = context.filectx(self._repo, self._path,
100
4f1129ddbdb8 Just re-bin the node kwarg of the hook, instead of using changelog
Christian Ebert <blacktrash@gmx.net>
parents: 99
diff changeset
   159
                                    fileid=node, filelog=self)
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   160
                return self._repo.kwt.re_kw.sub(lambda m:
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   161
                        self._repo.kwt.expand(m, self._path, c.node()), data)
51
1ecb6ec5d16b Reintroduce simpler kwfilelog.add(); simplify kwfilelog.read()
Christian Ebert <blacktrash@gmx.net>
parents: 50
diff changeset
   162
            return data
42
ba000e29ecf3 Implement near CVS compability with more than one keyword
Christian Ebert <blacktrash@gmx.net>
parents: 41
diff changeset
   163
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   164
        def add(self, text, meta, tr, link, p1=None, p2=None):
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   165
            '''Removes keyword substitutions when adding to filelog.'''
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   166
            if self.iskwcandidate(text):
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   167
                text = self._repo.kwt.re_kw.sub(r'$\1$', text)
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   168
            return super(kwfilelog, self).add(text,
102
393d6f8ea83c More doc, link to KeywordPlan
Christian Ebert <blacktrash@gmx.net>
parents: 101
diff changeset
   169
                            meta, tr, link, p1=p1, p2=p2)
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   170
49
5acfe7dc3086 Override filelog's size(), cmp() as well; remove add()
Christian Ebert <blacktrash@gmx.net>
parents: 48
diff changeset
   171
        def cmp(self, node, text):
78
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   172
            '''Removes keyword substitutions for comparison.'''
474b415433a1 Unexpanded storage hopefully covered now by adding kwfilelog.add (again!)
Christian Ebert <blacktrash@gmx.net>
parents: 77
diff changeset
   173
            if self.iskwcandidate(text):
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   174
                text = self._repo.kwt.re_kw.sub(r'$\1$', text)
71
f7a2a246740c No keyword substitution in cmp(); no overriding of size() ATM
Christian Ebert <blacktrash@gmx.net>
parents: 69
diff changeset
   175
            return super(kwfilelog, self).cmp(node, text)
33
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   176
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   177
    filelog.filelog = kwfilelog
ebb39c6a1476 Add original keyword extension by Thomas Arendsen Hain
Christian Ebert <blacktrash@gmx.net>
parents:
diff changeset
   178
    repo.__class__ = kwrepo
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   179
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   180
    # create filematching function once for repo
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   181
    setattr(repo, 'kwfmatcher',
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   182
            util.matcher(repo.root, inc=inc, exc=['.hg*']+exc)[1])
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   183
    # initialize kwtemplater once for repo
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   184
    setattr(repo, 'kwt', kwtemplater(ui, repo))
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   185
87
c193da9eb3e4 Only extend sys.path if needed
Christian Ebert <blacktrash@gmx.net>
parents: 86
diff changeset
   186
    # make pretxncommit hook import kwmodule regardless of where it's located
88
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   187
    for k, v in sys.modules.iteritems():
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   188
        if v is None:
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   189
            continue
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   190
        if not hasattr(v, '__file__'):
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   191
            continue
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   192
        if v.__file__.startswith(__file__):
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   193
            mod = k
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   194
            break
87
c193da9eb3e4 Only extend sys.path if needed
Christian Ebert <blacktrash@gmx.net>
parents: 86
diff changeset
   195
    else:
88
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   196
        sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   197
        mod = os.path.splitext(os.path.basename(__file__))[0]
ffec227fced3 Module detection cleaner and more reliable
Christian Ebert <blacktrash@gmx.net>
parents: 87
diff changeset
   198
    ui.setconfig('hooks', 'pretxncommit.keyword', 'python:%s.pretxnkw' % mod)
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   199
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   200
    del inc, exc, mod
81
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   201
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   202
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   203
def pretxnkw(ui, repo, hooktype, **args):
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   204
    '''pretxncommit hook that collects candidates for keyword expansion
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   205
    on commit and expands keywords in working dir.'''
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   206
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   207
    cmd, sysargs, globalopts, cmdopts = commands.parse(ui, sys.argv[1:])[1:]
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   208
    if repr(cmd).split()[1] in ('tag', 'import_'):
99
f881ecdcdec9 Same as for hardcoded branch: omit hooktype test, return w/o explicit value
Christian Ebert <blacktrash@gmx.net>
parents: 97
diff changeset
   209
        return
81
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   210
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   211
    files, match, anypats = cmdutil.matchpats(repo, sysargs, cmdopts)
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   212
    modified, added = repo.status(files=files, match=match)[:2]
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   213
    candidates = [f for f in modified+added if repo.kwfmatcher(f)]
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   214
    if not candidates:
99
f881ecdcdec9 Same as for hardcoded branch: omit hooktype test, return w/o explicit value
Christian Ebert <blacktrash@gmx.net>
parents: 97
diff changeset
   215
        return
81
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   216
101
98a65d978098 No need to read changelog in show(); node mandatory arg for expand()
Christian Ebert <blacktrash@gmx.net>
parents: 100
diff changeset
   217
    node = bin(args['node'])
95
9e4cbe64fb4f Implement custom keyword map templates in hgrc
Christian Ebert <blacktrash@gmx.net>
parents: 93
diff changeset
   218
    for f in candidates:
81
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   219
        data = repo.wfile(f).read()
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   220
        if not util.binary(data):
110
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   221
            data, kwct = repo.kwt.re_kw.subn(lambda m:
b0b85b383f36 Move all that can be done only once per repo into reposetup
Christian Ebert <blacktrash@gmx.net>
parents: 109
diff changeset
   222
                    repo.kwt.expand(m, f, node), data)
81
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   223
            if kwct:
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   224
                ui.debug(_('overwriting %s expanding keywords\n' % f))
fd5d3a974ea7 Implement self initializing pretxncommit hook
Christian Ebert <blacktrash@gmx.net>
parents: 80
diff changeset
   225
                repo.wfile(f, 'w').write(data)