--- a/mercurial/sparse.py Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/sparse.py Sun Oct 06 09:45:02 2019 -0400
@@ -30,6 +30,7 @@
# a per-repo option, possibly a repo requirement.
enabled = False
+
def parseconfig(ui, raw, action):
"""Parse sparse config file content.
@@ -55,8 +56,13 @@
elif line == '[include]':
if havesection and current != includes:
# TODO pass filename into this API so we can report it.
- raise error.Abort(_('%(action)s config cannot have includes '
- 'after excludes') % {'action': action})
+ raise error.Abort(
+ _(
+ '%(action)s config cannot have includes '
+ 'after excludes'
+ )
+ % {'action': action}
+ )
havesection = True
current = includes
continue
@@ -65,21 +71,29 @@
current = excludes
elif line:
if current is None:
- raise error.Abort(_('%(action)s config entry outside of '
- 'section: %(line)s')
- % {'action': action, 'line': line},
- hint=_('add an [include] or [exclude] line '
- 'to declare the entry type'))
+ raise error.Abort(
+ _('%(action)s config entry outside of ' 'section: %(line)s')
+ % {'action': action, 'line': line},
+ hint=_(
+ 'add an [include] or [exclude] line '
+ 'to declare the entry type'
+ ),
+ )
if line.strip().startswith('/'):
- ui.warn(_('warning: %(action)s profile cannot use'
- ' paths starting with /, ignoring %(line)s\n')
- % {'action': action, 'line': line})
+ ui.warn(
+ _(
+ 'warning: %(action)s profile cannot use'
+ ' paths starting with /, ignoring %(line)s\n'
+ )
+ % {'action': action, 'line': line}
+ )
continue
current.add(line)
return includes, excludes, profiles
+
# Exists as separate function to facilitate monkeypatching.
def readprofile(repo, profile, changeid):
"""Resolve the raw content of a sparse profile file."""
@@ -87,6 +101,7 @@
# resolve and can be slow.
return repo.filectx(profile, changeid=changeid).data()
+
def patternsforrev(repo, rev):
"""Obtain sparse checkout patterns for the given rev.
@@ -102,8 +117,9 @@
return set(), set(), set()
if rev is None:
- raise error.Abort(_('cannot parse sparse patterns from working '
- 'directory'))
+ raise error.Abort(
+ _('cannot parse sparse patterns from working ' 'directory')
+ )
includes, excludes, profiles = parseconfig(repo.ui, raw, 'sparse')
ctx = repo[rev]
@@ -122,10 +138,10 @@
except error.ManifestLookupError:
msg = (
"warning: sparse profile '%s' not found "
- "in rev %s - ignoring it\n" % (profile, ctx))
+ "in rev %s - ignoring it\n" % (profile, ctx)
+ )
# experimental config: sparse.missingwarning
- if repo.ui.configbool(
- 'sparse', 'missingwarning'):
+ if repo.ui.configbool('sparse', 'missingwarning'):
repo.ui.warn(msg)
else:
repo.ui.debug(msg)
@@ -143,14 +159,18 @@
return includes, excludes, profiles
+
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.
"""
- revs = [repo.changelog.rev(node) for node in
- repo.dirstate.parents() if node != nullid]
+ revs = [
+ repo.changelog.rev(node)
+ for node in repo.dirstate.parents()
+ if node != nullid
+ ]
allincludes = set()
allexcludes = set()
@@ -164,6 +184,7 @@
return allincludes, allexcludes, allprofiles
+
def configsignature(repo, includetemp=True):
"""Obtain the signature string for the current sparse configuration.
@@ -189,6 +210,7 @@
return '%s %s' % (signature, tempsignature)
+
def writeconfig(repo, includes, excludes, profiles):
"""Write the sparse config file given a sparse configuration."""
with repo.vfs('sparse', 'wb') as fh:
@@ -209,6 +231,7 @@
repo._sparsesignaturecache.clear()
+
def readtemporaryincludes(repo):
raw = repo.vfs.tryread('tempsparse')
if not raw:
@@ -216,16 +239,19 @@
return set(raw.split('\n'))
+
def writetemporaryincludes(repo, includes):
repo.vfs.write('tempsparse', '\n'.join(sorted(includes)))
repo._sparsesignaturecache.clear()
+
def addtemporaryincludes(repo, additional):
includes = readtemporaryincludes(repo)
for i in additional:
includes.add(i)
writetemporaryincludes(repo, includes)
+
def prunetemporaryincludes(repo):
if not enabled or not repo.vfs.exists('tempsparse'):
return
@@ -248,8 +274,9 @@
typeactions = mergemod.emptyactions()
typeactions['r'] = actions
- mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False,
- wantfiledata=False)
+ mergemod.applyupdates(
+ repo, typeactions, repo[None], repo['.'], False, wantfiledata=False
+ )
# Fix dirstate
for file in dropped:
@@ -257,10 +284,12 @@
repo.vfs.unlink('tempsparse')
repo._sparsesignaturecache.clear()
- msg = _('cleaned up %d temporarily added file(s) from the '
- 'sparse checkout\n')
+ msg = _(
+ 'cleaned up %d temporarily added file(s) from the ' 'sparse checkout\n'
+ )
repo.ui.status(msg % len(tempincludes))
+
def forceincludematcher(matcher, includes):
"""Returns a matcher that returns true for any of the forced includes
before testing against the actual matcher."""
@@ -268,6 +297,7 @@
includematcher = matchmod.includematcher('', kindpats)
return matchmod.unionmatcher([includematcher, matcher])
+
def matcher(repo, revs=None, includetemp=True):
"""Obtain a matcher for sparse working directories for the given revs.
@@ -281,8 +311,11 @@
return matchmod.always()
if not revs or revs == [None]:
- revs = [repo.changelog.rev(node)
- for node in repo.dirstate.parents() if node != nullid]
+ revs = [
+ repo.changelog.rev(node)
+ for node in repo.dirstate.parents()
+ if node != nullid
+ ]
signature = configsignature(repo, includetemp=includetemp)
@@ -298,9 +331,14 @@
includes, excludes, profiles = patternsforrev(repo, rev)
if includes or excludes:
- matcher = matchmod.match(repo.root, '', [],
- include=includes, exclude=excludes,
- default='relpath')
+ matcher = matchmod.match(
+ repo.root,
+ '',
+ [],
+ include=includes,
+ exclude=excludes,
+ default='relpath',
+ )
matchers.append(matcher)
except IOError:
pass
@@ -320,6 +358,7 @@
return result
+
def filterupdatesactions(repo, wctx, mctx, branchmerge, actions):
"""Filter updates to only lay out files that match the sparse rules."""
if not enabled:
@@ -367,8 +406,13 @@
temporaryfiles.append(f1)
if len(temporaryfiles) > 0:
- repo.ui.status(_('temporarily included %d file(s) in the sparse '
- 'checkout for merging\n') % len(temporaryfiles))
+ repo.ui.status(
+ _(
+ 'temporarily included %d file(s) in the sparse '
+ 'checkout for merging\n'
+ )
+ % len(temporaryfiles)
+ )
addtemporaryincludes(repo, temporaryfiles)
# Add the new files to the working copy so they can be merged, etc
@@ -382,8 +426,9 @@
typeactions = mergemod.emptyactions()
typeactions['g'] = actions
- mergemod.applyupdates(repo, typeactions, repo[None], repo['.'],
- False, wantfiledata=False)
+ mergemod.applyupdates(
+ repo, typeactions, repo[None], repo['.'], False, wantfiledata=False
+ )
dirstate = repo.dirstate
for file, flags, msg in actions:
@@ -407,6 +452,7 @@
return prunedactions
+
def refreshwdir(repo, origstatus, origsparsematch, force=False):
"""Refreshes working directory by taking sparse config into account.
@@ -430,8 +476,9 @@
abort = not force
if abort:
- raise error.Abort(_('could not update sparseness due to pending '
- 'changes'))
+ raise error.Abort(
+ _('could not update sparseness due to pending ' 'changes')
+ )
# Calculate actions
dirstate = repo.dirstate
@@ -470,9 +517,13 @@
repo.ui.warn(_("pending changes to '%s'\n") % file)
abort = not force
if abort:
- raise error.Abort(_('cannot change sparseness due to pending '
- 'changes (delete the files or use '
- '--force to bring them back dirty)'))
+ raise error.Abort(
+ _(
+ 'cannot change sparseness due to pending '
+ 'changes (delete the files or use '
+ '--force to bring them back dirty)'
+ )
+ )
# Check for files that were only in the dirstate.
for file, state in dirstate.iteritems():
@@ -487,8 +538,9 @@
for f, (m, args, msg) in actions.iteritems():
typeactions[m].append((f, args, msg))
- mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False,
- wantfiledata=False)
+ mergemod.applyupdates(
+ repo, typeactions, repo[None], repo['.'], False, wantfiledata=False
+ )
# Fix dirstate
for file in added:
@@ -503,6 +555,7 @@
return added, dropped, lookup
+
def aftercommit(repo, node):
"""Perform actions after a working directory commit."""
# This function is called unconditionally, even if sparse isn't
@@ -519,8 +572,10 @@
prunetemporaryincludes(repo)
-def _updateconfigandrefreshwdir(repo, includes, excludes, profiles,
- force=False, removing=False):
+
+def _updateconfigandrefreshwdir(
+ repo, includes, excludes, profiles, force=False, removing=False
+):
"""Update the sparse config and working directory state."""
raw = repo.vfs.tryread('sparse')
oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw, 'sparse')
@@ -555,6 +610,7 @@
writeconfig(repo, oldincludes, oldexcludes, oldprofiles)
raise
+
def clearrules(repo, force=False):
"""Clears include/exclude rules from the sparse config.
@@ -570,6 +626,7 @@
_updateconfigandrefreshwdir(repo, set(), set(), profiles, force=force)
+
def importfromfiles(repo, opts, paths, force=False):
"""Import sparse config rules from files.
@@ -589,8 +646,9 @@
with util.posixfile(util.expandpath(p), mode='rb') as fh:
raw = fh.read()
- iincludes, iexcludes, iprofiles = parseconfig(repo.ui, raw,
- 'sparse')
+ iincludes, iexcludes, iprofiles = parseconfig(
+ repo.ui, raw, 'sparse'
+ )
oldsize = len(includes) + len(excludes) + len(profiles)
includes.update(iincludes - aincludes)
excludes.update(iexcludes - aexcludes)
@@ -606,15 +664,31 @@
includecount = len(includes - aincludes)
excludecount = len(excludes - aexcludes)
- fcounts = map(len, _updateconfigandrefreshwdir(
- repo, includes, excludes, profiles, force=force))
+ fcounts = map(
+ len,
+ _updateconfigandrefreshwdir(
+ repo, includes, excludes, profiles, force=force
+ ),
+ )
+
+ printchanges(
+ repo.ui, opts, profilecount, includecount, excludecount, *fcounts
+ )
+
- printchanges(repo.ui, opts, profilecount, includecount, excludecount,
- *fcounts)
-
-def updateconfig(repo, pats, opts, include=False, exclude=False, reset=False,
- delete=False, enableprofile=False, disableprofile=False,
- force=False, usereporootpaths=False):
+def updateconfig(
+ repo,
+ pats,
+ opts,
+ include=False,
+ exclude=False,
+ reset=False,
+ delete=False,
+ enableprofile=False,
+ disableprofile=False,
+ force=False,
+ usereporootpaths=False,
+):
"""Perform a sparse config update.
Only one of the actions may be performed.
@@ -623,8 +697,9 @@
"""
with repo.wlock():
raw = repo.vfs.tryread('sparse')
- oldinclude, oldexclude, oldprofiles = parseconfig(repo.ui, raw,
- 'sparse')
+ oldinclude, oldexclude, oldprofiles = parseconfig(
+ repo.ui, raw, 'sparse'
+ )
if reset:
newinclude = set()
@@ -645,8 +720,9 @@
for kindpat in pats:
kind, pat = matchmod._patsplit(kindpat, None)
if kind in matchmod.cwdrelativepatternkinds or kind is None:
- ap = ((kind + ':' if kind else '') +
- pathutil.canonpath(root, cwd, pat))
+ ap = (kind + ':' if kind else '') + pathutil.canonpath(
+ root, cwd, pat
+ )
abspats.append(ap)
else:
abspats.append(kindpat)
@@ -664,39 +740,78 @@
newinclude.difference_update(pats)
newexclude.difference_update(pats)
- profilecount = (len(newprofiles - oldprofiles) -
- len(oldprofiles - newprofiles))
- includecount = (len(newinclude - oldinclude) -
- len(oldinclude - newinclude))
- excludecount = (len(newexclude - oldexclude) -
- len(oldexclude - newexclude))
+ profilecount = len(newprofiles - oldprofiles) - len(
+ oldprofiles - newprofiles
+ )
+ includecount = len(newinclude - oldinclude) - len(
+ oldinclude - newinclude
+ )
+ excludecount = len(newexclude - oldexclude) - len(
+ oldexclude - newexclude
+ )
- fcounts = map(len, _updateconfigandrefreshwdir(
- repo, newinclude, newexclude, newprofiles, force=force,
- removing=reset))
+ fcounts = map(
+ len,
+ _updateconfigandrefreshwdir(
+ repo,
+ newinclude,
+ newexclude,
+ newprofiles,
+ force=force,
+ removing=reset,
+ ),
+ )
- printchanges(repo.ui, opts, profilecount, includecount,
- excludecount, *fcounts)
+ printchanges(
+ repo.ui, opts, profilecount, includecount, excludecount, *fcounts
+ )
+
-def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0,
- added=0, dropped=0, conflicting=0):
+def printchanges(
+ ui,
+ opts,
+ profilecount=0,
+ includecount=0,
+ excludecount=0,
+ added=0,
+ dropped=0,
+ conflicting=0,
+):
"""Print output summarizing sparse config changes."""
with ui.formatter('sparse', opts) as fm:
fm.startitem()
- fm.condwrite(ui.verbose, 'profiles_added', _('Profiles changed: %d\n'),
- profilecount)
- fm.condwrite(ui.verbose, 'include_rules_added',
- _('Include rules changed: %d\n'), includecount)
- fm.condwrite(ui.verbose, 'exclude_rules_added',
- _('Exclude rules changed: %d\n'), excludecount)
+ fm.condwrite(
+ ui.verbose,
+ 'profiles_added',
+ _('Profiles changed: %d\n'),
+ profilecount,
+ )
+ fm.condwrite(
+ ui.verbose,
+ 'include_rules_added',
+ _('Include rules changed: %d\n'),
+ includecount,
+ )
+ fm.condwrite(
+ ui.verbose,
+ 'exclude_rules_added',
+ _('Exclude rules changed: %d\n'),
+ excludecount,
+ )
# 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():
- fm.condwrite(ui.verbose, 'files_added', _('Files added: %d\n'),
- added)
- fm.condwrite(ui.verbose, 'files_dropped', _('Files dropped: %d\n'),
- dropped)
- fm.condwrite(ui.verbose, 'files_conflicting',
- _('Files conflicting: %d\n'), conflicting)
+ fm.condwrite(
+ ui.verbose, 'files_added', _('Files added: %d\n'), added
+ )
+ fm.condwrite(
+ ui.verbose, 'files_dropped', _('Files dropped: %d\n'), dropped
+ )
+ fm.condwrite(
+ ui.verbose,
+ 'files_conflicting',
+ _('Files conflicting: %d\n'),
+ conflicting,
+ )