Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/sparse.py @ 33320:153456f02426
sparse: move function for resolving sparse matcher into core
As part of the move, the function arguments changed so revs are
passed as a list instead of *args. This allows us to use keyword
arguments properly.
Since the plan is to integrate sparse into core and have it
enabled by default, we need to prepare for a sparse matcher
to always be obtained and operated on. As part of the move,
we inserted code that returns an always matcher if sparse
isn't enabled. Some callers in the sparse extension take this
into account and conditionally perform matching depending on
whether the special always matcher is seen. I /think/ this
may have sped up some operations where the extension is
installed but no sparse config is activated.
One thing I'm ensure of in this code is whether os.path.dirname()
is semantically correct. os.posixpath.dirname() (which is
exported as pathutil.dirname) might be a better choise because
all patterns should be using posix directory separators (/)
instead of Windows (\). There's an inline comment that implies
Windows was tested. So hopefully it won't be a problem. We
can improve this in a follow-up. I've added a TODO to track it.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 06 Jul 2017 17:41:45 -0700 |
parents | 526255fe7899 |
children | d09e948dc303 |
comparison
equal
deleted
inserted
replaced
33319:3c84591e7321 | 33320:153456f02426 |
---|---|
6 # GNU General Public License version 2 or any later version. | 6 # GNU General Public License version 2 or any later version. |
7 | 7 |
8 from __future__ import absolute_import | 8 from __future__ import absolute_import |
9 | 9 |
10 import hashlib | 10 import hashlib |
11 import os | |
11 | 12 |
12 from .i18n import _ | 13 from .i18n import _ |
13 from .node import nullid | 14 from .node import nullid |
14 from . import ( | 15 from . import ( |
15 error, | 16 error, |
17 match as matchmod, | |
18 pycompat, | |
16 ) | 19 ) |
17 | 20 |
18 # Whether sparse features are enabled. This variable is intended to be | 21 # Whether sparse features are enabled. This variable is intended to be |
19 # temporary to facilitate porting sparse to core. It should eventually be | 22 # temporary to facilitate porting sparse to core. It should eventually be |
20 # a per-repo option, possibly a repo requirement. | 23 # a per-repo option, possibly a repo requirement. |
191 def addtemporaryincludes(repo, additional): | 194 def addtemporaryincludes(repo, additional): |
192 includes = readtemporaryincludes(repo) | 195 includes = readtemporaryincludes(repo) |
193 for i in additional: | 196 for i in additional: |
194 includes.add(i) | 197 includes.add(i) |
195 writetemporaryincludes(repo, includes) | 198 writetemporaryincludes(repo, includes) |
199 | |
200 def matcher(repo, revs=None, includetemp=True): | |
201 """Obtain a matcher for sparse working directories for the given revs. | |
202 | |
203 If multiple revisions are specified, the matcher is the union of all | |
204 revs. | |
205 | |
206 ``includetemp`` indicates whether to use the temporary sparse profile. | |
207 """ | |
208 # If sparse isn't enabled, sparse matcher matches everything. | |
209 if not enabled: | |
210 return matchmod.always(repo.root, '') | |
211 | |
212 if not revs or revs == [None]: | |
213 revs = [repo.changelog.rev(node) | |
214 for node in repo.dirstate.parents() if node != nullid] | |
215 | |
216 signature = configsignature(repo, includetemp=includetemp) | |
217 | |
218 key = '%s %s' % (signature, ' '.join(map(pycompat.bytestr, revs))) | |
219 | |
220 result = repo._sparsematchercache.get(key) | |
221 if result: | |
222 return result | |
223 | |
224 matchers = [] | |
225 for rev in revs: | |
226 try: | |
227 includes, excludes, profiles = patternsforrev(repo, rev) | |
228 | |
229 if includes or excludes: | |
230 # Explicitly include subdirectories of includes so | |
231 # status will walk them down to the actual include. | |
232 subdirs = set() | |
233 for include in includes: | |
234 # TODO consider using posix path functions here so Windows | |
235 # \ directory separators don't come into play. | |
236 dirname = os.path.dirname(include) | |
237 # basename is used to avoid issues with absolute | |
238 # paths (which on Windows can include the drive). | |
239 while os.path.basename(dirname): | |
240 subdirs.add(dirname) | |
241 dirname = os.path.dirname(dirname) | |
242 | |
243 matcher = matchmod.match(repo.root, '', [], | |
244 include=includes, exclude=excludes, | |
245 default='relpath') | |
246 if subdirs: | |
247 matcher = matchmod.forceincludematcher(matcher, subdirs) | |
248 matchers.append(matcher) | |
249 except IOError: | |
250 pass | |
251 | |
252 if not matchers: | |
253 result = matchmod.always(repo.root, '') | |
254 elif len(matchers) == 1: | |
255 result = matchers[0] | |
256 else: | |
257 result = matchmod.unionmatcher(matchers) | |
258 | |
259 if includetemp: | |
260 tempincludes = readtemporaryincludes(repo) | |
261 result = matchmod.forceincludematcher(result, tempincludes) | |
262 | |
263 repo._sparsematchercache[key] = result | |
264 | |
265 return result |