# HG changeset patch # User Matt Harbison # Date 2019-12-07 01:40:02 # Node ID e685fac56693490178cfdc5edd067666dc082f41 # Parent ac72e17457e588c530a8a5814a9aefb4f992e7a8 match: resolve filesets against the passed `cwd`, not the current one This allows filesets to be resolved relative to `repo.root`, the same as other patterns are since f02d3c0eed18. The current example in contrib/ wasn't working from the tests directory because of this. Differential Revision: https://phab.mercurial-scm.org/D7570 diff --git a/hgext/highlight/__init__.py b/hgext/highlight/__init__.py --- a/hgext/highlight/__init__.py +++ b/hgext/highlight/__init__.py @@ -52,7 +52,7 @@ def pygmentize(web, field, fctx, tmpl): filenameonly = web.configbool(b'web', b'highlightonlymatchfilename', False) ctx = fctx.changectx() - m = ctx.matchfileset(expr) + m = ctx.matchfileset(fctx.repo().root, expr) if m(fctx.path()): highlight.pygmentize( field, fctx, style, tmpl, guessfilenameonly=filenameonly diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -200,8 +200,8 @@ class basectx(object): def mutable(self): return self.phase() > phases.public - def matchfileset(self, expr, badfn=None): - return fileset.match(self, expr, badfn=badfn) + def matchfileset(self, cwd, expr, badfn=None): + return fileset.match(self, cwd, expr, badfn=badfn) def obsolete(self): """True if the changeset is obsolete""" @@ -328,11 +328,14 @@ class basectx(object): default=b'glob', listsubrepos=False, badfn=None, + cwd=None, ): r = self._repo + if not cwd: + cwd = r.getcwd() return matchmod.match( r.root, - r.getcwd(), + cwd, pats, include, exclude, @@ -1694,15 +1697,18 @@ class workingctx(committablectx): default=b'glob', listsubrepos=False, badfn=None, + cwd=None, ): r = self._repo + if not cwd: + cwd = r.getcwd() # Only a case insensitive filesystem needs magic to translate user input # to actual case in the filesystem. icasefs = not util.fscasesensitive(r.root) return matchmod.match( r.root, - r.getcwd(), + cwd, pats, include, exclude, diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -1171,7 +1171,7 @@ def debugfileset(ui, repo, expr, **opts) files.update(ctx.files()) files.update(ctx.substate) - m = ctx.matchfileset(expr) + m = ctx.matchfileset(repo.getcwd(), expr) if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose): ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n') for f in sorted(files): diff --git a/mercurial/fileset.py b/mercurial/fileset.py --- a/mercurial/fileset.py +++ b/mercurial/fileset.py @@ -520,29 +520,30 @@ methods = { class matchctx(object): - def __init__(self, basectx, ctx, badfn=None): + def __init__(self, basectx, ctx, cwd, badfn=None): self._basectx = basectx self.ctx = ctx self._badfn = badfn self._match = None self._status = None + self.cwd = cwd def narrowed(self, match): """Create matchctx for a sub-tree narrowed by the given matcher""" - mctx = matchctx(self._basectx, self.ctx, self._badfn) + mctx = matchctx(self._basectx, self.ctx, self.cwd, self._badfn) mctx._match = match # leave wider status which we don't have to care mctx._status = self._status return mctx def switch(self, basectx, ctx): - mctx = matchctx(basectx, ctx, self._badfn) + mctx = matchctx(basectx, ctx, self.cwd, self._badfn) mctx._match = self._match return mctx def withstatus(self, keys): """Create matchctx which has precomputed status specified by the keys""" - mctx = matchctx(self._basectx, self.ctx, self._badfn) + mctx = matchctx(self._basectx, self.ctx, self.cwd, self._badfn) mctx._match = self._match mctx._buildstatus(keys) return mctx @@ -560,7 +561,7 @@ class matchctx(object): return self._status def matcher(self, patterns): - return self.ctx.match(patterns, badfn=self._badfn) + return self.ctx.match(patterns, badfn=self._badfn, cwd=self.cwd) def predicate(self, predfn, predrepr=None, cache=False): """Create a matcher to select files by predfn(filename)""" @@ -617,12 +618,12 @@ class matchctx(object): return matchmod.never(badfn=self._badfn) -def match(ctx, expr, badfn=None): +def match(ctx, cwd, expr, badfn=None): """Create a matcher for a single fileset expression""" tree = filesetlang.parse(expr) tree = filesetlang.analyze(tree) tree = filesetlang.optimize(tree) - mctx = matchctx(ctx.p1(), ctx, badfn=badfn) + mctx = matchctx(ctx.p1(), ctx, cwd, badfn=badfn) return getmatch(mctx, tree) diff --git a/mercurial/match.py b/mercurial/match.py --- a/mercurial/match.py +++ b/mercurial/match.py @@ -57,7 +57,7 @@ def _rematcher(regex): return m.match -def _expandsets(kindpats, ctx=None, listsubrepos=False, badfn=None): +def _expandsets(cwd, kindpats, ctx=None, listsubrepos=False, badfn=None): '''Returns the kindpats list with the 'set' patterns expanded to matchers''' matchers = [] other = [] @@ -68,11 +68,11 @@ def _expandsets(kindpats, ctx=None, list raise error.ProgrammingError( b"fileset expression with no context" ) - matchers.append(ctx.matchfileset(pat, badfn=badfn)) + matchers.append(ctx.matchfileset(cwd, pat, badfn=badfn)) if listsubrepos: for subpath in ctx.substate: - sm = ctx.sub(subpath).matchfileset(pat, badfn=badfn) + sm = ctx.sub(subpath).matchfileset(cwd, pat, badfn=badfn) pm = prefixdirmatcher(subpath, sm, badfn=badfn) matchers.append(pm) @@ -117,11 +117,11 @@ def _kindpatsalwaysmatch(kindpats): def _buildkindpatsmatcher( - matchercls, root, kindpats, ctx=None, listsubrepos=False, badfn=None + matchercls, root, cwd, kindpats, ctx=None, listsubrepos=False, badfn=None, ): matchers = [] fms, kindpats = _expandsets( - kindpats, ctx=ctx, listsubrepos=listsubrepos, badfn=badfn + cwd, kindpats, ctx=ctx, listsubrepos=listsubrepos, badfn=badfn, ) if kindpats: m = matchercls(root, kindpats, badfn=badfn) @@ -261,6 +261,7 @@ def match( m = _buildkindpatsmatcher( patternmatcher, root, + cwd, kindpats, ctx=ctx, listsubrepos=listsubrepos, @@ -276,6 +277,7 @@ def match( im = _buildkindpatsmatcher( includematcher, root, + cwd, kindpats, ctx=ctx, listsubrepos=listsubrepos, @@ -287,6 +289,7 @@ def match( em = _buildkindpatsmatcher( includematcher, root, + cwd, kindpats, ctx=ctx, listsubrepos=listsubrepos, diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -355,7 +355,7 @@ class abstractsubrepo(object): """return file flags""" return b'' - def matchfileset(self, expr, badfn=None): + def matchfileset(self, cwd, expr, badfn=None): """Resolve the fileset expression for this repo""" return matchmod.never(badfn=badfn) @@ -896,20 +896,20 @@ class hgsubrepo(abstractsubrepo): return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt, subrepos) @annotatesubrepoerror - def matchfileset(self, expr, badfn=None): + def matchfileset(self, cwd, expr, badfn=None): if self._ctx.rev() is None: ctx = self._repo[None] else: rev = self._state[1] ctx = self._repo[rev] - matchers = [ctx.matchfileset(expr, badfn=badfn)] + matchers = [ctx.matchfileset(cwd, expr, badfn=badfn)] for subpath in ctx.substate: sub = ctx.sub(subpath) try: - sm = sub.matchfileset(expr, badfn=badfn) + sm = sub.matchfileset(cwd, expr, badfn=badfn) pm = matchmod.prefixdirmatcher(subpath, sm, badfn=badfn) matchers.append(pm) except error.LookupError: diff --git a/tests/test-fix.t b/tests/test-fix.t --- a/tests/test-fix.t +++ b/tests/test-fix.t @@ -1335,24 +1335,20 @@ reasonable with that. Apparently fixing p1() and its descendants doesn't include wdir() unless explicitly stated. -BROKEN: fileset matches aren't relative to repo.root for commits - $ hg fix -r '.::' $ hg cat -r . ../quux quux $ hg cat -r tip ../quux - quux + fs: $TESTTMP/subprocesscwd $ cat ../quux quux Clean files are not fixed unless explicitly named $ echo 'dirty' > ../quux -BROKEN: fileset matches aren't relative to repo.root for wdir - $ hg fix --working-dir $ cat ../quux - dirty + fs: $TESTTMP/subprocesscwd $ cd ../..