comparison mercurial/sparse.py @ 33556:22371eabb3b1

sparse: add a requirement when a repository uses sparse (BC) The presence of a sparse checkout can confuse legacy clients or clients without sparse enabled for reasons that should be obvious. This commit introduces a new repository requirement that tracks whether sparse is enabled. The requirement is added when a sparse config is activated and removed when the sparse config is reset. The localrepository constructor has been taught to not open repos with this requirement unless the sparse feature is enabled. It yields a more actionable error message than what you would get if the lockout were handled strictly at the requirements verification phase. Old clients that aren't sparse aware will see the generic "repository requires features unknown to this Mercurial" error, however. The new requirement has "exp" in its name to reflect the experimental nature of sparse. There's a chance that the eventual non-experimental feature won't change significantly and we could have squatted on the "sparse" requirement without ill effect. If that happens, we can teach new clients to still recognize the old name. But I suspect we'll sneak in some BC and we'll want a new requirement to convey new meaning. Differential Revision: https://phab.mercurial-scm.org/D110
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 17 Jul 2017 11:45:38 -0700
parents 6755b719048c
children 7dcb517122f9
comparison
equal deleted inserted replaced
33555:6755b719048c 33556:22371eabb3b1
16 from . import ( 16 from . import (
17 error, 17 error,
18 match as matchmod, 18 match as matchmod,
19 merge as mergemod, 19 merge as mergemod,
20 pycompat, 20 pycompat,
21 scmutil,
21 util, 22 util,
22 ) 23 )
23 24
24 # Whether sparse features are enabled. This variable is intended to be 25 # Whether sparse features are enabled. This variable is intended to be
25 # temporary to facilitate porting sparse to core. It should eventually be 26 # temporary to facilitate porting sparse to core. It should eventually be
520 refreshwdir(repo, origstatus, origsparsematch, force=True) 521 refreshwdir(repo, origstatus, origsparsematch, force=True)
521 522
522 prunetemporaryincludes(repo) 523 prunetemporaryincludes(repo)
523 524
524 def _updateconfigandrefreshwdir(repo, includes, excludes, profiles, 525 def _updateconfigandrefreshwdir(repo, includes, excludes, profiles,
525 force=False): 526 force=False, removing=False):
526 """Update the sparse config and working directory state.""" 527 """Update the sparse config and working directory state."""
527 raw = repo.vfs.tryread('sparse') 528 raw = repo.vfs.tryread('sparse')
528 oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw) 529 oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw)
529 530
530 oldstatus = repo.status() 531 oldstatus = repo.status()
531 oldmatch = matcher(repo) 532 oldmatch = matcher(repo)
533 oldrequires = set(repo.requirements)
532 534
533 # TODO remove this try..except once the matcher integrates better 535 # TODO remove this try..except once the matcher integrates better
534 # with dirstate. We currently have to write the updated config 536 # with dirstate. We currently have to write the updated config
535 # because that will invalidate the matcher cache and force a 537 # because that will invalidate the matcher cache and force a
536 # re-read. We ideally want to update the cached matcher on the 538 # re-read. We ideally want to update the cached matcher on the
537 # repo instance then flush the new config to disk once wdir is 539 # repo instance then flush the new config to disk once wdir is
538 # updated. But this requires massive rework to matcher() and its 540 # updated. But this requires massive rework to matcher() and its
539 # consumers. 541 # consumers.
540 542
541 writeconfig(repo, includes, excludes, profiles) 543 if 'exp-sparse' in oldrequires and removing:
544 repo.requirements.discard('exp-sparse')
545 scmutil.writerequires(repo.vfs, repo.requirements)
546 elif 'exp-sparse' not in oldrequires:
547 repo.requirements.add('exp-sparse')
548 scmutil.writerequires(repo.vfs, repo.requirements)
542 549
543 try: 550 try:
551 writeconfig(repo, includes, excludes, profiles)
544 return refreshwdir(repo, oldstatus, oldmatch, force=force) 552 return refreshwdir(repo, oldstatus, oldmatch, force=force)
545 except Exception: 553 except Exception:
554 if repo.requirements != oldrequires:
555 repo.requirements.clear()
556 repo.requirements |= oldrequires
557 scmutil.writerequires(repo.vfs, repo.requirements)
546 writeconfig(repo, oldincludes, oldexcludes, oldprofiles) 558 writeconfig(repo, oldincludes, oldexcludes, oldprofiles)
547 raise 559 raise
548 560
549 def clearrules(repo, force=False): 561 def clearrules(repo, force=False):
550 """Clears include/exclude rules from the sparse config. 562 """Clears include/exclude rules from the sparse config.
645 len(oldinclude - newinclude)) 657 len(oldinclude - newinclude))
646 excludecount = (len(newexclude - oldexclude) - 658 excludecount = (len(newexclude - oldexclude) -
647 len(oldexclude - newexclude)) 659 len(oldexclude - newexclude))
648 660
649 fcounts = map(len, _updateconfigandrefreshwdir( 661 fcounts = map(len, _updateconfigandrefreshwdir(
650 repo, newinclude, newexclude, newprofiles, force=force)) 662 repo, newinclude, newexclude, newprofiles, force=force,
663 removing=reset))
651 664
652 printchanges(repo.ui, opts, profilecount, includecount, 665 printchanges(repo.ui, opts, profilecount, includecount,
653 excludecount, *fcounts) 666 excludecount, *fcounts)
654 667
655 def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0, 668 def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0,