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
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
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
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)
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)
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