Ejemplo n.º 1
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.
    Overrides file method to return kwfilelog instead of filelog
    if file matches user configuration.
    Wraps commit to overwrite configured files with updated
    keyword substitutions.
    Monkeypatches patch and webcommands.'''

    try:
        if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
                or '.hg' in util.splitpath(repo.root)
                or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    inc, exc = [], ['.hg*']
    for pat, opt in ui.configitems('keyword'):
        if opt != 'ignore':
            inc.append(pat)
        else:
            exc.append(pat)
    if not inc:
        return

    kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.svfs, kwt, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self, *args, **opts):
            # use custom commitctx for user commands
            # other extensions can still wrap repo.commitctx directly
            self.commitctx = self.kwcommitctx
            try:
                return super(kwrepo, self).commit(*args, **opts)
            finally:
                del self.commitctx

        def kwcommitctx(self, ctx, error=False):
            n = super(kwrepo, self).commitctx(ctx, error)
            # no lock needed, only called from repo.commit() which already locks
            if not kwt.postcommit:
                restrict = kwt.restrict
                kwt.restrict = True
                kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
                              False, True)
                kwt.restrict = restrict
            return n

        def rollback(self, dryrun=False, force=False):
            wlock = self.wlock()
            try:
                if not dryrun:
                    changed = self['.'].files()
                ret = super(kwrepo, self).rollback(dryrun, force)
                if not dryrun:
                    ctx = self['.']
                    modified, added = _preselect(ctx.status(), changed)
                    kwt.overwrite(ctx, modified, True, True)
                    kwt.overwrite(ctx, added, True, False)
                return ret
            finally:
                wlock.release()

    # monkeypatches
    def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
        '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
        rejects or conflicts due to expanded keywords in working dir.'''
        orig(self, ui, gp, backend, store, eolmode)
        # shrink keywords read from working dir
        self.lines = kwt.shrinklines(self.fname, self.lines)

    def kwdiff(orig, *args, **kwargs):
        '''Monkeypatch patch.diff to avoid expansion.'''
        kwt.restrict = True
        return orig(*args, **kwargs)

    def kwweb_skip(orig, web, req, tmpl):
        '''Wraps webcommands.x turning off keyword expansion.'''
        kwt.match = util.never
        return orig(web, req, tmpl)

    def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts):
        '''Wraps cmdutil.amend expanding keywords after amend.'''
        wlock = repo.wlock()
        try:
            kwt.postcommit = True
            newid = orig(ui, repo, commitfunc, old, extra, pats, opts)
            if newid != old.node():
                ctx = repo[newid]
                kwt.restrict = True
                kwt.overwrite(ctx, ctx.files(), False, True)
                kwt.restrict = False
            return newid
        finally:
            wlock.release()

    def kw_copy(orig, ui, repo, pats, opts, rename=False):
        '''Wraps cmdutil.copy so that copy/rename destinations do not
        contain expanded keywords.
        Note that the source of a regular file destination may also be a
        symlink:
        hg cp sym x                -> x is symlink
        cp sym x; hg cp -A sym x   -> x is file (maybe expanded keywords)
        For the latter we have to follow the symlink to find out whether its
        target is configured for expansion and we therefore must unexpand the
        keywords in the destination.'''
        wlock = repo.wlock()
        try:
            orig(ui, repo, pats, opts, rename)
            if opts.get('dry_run'):
                return
            wctx = repo[None]
            cwd = repo.getcwd()

            def haskwsource(dest):
                '''Returns true if dest is a regular file and configured for
                expansion or a symlink which points to a file configured for
                expansion. '''
                source = repo.dirstate.copied(dest)
                if 'l' in wctx.flags(source):
                    source = pathutil.canonpath(repo.root, cwd,
                                                os.path.realpath(source))
                return kwt.match(source)

            candidates = [
                f for f in repo.dirstate.copies()
                if 'l' not in wctx.flags(f) and haskwsource(f)
            ]
            kwt.overwrite(wctx, candidates, False, False)
        finally:
            wlock.release()

    def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
        '''Wraps record.dorecord expanding keywords after recording.'''
        wlock = repo.wlock()
        try:
            # record returns 0 even when nothing has changed
            # therefore compare nodes before and after
            kwt.postcommit = True
            ctx = repo['.']
            wstatus = ctx.status()
            ret = orig(ui, repo, commitfunc, *pats, **opts)
            recctx = repo['.']
            if ctx != recctx:
                modified, added = _preselect(wstatus, recctx.files())
                kwt.restrict = False
                kwt.overwrite(recctx, modified, False, True)
                kwt.overwrite(recctx, added, False, True, True)
                kwt.restrict = True
            return ret
        finally:
            wlock.release()

    def kwfilectx_cmp(orig, self, fctx):
        # keyword affects data size, comparing wdir and filelog size does
        # not make sense
        if (fctx._filerev is None and
            (self._repo._encodefilterpats or kwt.match(fctx.path())
             and 'l' not in fctx.flags() or self.size() - 4 == fctx.size())
                or self.size() == fctx.size()):
            return self._filelog.cmp(self._filenode, fctx.data())
        return True

    extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp)
    extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
    extensions.wrapfunction(patch, 'diff', kwdiff)
    extensions.wrapfunction(cmdutil, 'amend', kw_amend)
    extensions.wrapfunction(cmdutil, 'copy', kw_copy)
    extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord)
    for c in 'annotate changeset rev filediff diff'.split():
        extensions.wrapfunction(webcommands, c, kwweb_skip)
    repo.__class__ = kwrepo
Ejemplo n.º 2
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.'''

    try:
        if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
            or '.hg' in util.splitpath(repo.root)
            or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    inc, exc = [], ['.hg*']
    for pat, opt in ui.configitems('keyword'):
        if opt != 'ignore':
            inc.append(pat)
        else:
            exc.append(pat)
    if not inc:
        return

    kwt = kwtemplater(ui, repo, inc, exc)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.svfs, kwt, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self, *args, **opts):
            # use custom commitctx for user commands
            # other extensions can still wrap repo.commitctx directly
            self.commitctx = self.kwcommitctx
            try:
                return super(kwrepo, self).commit(*args, **opts)
            finally:
                del self.commitctx

        def kwcommitctx(self, ctx, error=False):
            n = super(kwrepo, self).commitctx(ctx, error)
            # no lock needed, only called from repo.commit() which already locks
            if not kwt.postcommit:
                restrict = kwt.restrict
                kwt.restrict = True
                kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
                              False, True)
                kwt.restrict = restrict
            return n

        def rollback(self, dryrun=False, force=False):
            with self.wlock():
                origrestrict = kwt.restrict
                try:
                    if not dryrun:
                        changed = self['.'].files()
                    ret = super(kwrepo, self).rollback(dryrun, force)
                    if not dryrun:
                        ctx = self['.']
                        modified, added = _preselect(ctx.status(), changed)
                        kwt.restrict = False
                        kwt.overwrite(ctx, modified, True, True)
                        kwt.overwrite(ctx, added, True, False)
                    return ret
                finally:
                    kwt.restrict = origrestrict

    repo.__class__ = kwrepo
    repo._keywordkwt = kwt
Ejemplo n.º 3
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.
    Overrides file method to return kwfilelog instead of filelog
    if file matches user configuration.
    Wraps commit to overwrite configured files with updated
    keyword substitutions.
    Monkeypatches patch and webcommands.'''

    try:
        if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
            or '.hg' in util.splitpath(repo.root)
            or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    inc, exc = [], ['.hg*']
    for pat, opt in ui.configitems('keyword'):
        if opt != 'ignore':
            inc.append(pat)
        else:
            exc.append(pat)
    if not inc:
        return

    kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.sopener, kwt, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self, *args, **opts):
            # use custom commitctx for user commands
            # other extensions can still wrap repo.commitctx directly
            self.commitctx = self.kwcommitctx
            try:
                return super(kwrepo, self).commit(*args, **opts)
            finally:
                del self.commitctx

        def kwcommitctx(self, ctx, error=False):
            n = super(kwrepo, self).commitctx(ctx, error)
            # no lock needed, only called from repo.commit() which already locks
            if not kwt.postcommit:
                restrict = kwt.restrict
                kwt.restrict = True
                kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
                              False, True)
                kwt.restrict = restrict
            return n

        def rollback(self, dryrun=False, force=False):
            wlock = self.wlock()
            try:
                if not dryrun:
                    changed = self['.'].files()
                ret = super(kwrepo, self).rollback(dryrun, force)
                if not dryrun:
                    ctx = self['.']
                    modified, added = _preselect(self[None].status(), changed)
                    kwt.overwrite(ctx, modified, True, True)
                    kwt.overwrite(ctx, added, True, False)
                return ret
            finally:
                wlock.release()

    # monkeypatches
    def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
        '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
        rejects or conflicts due to expanded keywords in working dir.'''
        orig(self, ui, gp, backend, store, eolmode)
        # shrink keywords read from working dir
        self.lines = kwt.shrinklines(self.fname, self.lines)

    def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
                opts=None, prefix=''):
        '''Monkeypatch patch.diff to avoid expansion.'''
        kwt.restrict = True
        return orig(repo, node1, node2, match, changes, opts, prefix)

    def kwweb_skip(orig, web, req, tmpl):
        '''Wraps webcommands.x turning off keyword expansion.'''
        kwt.match = util.never
        return orig(web, req, tmpl)

    def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts):
        '''Wraps cmdutil.amend expanding keywords after amend.'''
        wlock = repo.wlock()
        try:
            kwt.postcommit = True
            newid = orig(ui, repo, commitfunc, old, extra, pats, opts)
            if newid != old.node():
                ctx = repo[newid]
                kwt.restrict = True
                kwt.overwrite(ctx, ctx.files(), False, True)
                kwt.restrict = False
            return newid
        finally:
            wlock.release()

    def kw_copy(orig, ui, repo, pats, opts, rename=False):
        '''Wraps cmdutil.copy so that copy/rename destinations do not
        contain expanded keywords.
        Note that the source of a regular file destination may also be a
        symlink:
        hg cp sym x                -> x is symlink
        cp sym x; hg cp -A sym x   -> x is file (maybe expanded keywords)
        For the latter we have to follow the symlink to find out whether its
        target is configured for expansion and we therefore must unexpand the
        keywords in the destination.'''
        wlock = repo.wlock()
        try:
            orig(ui, repo, pats, opts, rename)
            if opts.get('dry_run'):
                return
            wctx = repo[None]
            cwd = repo.getcwd()

            def haskwsource(dest):
                '''Returns true if dest is a regular file and configured for
                expansion or a symlink which points to a file configured for
                expansion. '''
                source = repo.dirstate.copied(dest)
                if 'l' in wctx.flags(source):
                    source = pathutil.canonpath(repo.root, cwd,
                                               os.path.realpath(source))
                return kwt.match(source)

            candidates = [f for f in repo.dirstate.copies() if
                          'l' not in wctx.flags(f) and haskwsource(f)]
            kwt.overwrite(wctx, candidates, False, False)
        finally:
            wlock.release()

    def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
        '''Wraps record.dorecord expanding keywords after recording.'''
        wlock = repo.wlock()
        try:
            # record returns 0 even when nothing has changed
            # therefore compare nodes before and after
            kwt.postcommit = True
            ctx = repo['.']
            wstatus = repo[None].status()
            ret = orig(ui, repo, commitfunc, *pats, **opts)
            recctx = repo['.']
            if ctx != recctx:
                modified, added = _preselect(wstatus, recctx.files())
                kwt.restrict = False
                kwt.overwrite(recctx, modified, False, True)
                kwt.overwrite(recctx, added, False, True, True)
                kwt.restrict = True
            return ret
        finally:
            wlock.release()

    def kwfilectx_cmp(orig, self, fctx):
        # keyword affects data size, comparing wdir and filelog size does
        # not make sense
        if (fctx._filerev is None and
            (self._repo._encodefilterpats or
             kwt.match(fctx.path()) and 'l' not in fctx.flags() or
             self.size() - 4 == fctx.size()) or
            self.size() == fctx.size()):
            return self._filelog.cmp(self._filenode, fctx.data())
        return True

    extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp)
    extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
    extensions.wrapfunction(patch, 'diff', kw_diff)
    extensions.wrapfunction(cmdutil, 'amend', kw_amend)
    extensions.wrapfunction(cmdutil, 'copy', kw_copy)
    for c in 'annotate changeset rev filediff diff'.split():
        extensions.wrapfunction(webcommands, c, kwweb_skip)
    for name in recordextensions.split():
        try:
            record = extensions.find(name)
            extensions.wrapfunction(record, 'dorecord', kw_dorecord)
        except KeyError:
            pass

    repo.__class__ = kwrepo
Ejemplo n.º 4
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.
    Overrides file method to return kwfilelog instead of filelog
    if file matches user configuration.
    Wraps commit to overwrite configured files with updated
    keyword substitutions.
    Monkeypatches patch and webcommands.'''

    try:
        if (not repo.local() or not kwtools['inc']
            or kwtools['hgcmd'] in nokwcommands.split()
            or '.hg' in util.splitpath(repo.root)
            or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    kwtools['templater'] = kwt = kwtemplater(ui, repo)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.sopener, kwt, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self, *args, **opts):
            # use custom commitctx for user commands
            # other extensions can still wrap repo.commitctx directly
            self.commitctx = self.kwcommitctx
            try:
                return super(kwrepo, self).commit(*args, **opts)
            finally:
                del self.commitctx

        def kwcommitctx(self, ctx, error=False):
            wlock = lock = None
            try:
                wlock = self.wlock()
                lock = self.lock()
                # store and postpone commit hooks
                commithooks = {}
                for name, cmd in ui.configitems('hooks'):
                    if name.split('.', 1)[0] == 'commit':
                        commithooks[name] = cmd
                        ui.setconfig('hooks', name, None)
                if commithooks:
                    # store parents for commit hooks
                    p1, p2 = ctx.p1(), ctx.p2()
                    xp1, xp2 = p1.hex(), p2 and p2.hex() or ''

                n = super(kwrepo, self).commitctx(ctx, error)

                kwt.overwrite(n, True, None)
                if commithooks:
                    for name, cmd in commithooks.iteritems():
                        ui.setconfig('hooks', name, cmd)
                    self.hook('commit', node=n, parent1=xp1, parent2=xp2)
                return n
            finally:
                release(lock, wlock)

    # monkeypatches
    def kwpatchfile_init(orig, self, ui, fname, opener,
                         missing=False, eol=None):
        '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
        rejects or conflicts due to expanded keywords in working dir.'''
        orig(self, ui, fname, opener, missing, eol)
        # shrink keywords read from working dir
        self.lines = kwt.shrinklines(self.fname, self.lines)

    def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
                opts=None):
        '''Monkeypatch patch.diff to avoid expansion except when
        comparing against working dir.'''
        if node2 is not None:
            kwt.match = util.never
        elif node1 is not None and node1 != repo['.'].node():
            kwt.restrict = True
        return orig(repo, node1, node2, match, changes, opts)

    def kwweb_skip(orig, web, req, tmpl):
        '''Wraps webcommands.x turning off keyword expansion.'''
        kwt.match = util.never
        return orig(web, req, tmpl)

    repo.__class__ = kwrepo

    extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
    if not kwt.restrict:
        extensions.wrapfunction(patch, 'diff', kw_diff)
    for c in 'annotate changeset rev filediff diff'.split():
        extensions.wrapfunction(webcommands, c, kwweb_skip)
Ejemplo n.º 5
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.
    Overrides file method to return kwfilelog instead of filelog
    if file matches user configuration.
    Wraps commit to overwrite configured files with updated
    keyword substitutions.
    Monkeypatches patch and webcommands.'''

    try:
        if (not repo.local() or not kwtools['inc']
                or kwtools['hgcmd'] in nokwcommands.split()
                or '.hg' in util.splitpath(repo.root)
                or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    kwtools['templater'] = kwt = kwtemplater(ui, repo)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.sopener, kwt, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self, *args, **opts):
            # use custom commitctx for user commands
            # other extensions can still wrap repo.commitctx directly
            self.commitctx = self.kwcommitctx
            try:
                return super(kwrepo, self).commit(*args, **opts)
            finally:
                del self.commitctx

        def kwcommitctx(self, ctx, error=False):
            wlock = lock = None
            try:
                wlock = self.wlock()
                lock = self.lock()
                n = super(kwrepo, self).commitctx(ctx, error)
                kwt.overwrite(n, True, None)
                return n
            finally:
                release(lock, wlock)

    # monkeypatches
    def kwpatchfile_init(orig,
                         self,
                         ui,
                         fname,
                         opener,
                         missing=False,
                         eol=None):
        '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
        rejects or conflicts due to expanded keywords in working dir.'''
        orig(self, ui, fname, opener, missing, eol)
        # shrink keywords read from working dir
        self.lines = kwt.shrinklines(self.fname, self.lines)

    def kw_diff(orig,
                repo,
                node1=None,
                node2=None,
                match=None,
                changes=None,
                opts=None):
        '''Monkeypatch patch.diff to avoid expansion except when
        comparing against working dir.'''
        if node2 is not None:
            kwt.match = util.never
        elif node1 is not None and node1 != repo['.'].node():
            kwt.restrict = True
        return orig(repo, node1, node2, match, changes, opts)

    def kwweb_skip(orig, web, req, tmpl):
        '''Wraps webcommands.x turning off keyword expansion.'''
        kwt.match = util.never
        return orig(web, req, tmpl)

    repo.__class__ = kwrepo

    extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
    if not kwt.restrict:
        extensions.wrapfunction(patch, 'diff', kw_diff)
    for c in 'annotate changeset rev filediff diff'.split():
        extensions.wrapfunction(webcommands, c, kwweb_skip)
Ejemplo n.º 6
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.
    Overrides file method to return kwfilelog instead of filelog
    if file matches user configuration.
    Wraps commit to overwrite configured files with updated
    keyword substitutions.
    This is done for local repos only, and only if there are
    files configured at all for keyword substitution.'''

    try:
        if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
                or '.hg' in util.splitpath(repo.root)
                or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    inc, exc = [], ['.hg*']
    for pat, opt in ui.configitems('keyword'):
        if opt != 'ignore':
            inc.append(pat)
        else:
            exc.append(pat)
    if not inc:
        return

    kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.sopener, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self,
                   files=None,
                   text='',
                   user=None,
                   date=None,
                   match=util.always,
                   force=False,
                   force_editor=False,
                   p1=None,
                   p2=None,
                   extra={},
                   empty_ok=False):
            wlock = lock = None
            _p1 = _p2 = None
            try:
                wlock = self.wlock()
                lock = self.lock()
                # store and postpone commit hooks
                commithooks = {}
                for name, cmd in ui.configitems('hooks'):
                    if name.split('.', 1)[0] == 'commit':
                        commithooks[name] = cmd
                        ui.setconfig('hooks', name, None)
                if commithooks:
                    # store parents for commit hook environment
                    if p1 is None:
                        _p1, _p2 = repo.dirstate.parents()
                    else:
                        _p1, _p2 = p1, p2 or nullid
                    _p1 = hex(_p1)
                    if _p2 == nullid:
                        _p2 = ''
                    else:
                        _p2 = hex(_p2)

                node = super(kwrepo, self).commit(files=files,
                                                  text=text,
                                                  user=user,
                                                  date=date,
                                                  match=match,
                                                  force=force,
                                                  force_editor=force_editor,
                                                  p1=p1,
                                                  p2=p2,
                                                  extra=extra,
                                                  empty_ok=empty_ok)

                # restore commit hooks
                for name, cmd in commithooks.iteritems():
                    ui.setconfig('hooks', name, cmd)
                if node is not None:
                    kwt.overwrite(node=node)
                    repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
                return node
            finally:
                del wlock, lock

    repo.__class__ = kwrepo
    patch.patchfile.__init__ = _kwpatchfile_init
    patch.diff = _kw_diff
    webcommands.changeset = webcommands.rev = _kwweb_changeset
    webcommands.filediff = webcommands.diff = _kwweb_filediff
Ejemplo n.º 7
0
def reposetup(ui, repo):
    '''Sets up repo as kwrepo for keyword substitution.
    Overrides file method to return kwfilelog instead of filelog
    if file matches user configuration.
    Wraps commit to overwrite configured files with updated
    keyword substitutions.
    This is done for local repos only, and only if there are
    files configured at all for keyword substitution.'''

    try:
        if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
            or '.hg' in util.splitpath(repo.root)
            or repo._url.startswith('bundle:')):
            return
    except AttributeError:
        pass

    inc, exc = [], ['.hg*']
    for pat, opt in ui.configitems('keyword'):
        if opt != 'ignore':
            inc.append(pat)
        else:
            exc.append(pat)
    if not inc:
        return

    kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.sopener, f)

        def wread(self, filename):
            data = super(kwrepo, self).wread(filename)
            return kwt.wread(filename, data)

        def commit(self, files=None, text='', user=None, date=None,
                   match=util.always, force=False, force_editor=False,
                   p1=None, p2=None, extra={}, empty_ok=False):
            wlock = lock = None
            _p1 = _p2 = None
            try:
                wlock = self.wlock()
                lock = self.lock()
                # store and postpone commit hooks
                commithooks = {}
                for name, cmd in ui.configitems('hooks'):
                    if name.split('.', 1)[0] == 'commit':
                        commithooks[name] = cmd
                        ui.setconfig('hooks', name, None)
                if commithooks:
                    # store parents for commit hook environment
                    if p1 is None:
                        _p1, _p2 = repo.dirstate.parents()
                    else:
                        _p1, _p2 = p1, p2 or nullid
                    _p1 = hex(_p1)
                    if _p2 == nullid:
                        _p2 = ''
                    else:
                        _p2 = hex(_p2)

                node = super(kwrepo,
                             self).commit(files=files, text=text, user=user,
                                          date=date, match=match, force=force,
                                          force_editor=force_editor,
                                          p1=p1, p2=p2, extra=extra,
                                          empty_ok=empty_ok)

                # restore commit hooks
                for name, cmd in commithooks.iteritems():
                    ui.setconfig('hooks', name, cmd)
                if node is not None:
                    kwt.overwrite(node=node)
                    repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
                return node
            finally:
                del wlock, lock

    repo.__class__ = kwrepo
    patch.patchfile.__init__ = _kwpatchfile_init
    patch.diff = _kw_diff
    webcommands.changeset = webcommands.rev = _kwweb_changeset
    webcommands.filediff = webcommands.diff = _kwweb_filediff