##// END OF EJS Templates
interfaces: convert `repository.iverifyproblem` from zope `Attribute` attrs...
interfaces: convert `repository.iverifyproblem` from zope `Attribute` attrs This is the same transformation as b455dfddfed0 did for dirstate.

File last commit:

r52756:f4733654 default
r53364:f968926a default
Show More
sparse.py
857 lines | 26.9 KiB | text/x-python | PythonLexer
Gregory Szorc
sparse: move config parsing into core...
r33297 # sparse.py - functionality for sparse checkouts
#
# Copyright 2014 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Matt Harbison
typing: add `from __future__ import annotations` to most files...
r52756 from __future__ import annotations
Gregory Szorc
sparse: move config parsing into core...
r33297
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320 import os
Gregory Szorc
sparse: move config signature logic into core...
r33317
Gregory Szorc
sparse: move config parsing into core...
r33297 from .i18n import _
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 from .node import hex
Gregory Szorc
sparse: move config parsing into core...
r33297 from . import (
error,
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320 match as matchmod,
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 merge as mergemod,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestate as mergestatemod,
Kostia Balytskyi
sparse: treat paths as cwd-relative...
r33648 pathutil,
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320 pycompat,
Pulkit Goyal
requirements: introduce new requirements related module...
r45932 requirements,
Gregory Szorc
sparse: add a requirement when a repository uses sparse (BC)...
r33556 scmutil,
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 util,
Gregory Szorc
sparse: move config parsing into core...
r33297 )
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 from .utils import hashutil
Gregory Szorc
sparse: move config parsing into core...
r33297
Pulkit Goyal
repository: introduce constant for sparse repo requirement and use it...
r45914
Gregory Szorc
sparse: variable to track if sparse is enabled...
r33299 # Whether sparse features are enabled. This variable is intended to be
# temporary to facilitate porting sparse to core. It should eventually be
# a per-repo option, possibly a repo requirement.
enabled = False
Augie Fackler
formatting: blacken the codebase...
r43346
sparse: start moving away from the global variable for detection of usage...
r50249 def use_sparse(repo):
if getattr(repo, "_has_sparse", False):
# When enabling sparse the first time we need it to be enabled before
# actually enabling it. This hack could be avoided if the code was
# improved further, however this is an improvement over the previously
# existing global variable.
return True
return requirements.SPARSE_REQUIREMENT in repo.requirements
Pulkit Goyal
sparse: add an action argument to parseconfig()...
r38874 def parseconfig(ui, raw, action):
Gregory Szorc
sparse: move config parsing into core...
r33297 """Parse sparse config file content.
Pulkit Goyal
sparse: add an action argument to parseconfig()...
r38874 action is the command which is trigerring this read, can be narrow, sparse
Gregory Szorc
sparse: move config parsing into core...
r33297 Returns a tuple of includes, excludes, and profiles.
"""
Augie Fackler
sparse: add timing block for parsing sparse configs...
r49627 with util.timedcm(
'sparse.parseconfig(ui, %d bytes, action=%s)', len(raw), action
):
includes = set()
excludes = set()
profiles = set()
current = None
havesection = False
Gregory Szorc
sparse: require [section] in sparse config files (BC)...
r33551
Augie Fackler
sparse: add timing block for parsing sparse configs...
r49627 for line in raw.split(b'\n'):
line = line.strip()
if not line or line.startswith(b'#'):
# empty or comment line, skip
continue
elif line.startswith(b'%include '):
line = line[9:].strip()
if line:
profiles.add(line)
elif line == b'[include]':
if havesection and current != includes:
# TODO pass filename into this API so we can report it.
raise error.Abort(
_(
b'%(action)s config cannot have includes '
b'after excludes'
)
% {b'action': action}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
sparse: add timing block for parsing sparse configs...
r49627 havesection = True
current = includes
continue
elif line == b'[exclude]':
havesection = True
current = excludes
elif line:
if current is None:
raise error.Abort(
_(
b'%(action)s config entry outside of '
b'section: %(line)s'
)
% {b'action': action, b'line': line},
hint=_(
b'add an [include] or [exclude] line '
b'to declare the entry type'
),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 )
Gregory Szorc
sparse: require [section] in sparse config files (BC)...
r33551
Augie Fackler
sparse: add timing block for parsing sparse configs...
r49627 if line.strip().startswith(b'/'):
ui.warn(
_(
b'warning: %(action)s profile cannot use'
b' paths starting with /, ignoring %(line)s\n'
)
% {b'action': action, b'line': line}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
sparse: add timing block for parsing sparse configs...
r49627 continue
current.add(line)
Gregory Szorc
sparse: move config parsing into core...
r33297
Augie Fackler
sparse: add timing block for parsing sparse configs...
r49627 return includes, excludes, profiles
Gregory Szorc
sparse: move profile reading into core...
r33298
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move profile reading into core...
r33298 # Exists as separate function to facilitate monkeypatching.
def readprofile(repo, profile, changeid):
"""Resolve the raw content of a sparse profile file."""
# TODO add some kind of cache here because this incurs a manifest
# resolve and can be slow.
return repo.filectx(profile, changeid=changeid).data()
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300 def patternsforrev(repo, rev):
"""Obtain sparse checkout patterns for the given rev.
Returns a tuple of iterables representing includes, excludes, and
patterns.
"""
# Feature isn't enabled. No-op.
sparse: start moving away from the global variable for detection of usage...
r50249 if not use_sparse(repo):
Gregory Szorc
sparse: use set for capturing profiles...
r33550 return set(), set(), set()
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = repo.vfs.tryread(b'sparse')
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300 if not raw:
Gregory Szorc
sparse: use set for capturing profiles...
r33550 return set(), set(), set()
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300
if rev is None:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'cannot parse sparse patterns from working directory')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 includes, excludes, profiles = parseconfig(repo.ui, raw, b'sparse')
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300 ctx = repo[rev]
if profiles:
visited = set()
while profiles:
profile = profiles.pop()
if profile in visited:
continue
visited.add(profile)
try:
raw = readprofile(repo, profile, rev)
except error.ManifestLookupError:
msg = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"warning: sparse profile '%s' not found "
b"in rev %s - ignoring it\n" % (profile, ctx)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300 # experimental config: sparse.missingwarning
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.ui.configbool(b'sparse', b'missingwarning'):
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300 repo.ui.warn(msg)
else:
repo.ui.debug(msg)
continue
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 pincludes, pexcludes, subprofs = parseconfig(
repo.ui, raw, b'sparse'
)
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300 includes.update(pincludes)
excludes.update(pexcludes)
Gregory Szorc
sparse: use set for capturing profiles...
r33550 profiles.update(subprofs)
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300
profiles = visited
if includes:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 includes.add(b'.hg*')
Gregory Szorc
sparse: move resolving of sparse patterns for rev into core...
r33300
return includes, excludes, profiles
Gregory Szorc
sparse: move active profiles function into core...
r33301
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: refactor activeprofiles into a generic function (API)...
r33370 def activeconfig(repo):
"""Determine the active sparse config rules.
Rules are constructed by reading the current sparse config and bringing in
referenced profiles from parents of the working directory.
"""
Augie Fackler
formatting: blacken the codebase...
r43346 revs = [
repo.changelog.rev(node)
for node in repo.dirstate.parents()
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node != repo.nullid
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Gregory Szorc
sparse: move active profiles function into core...
r33301
Gregory Szorc
sparse: refactor activeprofiles into a generic function (API)...
r33370 allincludes = set()
allexcludes = set()
allprofiles = set()
Gregory Szorc
sparse: move active profiles function into core...
r33301 for rev in revs:
Gregory Szorc
sparse: refactor activeprofiles into a generic function (API)...
r33370 includes, excludes, profiles = patternsforrev(repo, rev)
allincludes |= includes
allexcludes |= excludes
Gregory Szorc
sparse: use set for capturing profiles...
r33550 allprofiles |= profiles
Gregory Szorc
sparse: move active profiles function into core...
r33301
Gregory Szorc
sparse: refactor activeprofiles into a generic function (API)...
r33370 return allincludes, allexcludes, allprofiles
Gregory Szorc
localrepo: add sparse caches...
r33302
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move config signature logic into core...
r33317 def configsignature(repo, includetemp=True):
"""Obtain the signature string for the current sparse configuration.
This is used to construct a cache key for matchers.
"""
cache = repo._sparsesignaturecache
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 signature = cache.get(b'signature')
Gregory Szorc
sparse: move config signature logic into core...
r33317
if includetemp:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tempsignature = cache.get(b'tempsignature')
Gregory Szorc
sparse: move config signature logic into core...
r33317 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tempsignature = b'0'
Gregory Szorc
sparse: move config signature logic into core...
r33317
if signature is None or (includetemp and tempsignature is None):
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 signature = hex(hashutil.sha1(repo.vfs.tryread(b'sparse')).digest())
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cache[b'signature'] = signature
Gregory Szorc
sparse: move config signature logic into core...
r33317
if includetemp:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = repo.vfs.tryread(b'tempsparse')
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 tempsignature = hex(hashutil.sha1(raw).digest())
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cache[b'tempsignature'] = tempsignature
Gregory Szorc
sparse: move config signature logic into core...
r33317
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'%s %s' % (signature, tempsignature)
Gregory Szorc
sparse: move config signature logic into core...
r33317
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move config file writing into core...
r33303 def writeconfig(repo, includes, excludes, profiles):
"""Write the sparse config file given a sparse configuration."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.vfs(b'sparse', b'wb') as fh:
Gregory Szorc
sparse: move config file writing into core...
r33303 for p in sorted(profiles):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fh.write(b'%%include %s\n' % p)
Gregory Szorc
sparse: move config file writing into core...
r33303
if includes:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fh.write(b'[include]\n')
Gregory Szorc
sparse: move config file writing into core...
r33303 for i in sorted(includes):
fh.write(i)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fh.write(b'\n')
Gregory Szorc
sparse: move config file writing into core...
r33303
if excludes:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fh.write(b'[exclude]\n')
Gregory Szorc
sparse: move config file writing into core...
r33303 for e in sorted(excludes):
fh.write(e)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fh.write(b'\n')
Gregory Szorc
sparse: move config file writing into core...
r33303
Gregory Szorc
sparse: inline signature cache clearing...
r33325 repo._sparsesignaturecache.clear()
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304 def readtemporaryincludes(repo):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = repo.vfs.tryread(b'tempsparse')
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304 if not raw:
return set()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return set(raw.split(b'\n'))
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304 def writetemporaryincludes(repo, includes):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.vfs.write(b'tempsparse', b'\n'.join(sorted(includes)))
Gregory Szorc
sparse: inline signature cache clearing...
r33325 repo._sparsesignaturecache.clear()
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move some temporary includes functions into core...
r33304 def addtemporaryincludes(repo, additional):
includes = readtemporaryincludes(repo)
for i in additional:
includes.add(i)
writetemporaryincludes(repo, includes)
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 def prunetemporaryincludes(repo):
sparse: start moving away from the global variable for detection of usage...
r50249 if not use_sparse(repo) or not repo.vfs.exists(b'tempsparse'):
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 return
Martin von Zweigbergk
sparse: access status fields by name instead of deconstructing it...
r33356 s = repo.status()
if s.modified or s.added or s.removed or s.deleted:
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 # Still have pending changes. Don't bother trying to prune.
return
sparsematch = matcher(repo, includetemp=False)
dirstate = repo.dirstate
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 mresult = mergemod.mergeresult()
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 dropped = []
tempincludes = readtemporaryincludes(repo)
for file in tempincludes:
if file in dirstate and not sparsematch(file):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 message = _(b'dropping temporarily included sparse files')
Pulkit Goyal
sparse: replace merge action values with mergestate.ACTION_* constants...
r45899 mresult.addfile(file, mergestatemod.ACTION_REMOVE, None, message)
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 dropped.append(file)
Augie Fackler
formatting: blacken the codebase...
r43346 mergemod.applyupdates(
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 repo, mresult, repo[None], repo[b'.'], False, wantfiledata=False
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321
# Fix dirstate
for file in dropped:
sparse: use `update_file` instead of `drop`...
r48548 dirstate.update_file(file, p1_tracked=False, wc_tracked=False)
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.vfs.unlink(b'tempsparse')
Gregory Szorc
sparse: inline signature cache clearing...
r33325 repo._sparsesignaturecache.clear()
Augie Fackler
formatting: blacken the codebase...
r43346 msg = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'cleaned up %d temporarily added file(s) from the '
b'sparse checkout\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 repo.ui.status(msg % len(tempincludes))
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
match: write forceincludematcher using unionmatcher...
r33447 def forceincludematcher(matcher, includes):
"""Returns a matcher that returns true for any of the forced includes
before testing against the actual matcher."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 kindpats = [(b'path', include, b'') for include in includes]
includematcher = matchmod.includematcher(b'', kindpats)
Martin von Zweigbergk
match: write forceincludematcher using unionmatcher...
r33447 return matchmod.unionmatcher([includematcher, matcher])
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320 def matcher(repo, revs=None, includetemp=True):
"""Obtain a matcher for sparse working directories for the given revs.
If multiple revisions are specified, the matcher is the union of all
revs.
``includetemp`` indicates whether to use the temporary sparse profile.
"""
# If sparse isn't enabled, sparse matcher matches everything.
sparse: start moving away from the global variable for detection of usage...
r50249 if not use_sparse(repo):
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 return matchmod.always()
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320
if not revs or revs == [None]:
Augie Fackler
formatting: blacken the codebase...
r43346 revs = [
repo.changelog.rev(node)
for node in repo.dirstate.parents()
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if node != repo.nullid
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320
signature = configsignature(repo, includetemp=includetemp)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 key = b'%s %s' % (signature, b' '.join(map(pycompat.bytestr, revs)))
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320
result = repo._sparsematchercache.get(key)
if result:
return result
matchers = []
for rev in revs:
try:
includes, excludes, profiles = patternsforrev(repo, rev)
if includes or excludes:
Augie Fackler
formatting: blacken the codebase...
r43346 matcher = matchmod.match(
repo.root,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'',
Augie Fackler
formatting: blacken the codebase...
r43346 [],
include=includes,
exclude=excludes,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 default=b'relpath',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320 matchers.append(matcher)
except IOError:
pass
if not matchers:
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 result = matchmod.always()
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320 elif len(matchers) == 1:
result = matchers[0]
else:
result = matchmod.unionmatcher(matchers)
if includetemp:
tempincludes = readtemporaryincludes(repo)
Martin von Zweigbergk
match: write forceincludematcher using unionmatcher...
r33447 result = forceincludematcher(result, tempincludes)
Gregory Szorc
sparse: move function for resolving sparse matcher into core...
r33320
repo._sparsematchercache[key] = result
return result
Gregory Szorc
sparse: move update action filtering into core...
r33322
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
sparse: pass mergeresult obj in sparse.filterupdatesactions() (API)...
r45847 def filterupdatesactions(repo, wctx, mctx, branchmerge, mresult):
Gregory Szorc
sparse: refactor update actions filtering and call from core...
r33323 """Filter updates to only lay out files that match the sparse rules."""
sparse: start moving away from the global variable for detection of usage...
r50249 if not use_sparse(repo):
Pulkit Goyal
sparse: pass mergeresult obj in sparse.filterupdatesactions() (API)...
r45847 return
Gregory Szorc
sparse: move update action filtering into core...
r33322
oldrevs = [pctx.rev() for pctx in wctx.parents()]
oldsparsematch = matcher(repo, oldrevs)
if oldsparsematch.always():
Pulkit Goyal
sparse: pass mergeresult obj in sparse.filterupdatesactions() (API)...
r45847 return
Gregory Szorc
sparse: move update action filtering into core...
r33322
files = set()
prunedactions = {}
if branchmerge:
# If we're merging, use the wctx filter, since we're merging into
# the wctx.
Martin von Zweigbergk
cleanup: use p1() and p2() instead of parents()[0] and parents()[1]...
r41442 sparsematch = matcher(repo, [wctx.p1().rev()])
Gregory Szorc
sparse: move update action filtering into core...
r33322 else:
# If we're updating, use the target context's filter, since we're
# moving to the target context.
sparsematch = matcher(repo, [mctx.rev()])
temporaryfiles = []
Pulkit Goyal
mergeresult: introduce filemap() which yields filename based mapping...
r45906 for file, action in mresult.filemap():
Gregory Szorc
sparse: move update action filtering into core...
r33322 type, args, msg = action
files.add(file)
if sparsematch(file):
prunedactions[file] = action
Pulkit Goyal
mergeactions: use action constants instead of string values...
r45851 elif type == mergestatemod.ACTION_MERGE:
Gregory Szorc
sparse: move update action filtering into core...
r33322 temporaryfiles.append(file)
prunedactions[file] = action
elif branchmerge:
merge-actions: add an explicite "no_op" attribute...
r49562 if not type.no_op:
Gregory Szorc
sparse: move update action filtering into core...
r33322 temporaryfiles.append(file)
prunedactions[file] = action
Pulkit Goyal
mergeactions: use action constants instead of string values...
r45851 elif type == mergestatemod.ACTION_FORGET:
Gregory Szorc
sparse: move update action filtering into core...
r33322 prunedactions[file] = action
elif file in wctx:
Pulkit Goyal
mergeactions: use action constants instead of string values...
r45851 prunedactions[file] = (mergestatemod.ACTION_REMOVE, args, msg)
Gregory Szorc
sparse: move update action filtering into core...
r33322
Pulkit Goyal
sparse: add comment for an if condition which I tried to refactor...
r45852 # in case or rename on one side, it is possible that f1 might not
# be present in sparse checkout we should include it
# TODO: should we do the same for f2?
# exists as a separate check because file can be in sparse and hence
# if we try to club this condition in above `elif type == ACTION_MERGE`
# it won't be triggered
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 if branchmerge and type == mergestatemod.ACTION_MERGE:
Pulkit Goyal
sparse: add local files to temporaryfiles if they exist out of sparse...
r39563 f1, f2, fa, move, anc = args
if not sparsematch(f1):
temporaryfiles.append(f1)
Gregory Szorc
sparse: move update action filtering into core...
r33322 if len(temporaryfiles) > 0:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.status(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'temporarily included %d file(s) in the sparse '
b'checkout for merging\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% len(temporaryfiles)
)
Gregory Szorc
sparse: move update action filtering into core...
r33322 addtemporaryincludes(repo, temporaryfiles)
# Add the new files to the working copy so they can be merged, etc
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 tmresult = mergemod.mergeresult()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 message = b'temporarily adding to sparse checkout'
Gregory Szorc
sparse: move update action filtering into core...
r33322 wctxmanifest = repo[None].manifest()
for file in temporaryfiles:
if file in wctxmanifest:
fctx = repo[None][file]
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 tmresult.addfile(
file,
mergestatemod.ACTION_GET,
(fctx.flags(), False),
message,
)
Gregory Szorc
sparse: move update action filtering into core...
r33322
dirstate: rename parentchange to changing_parents...
r50855 with repo.dirstate.changing_parents(repo):
sparse: apply update with in a `parentchange` context...
r48508 mergemod.applyupdates(
repo,
tmresult,
repo[None],
repo[b'.'],
False,
wantfiledata=False,
)
Gregory Szorc
sparse: move update action filtering into core...
r33322
sparse: apply update with in a `parentchange` context...
r48508 dirstate = repo.dirstate
for file, flags, msg in tmresult.getactions(
[mergestatemod.ACTION_GET]
):
sparse: use `update_file` instead of `normal` during `applyupdates`...
r48509 dirstate.update_file(file, p1_tracked=True, wc_tracked=True)
Gregory Szorc
sparse: move update action filtering into core...
r33322
Gregory Szorc
sparse: refactor activeprofiles into a generic function (API)...
r33370 profiles = activeconfig(repo)[2]
Gregory Szorc
sparse: move update action filtering into core...
r33322 changedprofiles = profiles & files
# If an active profile changed during the update, refresh the checkout.
# Don't do this during a branch merge, since all incoming changes should
# have been handled by the temporary includes above.
if changedprofiles and not branchmerge:
mf = mctx.manifest()
for file in mf:
old = oldsparsematch(file)
new = sparsematch(file)
if not old and new:
flags = mf.flags(file)
Pulkit Goyal
mergeactions: use action constants instead of string values...
r45851 prunedactions[file] = (
mergestatemod.ACTION_GET,
(flags, False),
b'',
)
Gregory Szorc
sparse: move update action filtering into core...
r33322 elif old and not new:
Pulkit Goyal
mergeactions: use action constants instead of string values...
r45851 prunedactions[file] = (mergestatemod.ACTION_REMOVE, [], b'')
Gregory Szorc
sparse: move update action filtering into core...
r33322
Pulkit Goyal
sparse: pass mergeresult obj in sparse.filterupdatesactions() (API)...
r45847 mresult.setactions(prunedactions)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 def refreshwdir(repo, origstatus, origsparsematch, force=False):
"""Refreshes working directory by taking sparse config into account.
The old status and sparse matcher is compared against the current sparse
matcher.
Will abort if a file with pending changes is being excluded or included
unless ``force`` is True.
"""
# Verify there are no pending changes
pending = set()
Martin von Zweigbergk
sparse: access status fields by name instead of deconstructing it...
r33356 pending.update(origstatus.modified)
pending.update(origstatus.added)
pending.update(origstatus.removed)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 sparsematch = matcher(repo)
abort = False
for f in pending:
if not sparsematch(f):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b"pending changes to '%s'\n") % f)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 abort = not force
if abort:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'could not update sparseness due to pending changes')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 # Calculate merge result
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 dirstate = repo.dirstate
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ctx = repo[b'.']
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 added = []
lookup = []
dropped = []
mf = ctx.manifest()
files = set(mf)
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 mresult = mergemod.mergeresult()
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
for file in files:
old = origsparsematch(file)
new = sparsematch(file)
# Add files that are newly included, or that don't exist in
# the dirstate yet.
if (new and not old) or (old and new and not file in dirstate):
fl = mf.flags(file)
if repo.wvfs.exists(file):
Pulkit Goyal
sparse: replace merge action values with mergestate.ACTION_* constants...
r45899 mresult.addfile(file, mergestatemod.ACTION_EXEC, (fl,), b'')
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 lookup.append(file)
else:
Pulkit Goyal
sparse: replace merge action values with mergestate.ACTION_* constants...
r45899 mresult.addfile(
file, mergestatemod.ACTION_GET, (fl, False), b''
)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 added.append(file)
# Drop files that are newly excluded, or that still exist in
# the dirstate.
elif (old and not new) or (not old and not new and file in dirstate):
dropped.append(file)
if file not in pending:
Pulkit Goyal
sparse: replace merge action values with mergestate.ACTION_* constants...
r45899 mresult.addfile(file, mergestatemod.ACTION_REMOVE, [], b'')
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
# Verify there are no pending changes in newly included files
abort = False
for file in lookup:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b"pending changes to '%s'\n") % file)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 abort = not force
if abort:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'cannot change sparseness due to pending '
b'changes (delete the files or use '
b'--force to bring them back dirty)'
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
# Check for files that were only in the dirstate.
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for file, state in dirstate.items():
Gregory Szorc
sparse: move working directory refreshing into core...
r33324 if not file in files:
old = origsparsematch(file)
new = sparsematch(file)
if old and not new:
dropped.append(file)
Augie Fackler
formatting: blacken the codebase...
r43346 mergemod.applyupdates(
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 repo, mresult, repo[None], repo[b'.'], False, wantfiledata=False
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
# Fix dirstate
for file in added:
sparse: use `update_file` instead of `normal` in `refreshwdir`...
r48510 dirstate.update_file(file, p1_tracked=True, wc_tracked=True)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
for file in dropped:
sparse: use `update_file` instead of `drop` in `refreshwdir`...
r48547 dirstate.update_file(file, p1_tracked=False, wc_tracked=False)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
for file in lookup:
# File exists on disk, and we're bringing it back in an unknown state.
sparse: use `update_file` instead of `normallookup` in refreshwdir...
r48537 dirstate.update_file(
file, p1_tracked=True, wc_tracked=True, possibly_dirty=True
)
Gregory Szorc
sparse: move working directory refreshing into core...
r33324
return added, dropped, lookup
Gregory Szorc
sparse: move post commit actions into core...
r33353
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move post commit actions into core...
r33353 def aftercommit(repo, node):
"""Perform actions after a working directory commit."""
# This function is called unconditionally, even if sparse isn't
# enabled.
ctx = repo[node]
profiles = patternsforrev(repo, ctx.rev())[2]
# profiles will only have data if sparse is enabled.
Gregory Szorc
sparse: use set for capturing profiles...
r33550 if profiles & set(ctx.files()):
Gregory Szorc
sparse: move post commit actions into core...
r33353 origstatus = repo.status()
origsparsematch = matcher(repo)
refreshwdir(repo, origstatus, origsparsematch, force=True)
prunetemporaryincludes(repo)
Gregory Szorc
sparse: move code for clearing rules to core...
r33354
Augie Fackler
formatting: blacken the codebase...
r43346
def _updateconfigandrefreshwdir(
repo, includes, excludes, profiles, force=False, removing=False
):
Gregory Szorc
sparse: consolidate common code for writing sparse config...
r33555 """Update the sparse config and working directory state."""
Arseniy Alekseyev
debugsparse: stop taking the store lock...
r52698 with repo.wlock():
sparse: take lock before writing requirements...
r49511 raw = repo.vfs.tryread(b'sparse')
oldincludes, oldexcludes, oldprofiles = parseconfig(
repo.ui, raw, b'sparse'
)
Gregory Szorc
sparse: consolidate common code for writing sparse config...
r33555
sparse: take lock before writing requirements...
r49511 oldstatus = repo.status()
oldmatch = matcher(repo)
oldrequires = set(repo.requirements)
# TODO remove this try..except once the matcher integrates better
# with dirstate. We currently have to write the updated config
# because that will invalidate the matcher cache and force a
# re-read. We ideally want to update the cached matcher on the
# repo instance then flush the new config to disk once wdir is
# updated. But this requires massive rework to matcher() and its
# consumers.
Gregory Szorc
sparse: consolidate common code for writing sparse config...
r33555
sparse: take lock before writing requirements...
r49511 if requirements.SPARSE_REQUIREMENT in oldrequires and removing:
repo.requirements.discard(requirements.SPARSE_REQUIREMENT)
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 scmutil.writereporequirements(repo, maywritestore=False)
sparse: take lock before writing requirements...
r49511 elif requirements.SPARSE_REQUIREMENT not in oldrequires:
repo.requirements.add(requirements.SPARSE_REQUIREMENT)
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 scmutil.writereporequirements(repo, maywritestore=False)
Gregory Szorc
sparse: consolidate common code for writing sparse config...
r33555
sparse: take lock before writing requirements...
r49511 try:
writeconfig(repo, includes, excludes, profiles)
return refreshwdir(repo, oldstatus, oldmatch, force=force)
except Exception:
if repo.requirements != oldrequires:
repo.requirements.clear()
repo.requirements |= oldrequires
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 scmutil.writereporequirements(repo, maywritestore=False)
sparse: take lock before writing requirements...
r49511 writeconfig(repo, oldincludes, oldexcludes, oldprofiles)
raise
Gregory Szorc
sparse: consolidate common code for writing sparse config...
r33555
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move code for clearing rules to core...
r33354 def clearrules(repo, force=False):
"""Clears include/exclude rules from the sparse config.
The remaining sparse config only has profiles, if defined. The working
directory is refreshed, as needed.
"""
dirstate: rename parentchange to changing_parents...
r50855 with repo.wlock(), repo.dirstate.changing_parents(repo):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = repo.vfs.tryread(b'sparse')
includes, excludes, profiles = parseconfig(repo.ui, raw, b'sparse')
Gregory Szorc
sparse: move code for clearing rules to core...
r33354
if not includes and not excludes:
return
Gregory Szorc
sparse: consolidate common code for writing sparse config...
r33555 _updateconfigandrefreshwdir(repo, set(), set(), profiles, force=force)
Gregory Szorc
sparse: move printing of sparse config changes function into core...
r33355
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 def importfromfiles(repo, opts, paths, force=False):
"""Import sparse config rules from files.
The updated sparse config is written out and the working directory
is refreshed, as needed.
"""
dirstate: rename parentchange to changing_parents...
r50855 with repo.wlock(), repo.dirstate.changing_parents(repo):
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 # read current configuration
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = repo.vfs.tryread(b'sparse')
includes, excludes, profiles = parseconfig(repo.ui, raw, b'sparse')
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 aincludes, aexcludes, aprofiles = activeconfig(repo)
# Import rules on top; only take in rules that are not yet
# part of the active rules.
changed = False
for p in paths:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with util.posixfile(util.expandpath(p), mode=b'rb') as fh:
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 raw = fh.read()
Augie Fackler
formatting: blacken the codebase...
r43346 iincludes, iexcludes, iprofiles = parseconfig(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui, raw, b'sparse'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 oldsize = len(includes) + len(excludes) + len(profiles)
includes.update(iincludes - aincludes)
excludes.update(iexcludes - aexcludes)
Gregory Szorc
sparse: use set for capturing profiles...
r33550 profiles.update(iprofiles - aprofiles)
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371 if len(includes) + len(excludes) + len(profiles) > oldsize:
changed = True
profilecount = includecount = excludecount = 0
fcounts = (0, 0, 0)
if changed:
profilecount = len(profiles - aprofiles)
includecount = len(includes - aincludes)
excludecount = len(excludes - aexcludes)
Augie Fackler
formatting: blacken the codebase...
r43346 fcounts = map(
len,
_updateconfigandrefreshwdir(
repo, includes, excludes, profiles, force=force
),
)
printchanges(
repo.ui, opts, profilecount, includecount, excludecount, *fcounts
)
Gregory Szorc
sparse: move code for importing rules from files into core...
r33371
Augie Fackler
formatting: blacken the codebase...
r43346 def updateconfig(
repo,
opts,
Valentin Gatien-Baron
sparse: rework debugsparse's interface...
r49588 include=(),
exclude=(),
Augie Fackler
formatting: blacken the codebase...
r43346 reset=False,
Valentin Gatien-Baron
sparse: rework debugsparse's interface...
r49588 delete=(),
enableprofile=(),
disableprofile=(),
Augie Fackler
formatting: blacken the codebase...
r43346 force=False,
usereporootpaths=False,
):
Gregory Szorc
sparse: move config updating function into core...
r33374 """Perform a sparse config update.
The new config is written out and a working directory refresh is performed.
"""
Arseniy Alekseyev
debugsparse: stop taking the store lock...
r52698 with repo.wlock(), repo.dirstate.changing_parents(repo):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = repo.vfs.tryread(b'sparse')
Augie Fackler
formatting: blacken the codebase...
r43346 oldinclude, oldexclude, oldprofiles = parseconfig(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui, raw, b'sparse'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
sparse: move config updating function into core...
r33374
Gregory Szorc
sparse: shorten try..except block in updateconfig()...
r33376 if reset:
newinclude = set()
newexclude = set()
newprofiles = set()
else:
newinclude = set(oldinclude)
newexclude = set(oldexclude)
newprofiles = set(oldprofiles)
Gregory Szorc
sparse: move config updating function into core...
r33374
Valentin Gatien-Baron
sparse: rework debugsparse's interface...
r49588 def normalize_pats(pats):
if any(os.path.isabs(pat) for pat in pats):
raise error.Abort(_(b'paths cannot be absolute'))
Kostia Balytskyi
sparse: properly error out when absolute paths are used...
r33646
Valentin Gatien-Baron
sparse: rework debugsparse's interface...
r49588 if usereporootpaths:
return pats
Kostia Balytskyi
sparse: treat paths as cwd-relative...
r33648 # let's treat paths as relative to cwd
root, cwd = repo.root, repo.getcwd()
abspats = []
for kindpat in pats:
kind, pat = matchmod._patsplit(kindpat, None)
if kind in matchmod.cwdrelativepatternkinds or kind is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ap = (kind + b':' if kind else b'') + pathutil.canonpath(
Augie Fackler
formatting: blacken the codebase...
r43346 root, cwd, pat
)
Kostia Balytskyi
sparse: treat paths as cwd-relative...
r33648 abspats.append(ap)
else:
abspats.append(kindpat)
Valentin Gatien-Baron
sparse: rework debugsparse's interface...
r49588 return abspats
Kostia Balytskyi
sparse: treat paths as cwd-relative...
r33648
Valentin Gatien-Baron
sparse: rework debugsparse's interface...
r49588 include = normalize_pats(include)
exclude = normalize_pats(exclude)
delete = normalize_pats(delete)
disableprofile = normalize_pats(disableprofile)
enableprofile = normalize_pats(enableprofile)
newinclude.difference_update(delete)
newexclude.difference_update(delete)
newprofiles.difference_update(disableprofile)
newinclude.update(include)
newprofiles.update(enableprofile)
newexclude.update(exclude)
Gregory Szorc
sparse: move config updating function into core...
r33374
Augie Fackler
formatting: blacken the codebase...
r43346 profilecount = len(newprofiles - oldprofiles) - len(
oldprofiles - newprofiles
)
includecount = len(newinclude - oldinclude) - len(
oldinclude - newinclude
)
excludecount = len(newexclude - oldexclude) - len(
oldexclude - newexclude
)
Gregory Szorc
sparse: move config updating function into core...
r33374
Augie Fackler
formatting: blacken the codebase...
r43346 fcounts = map(
len,
_updateconfigandrefreshwdir(
repo,
newinclude,
newexclude,
newprofiles,
force=force,
removing=reset,
),
)
Gregory Szorc
sparse: shorten try..except block in updateconfig()...
r33376
Augie Fackler
formatting: blacken the codebase...
r43346 printchanges(
repo.ui, opts, profilecount, includecount, excludecount, *fcounts
)
Gregory Szorc
sparse: move config updating function into core...
r33374
Augie Fackler
formatting: blacken the codebase...
r43346 def printchanges(
ui,
opts,
profilecount=0,
includecount=0,
excludecount=0,
added=0,
dropped=0,
conflicting=0,
):
Gregory Szorc
sparse: move printing of sparse config changes function into core...
r33355 """Print output summarizing sparse config changes."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with ui.formatter(b'sparse', opts) as fm:
Gregory Szorc
sparse: move printing of sparse config changes function into core...
r33355 fm.startitem()
Augie Fackler
formatting: blacken the codebase...
r43346 fm.condwrite(
ui.verbose,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'profiles_added',
_(b'Profiles changed: %d\n'),
Augie Fackler
formatting: blacken the codebase...
r43346 profilecount,
)
fm.condwrite(
ui.verbose,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'include_rules_added',
_(b'Include rules changed: %d\n'),
Augie Fackler
formatting: blacken the codebase...
r43346 includecount,
)
fm.condwrite(
ui.verbose,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'exclude_rules_added',
_(b'Exclude rules changed: %d\n'),
Augie Fackler
formatting: blacken the codebase...
r43346 excludecount,
)
Gregory Szorc
sparse: move printing of sparse config changes function into core...
r33355
# In 'plain' verbose mode, mergemod.applyupdates already outputs what
# files are added or removed outside of the templating formatter
# framework. No point in repeating ourselves in that case.
if not fm.isplain():
Augie Fackler
formatting: blacken the codebase...
r43346 fm.condwrite(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.verbose, b'files_added', _(b'Files added: %d\n'), added
Augie Fackler
formatting: blacken the codebase...
r43346 )
fm.condwrite(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.verbose, b'files_dropped', _(b'Files dropped: %d\n'), dropped
Augie Fackler
formatting: blacken the codebase...
r43346 )
fm.condwrite(
ui.verbose,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'files_conflicting',
_(b'Files conflicting: %d\n'),
Augie Fackler
formatting: blacken the codebase...
r43346 conflicting,
)