Mercurial > hg
comparison mercurial/localrepo.py @ 39693:5b8e9b2060ef
localrepo: validate supported requirements in makelocalrepository()
This should be a glorified code move. I did take the opportunity to
refactor things. We now have a separate function for gathering
requirements and one for validating them.
I also mode cosmetic changes to the code, such as not using
abbreviations and using a set instead of list to model missing
requirements.
Differential Revision: https://phab.mercurial-scm.org/D4569
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 12 Sep 2018 14:54:17 -0700 |
parents | 6a3162ed881d |
children | cb2dcfa5cade |
comparison
equal
deleted
inserted
replaced
39692:6a3162ed881d | 39693:5b8e9b2060ef |
---|---|
428 except IOError: | 428 except IOError: |
429 pass | 429 pass |
430 else: | 430 else: |
431 extensions.loadall(ui) | 431 extensions.loadall(ui) |
432 | 432 |
433 supportedrequirements = gathersupportedrequirements(ui) | |
434 ensurerequirementsrecognized(requirements, supportedrequirements) | |
435 | |
436 # At this point, we know we should be capable of opening the repository. | |
437 # Now get on with doing that. | |
438 | |
433 return localrepository( | 439 return localrepository( |
434 baseui=baseui, | 440 baseui=baseui, |
435 ui=ui, | 441 ui=ui, |
436 origroot=path, | 442 origroot=path, |
437 wdirvfs=wdirvfs, | 443 wdirvfs=wdirvfs, |
438 hgvfs=hgvfs, | 444 hgvfs=hgvfs, |
439 requirements=requirements, | 445 requirements=requirements, |
446 supportedrequirements=supportedrequirements, | |
440 intents=intents) | 447 intents=intents) |
448 | |
449 def gathersupportedrequirements(ui): | |
450 """Determine the complete set of recognized requirements.""" | |
451 # Start with all requirements supported by this file. | |
452 supported = set(localrepository._basesupported) | |
453 | |
454 # Execute ``featuresetupfuncs`` entries if they belong to an extension | |
455 # relevant to this ui instance. | |
456 modules = {m.__name__ for n, m in extensions.extensions(ui)} | |
457 | |
458 for fn in featuresetupfuncs: | |
459 if fn.__module__ in modules: | |
460 fn(ui, supported) | |
461 | |
462 # Add derived requirements from registered compression engines. | |
463 for name in util.compengines: | |
464 engine = util.compengines[name] | |
465 if engine.revlogheader(): | |
466 supported.add(b'exp-compression-%s' % name) | |
467 | |
468 return supported | |
469 | |
470 def ensurerequirementsrecognized(requirements, supported): | |
471 """Validate that a set of local requirements is recognized. | |
472 | |
473 Receives a set of requirements. Raises an ``error.RepoError`` if there | |
474 exists any requirement in that set that currently loaded code doesn't | |
475 recognize. | |
476 | |
477 Returns a set of supported requirements. | |
478 """ | |
479 missing = set() | |
480 | |
481 for requirement in requirements: | |
482 if requirement in supported: | |
483 continue | |
484 | |
485 if not requirement or not requirement[0:1].isalnum(): | |
486 raise error.RequirementError(_(b'.hg/requires file is corrupt')) | |
487 | |
488 missing.add(requirement) | |
489 | |
490 if missing: | |
491 raise error.RequirementError( | |
492 _(b'repository requires features unknown to this Mercurial: %s') % | |
493 b' '.join(sorted(missing)), | |
494 hint=_(b'see https://mercurial-scm.org/wiki/MissingRequirement ' | |
495 b'for more information')) | |
441 | 496 |
442 @interfaceutil.implementer(repository.completelocalrepository) | 497 @interfaceutil.implementer(repository.completelocalrepository) |
443 class localrepository(object): | 498 class localrepository(object): |
444 | 499 |
445 # obsolete experimental requirements: | 500 # obsolete experimental requirements: |
488 # the remainig bit and drop this line | 543 # the remainig bit and drop this line |
489 'bisect.state', | 544 'bisect.state', |
490 } | 545 } |
491 | 546 |
492 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements, | 547 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements, |
493 intents=None): | 548 supportedrequirements, intents=None): |
494 """Create a new local repository instance. | 549 """Create a new local repository instance. |
495 | 550 |
496 Most callers should use ``hg.repository()``, ``localrepo.instance()``, | 551 Most callers should use ``hg.repository()``, ``localrepo.instance()``, |
497 or ``localrepo.makelocalrepository()`` for obtaining a new repository | 552 or ``localrepo.makelocalrepository()`` for obtaining a new repository |
498 object. | 553 object. |
514 hgvfs | 569 hgvfs |
515 ``vfs.vfs`` rooted at .hg/ | 570 ``vfs.vfs`` rooted at .hg/ |
516 | 571 |
517 requirements | 572 requirements |
518 ``set`` of bytestrings representing repository opening requirements. | 573 ``set`` of bytestrings representing repository opening requirements. |
574 | |
575 supportedrequirements | |
576 ``set`` of bytestrings representing repository requirements that we | |
577 know how to open. May be a supetset of ``requirements``. | |
519 | 578 |
520 intents | 579 intents |
521 ``set`` of system strings indicating what this repo will be used | 580 ``set`` of system strings indicating what this repo will be used |
522 for. | 581 for. |
523 """ | 582 """ |
528 self.wvfs = wdirvfs | 587 self.wvfs = wdirvfs |
529 self.root = wdirvfs.base | 588 self.root = wdirvfs.base |
530 # vfs rooted at .hg/. Used to access most non-store paths. | 589 # vfs rooted at .hg/. Used to access most non-store paths. |
531 self.vfs = hgvfs | 590 self.vfs = hgvfs |
532 self.path = hgvfs.base | 591 self.path = hgvfs.base |
592 self.requirements = requirements | |
593 self.supported = supportedrequirements | |
533 | 594 |
534 self.filtername = None | 595 self.filtername = None |
535 # svfs: usually rooted at .hg/store, used to access repository history | 596 # svfs: usually rooted at .hg/store, used to access repository history |
536 # If this is a shared repository, this vfs may point to another | 597 # If this is a shared repository, this vfs may point to another |
537 # repository's .hg/store directory. | 598 # repository's .hg/store directory. |
543 # A list of callback to shape the phase if no data were found. | 604 # A list of callback to shape the phase if no data were found. |
544 # Callback are in the form: func(repo, roots) --> processed root. | 605 # Callback are in the form: func(repo, roots) --> processed root. |
545 # This list it to be filled by extension during repo setup | 606 # This list it to be filled by extension during repo setup |
546 self._phasedefaults = [] | 607 self._phasedefaults = [] |
547 | 608 |
548 if featuresetupfuncs: | |
549 self.supported = set(self._basesupported) # use private copy | |
550 extmods = set(m.__name__ for n, m | |
551 in extensions.extensions(self.ui)) | |
552 for setupfunc in featuresetupfuncs: | |
553 if setupfunc.__module__ in extmods: | |
554 setupfunc(self.ui, self.supported) | |
555 else: | |
556 self.supported = self._basesupported | |
557 color.setup(self.ui) | 609 color.setup(self.ui) |
558 | |
559 # Add compression engines. | |
560 for name in util.compengines: | |
561 engine = util.compengines[name] | |
562 if engine.revlogheader(): | |
563 self.supported.add('exp-compression-%s' % name) | |
564 | |
565 # Validate that all seen repository requirements are supported. | |
566 missingrequirements = [] | |
567 for r in requirements: | |
568 if r not in self.supported: | |
569 if not r or not r[0:1].isalnum(): | |
570 raise error.RequirementError( | |
571 _(".hg/requires file is corrupt")) | |
572 missingrequirements.append(r) | |
573 missingrequirements.sort() | |
574 if missingrequirements: | |
575 raise error.RequirementError( | |
576 _("repository requires features unknown to this Mercurial: %s") | |
577 % " ".join(missingrequirements), | |
578 hint=_("see https://mercurial-scm.org/wiki/MissingRequirement" | |
579 " for more information")) | |
580 | |
581 self.requirements = requirements | |
582 | 610 |
583 cachepath = self.vfs.join('cache') | 611 cachepath = self.vfs.join('cache') |
584 self.sharedpath = self.path | 612 self.sharedpath = self.path |
585 try: | 613 try: |
586 sharedpath = self.vfs.read("sharedpath").rstrip('\n') | 614 sharedpath = self.vfs.read("sharedpath").rstrip('\n') |