comparison mercurial/localrepo.py @ 39692:6a3162ed881d

localrepo: read requirements file in makelocalrepository() Previously, scmutil.readrequires() loaded the requirements file and validated its content against what was supported. Requirements translate to repository features and are critical to our plans to dynamically create local repository types. So, we must load them in makelocalrepository() before a repository instance is constructed. This commit moves the reading of the .hg/requires file to makelocalrepository(). Because scmutil.readrequires() was performing I/O and validation, we inlined the validation into localrepository.__init__ and removed scmutil.readrequires(). I plan to remove scmutil.readrequires() in a future commit (we can't do it now because statichttprepo uses it). Differential Revision: https://phab.mercurial-scm.org/D4568
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 12 Sep 2018 14:45:52 -0700
parents 2f067e365532
children 5b8e9b2060ef
comparison
equal deleted inserted replaced
39691:2f067e365532 39692:6a3162ed881d
406 if e.errno != errno.ENOENT: 406 if e.errno != errno.ENOENT:
407 raise 407 raise
408 408
409 raise error.RepoError(_(b'repository %s not found') % path) 409 raise error.RepoError(_(b'repository %s not found') % path)
410 410
411 # .hg/requires file contains a newline-delimited list of
412 # features/capabilities the opener (us) must have in order to use
413 # the repository. This file was introduced in Mercurial 0.9.2,
414 # which means very old repositories may not have one. We assume
415 # a missing file translates to no requirements.
416 try:
417 requirements = set(hgvfs.read(b'requires').splitlines())
418 except IOError as e:
419 if e.errno != errno.ENOENT:
420 raise
421 requirements = set()
422
411 # The .hg/hgrc file may load extensions or contain config options 423 # The .hg/hgrc file may load extensions or contain config options
412 # that influence repository construction. Attempt to load it and 424 # that influence repository construction. Attempt to load it and
413 # process any new extensions that it may have pulled in. 425 # process any new extensions that it may have pulled in.
414 try: 426 try:
415 ui.readconfig(hgvfs.join(b'hgrc'), root=wdirvfs.base) 427 ui.readconfig(hgvfs.join(b'hgrc'), root=wdirvfs.base)
422 baseui=baseui, 434 baseui=baseui,
423 ui=ui, 435 ui=ui,
424 origroot=path, 436 origroot=path,
425 wdirvfs=wdirvfs, 437 wdirvfs=wdirvfs,
426 hgvfs=hgvfs, 438 hgvfs=hgvfs,
439 requirements=requirements,
427 intents=intents) 440 intents=intents)
428 441
429 @interfaceutil.implementer(repository.completelocalrepository) 442 @interfaceutil.implementer(repository.completelocalrepository)
430 class localrepository(object): 443 class localrepository(object):
431 444
474 # this changeset was introduced. Someone should fix 487 # this changeset was introduced. Someone should fix
475 # the remainig bit and drop this line 488 # the remainig bit and drop this line
476 'bisect.state', 489 'bisect.state',
477 } 490 }
478 491
479 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, intents=None): 492 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements,
493 intents=None):
480 """Create a new local repository instance. 494 """Create a new local repository instance.
481 495
482 Most callers should use ``hg.repository()``, ``localrepo.instance()``, 496 Most callers should use ``hg.repository()``, ``localrepo.instance()``,
483 or ``localrepo.makelocalrepository()`` for obtaining a new repository 497 or ``localrepo.makelocalrepository()`` for obtaining a new repository
484 object. 498 object.
497 wdirvfs 511 wdirvfs
498 ``vfs.vfs`` rooted at the working directory. 512 ``vfs.vfs`` rooted at the working directory.
499 513
500 hgvfs 514 hgvfs
501 ``vfs.vfs`` rooted at .hg/ 515 ``vfs.vfs`` rooted at .hg/
516
517 requirements
518 ``set`` of bytestrings representing repository opening requirements.
502 519
503 intents 520 intents
504 ``set`` of system strings indicating what this repo will be used 521 ``set`` of system strings indicating what this repo will be used
505 for. 522 for.
506 """ 523 """
543 for name in util.compengines: 560 for name in util.compengines:
544 engine = util.compengines[name] 561 engine = util.compengines[name]
545 if engine.revlogheader(): 562 if engine.revlogheader():
546 self.supported.add('exp-compression-%s' % name) 563 self.supported.add('exp-compression-%s' % name)
547 564
548 try: 565 # Validate that all seen repository requirements are supported.
549 self.requirements = scmutil.readrequires(self.vfs, self.supported) 566 missingrequirements = []
550 except IOError as inst: 567 for r in requirements:
551 if inst.errno != errno.ENOENT: 568 if r not in self.supported:
552 raise 569 if not r or not r[0:1].isalnum():
553 self.requirements = set() 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
554 582
555 cachepath = self.vfs.join('cache') 583 cachepath = self.vfs.join('cache')
556 self.sharedpath = self.path 584 self.sharedpath = self.path
557 try: 585 try:
558 sharedpath = self.vfs.read("sharedpath").rstrip('\n') 586 sharedpath = self.vfs.read("sharedpath").rstrip('\n')