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 |