comparison mercurial/localrepo.py @ 39548:7ce9dea3a14a

localrepo: move repo creation logic out of localrepository.__init__ (API) It has long bothered me that local repository creation is handled as part of localrepository.__init__. Upcoming changes I want to make around how repositories are initialized and instantiated will make the continued existence of repository creation code in localrepository.__init__ even more awkward. localrepository instances are almost never constructed directly: instead, callers are supposed to go through hg.repository() to obtain a handle on a repository. And hg.repository() calls localrepo.instance() to return a new repo instance. This commit teaches localrepo.instance() to handle the create=True logic. Most of the code for repo construction has been moved to a standalone function. This allows extensions to monkeypatch the function to further customize freshly-created repositories. A few calls to localrepo.localrepository.__init__ that were passing create=True were converted to call localrepo.instance(). .. api:: local repo creation moved out of constructor ``localrepo.localrepository.__init__`` no longer accepts a ``create`` argument to create a new repository. New repository creation is now performed as part of ``localrepo.instance()`` and the bulk of the work is performed by ``localrepo.createrepository()``. Differential Revision: https://phab.mercurial-scm.org/D4534
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 11 Sep 2018 13:46:59 -0700
parents 41aa5dced975
children 089fc0db0954
comparison
equal deleted inserted replaced
39546:41aa5dced975 39548:7ce9dea3a14a
424 # this changeset was introduced. Someone should fix 424 # this changeset was introduced. Someone should fix
425 # the remainig bit and drop this line 425 # the remainig bit and drop this line
426 'bisect.state', 426 'bisect.state',
427 } 427 }
428 428
429 def __init__(self, baseui, path, create=False, intents=None): 429 def __init__(self, baseui, path, intents=None):
430 """Create a new local repository instance.
431
432 Most callers should use ``hg.repository()`` or ``localrepo.instance()``
433 for obtaining a new repository object.
434 """
435
430 self.requirements = set() 436 self.requirements = set()
431 self.filtername = None 437 self.filtername = None
432 # wvfs: rooted at the repository root, used to access the working copy 438 # wvfs: rooted at the repository root, used to access the working copy
433 self.wvfs = vfsmod.vfs(path, expandpath=True, realpath=True) 439 self.wvfs = vfsmod.vfs(path, expandpath=True, realpath=True)
434 # vfs: rooted at .hg, used to access repo files outside of .hg/store 440 # vfs: rooted at .hg, used to access repo files outside of .hg/store
473 engine = util.compengines[name] 479 engine = util.compengines[name]
474 if engine.revlogheader(): 480 if engine.revlogheader():
475 self.supported.add('exp-compression-%s' % name) 481 self.supported.add('exp-compression-%s' % name)
476 482
477 if not self.vfs.isdir(): 483 if not self.vfs.isdir():
478 if create: 484 try:
479 self.requirements = newreporequirements(self.ui) 485 self.vfs.stat()
480 486 except OSError as inst:
481 if not self.wvfs.exists(): 487 if inst.errno != errno.ENOENT:
482 self.wvfs.makedirs() 488 raise
483 self.vfs.makedir(notindexed=True) 489 raise error.RepoError(_("repository %s not found") % path)
484
485 if 'store' in self.requirements:
486 self.vfs.mkdir("store")
487
488 # create an invalid changelog
489 self.vfs.append(
490 "00changelog.i",
491 '\0\0\0\2' # represents revlogv2
492 ' dummy changelog to prevent using the old repo layout'
493 )
494 else:
495 try:
496 self.vfs.stat()
497 except OSError as inst:
498 if inst.errno != errno.ENOENT:
499 raise
500 raise error.RepoError(_("repository %s not found") % path)
501 elif create:
502 raise error.RepoError(_("repository %s already exists") % path)
503 else: 490 else:
504 try: 491 try:
505 self.requirements = scmutil.readrequires( 492 self.requirements = scmutil.readrequires(
506 self.vfs, self.supported) 493 self.vfs, self.supported)
507 except IOError as inst: 494 except IOError as inst:
544 if util.safehasattr(self.svfs, 'vfs'): # this is filtervfs 531 if util.safehasattr(self.svfs, 'vfs'): # this is filtervfs
545 self.svfs.vfs.audit = self._getsvfsward(self.svfs.vfs.audit) 532 self.svfs.vfs.audit = self._getsvfsward(self.svfs.vfs.audit)
546 else: # standard vfs 533 else: # standard vfs
547 self.svfs.audit = self._getsvfsward(self.svfs.audit) 534 self.svfs.audit = self._getsvfsward(self.svfs.audit)
548 self._applyopenerreqs() 535 self._applyopenerreqs()
549 if create:
550 self._writerequirements()
551 536
552 self._dirstatevalidatewarned = False 537 self._dirstatevalidatewarned = False
553 538
554 self._branchcaches = {} 539 self._branchcaches = {}
555 self._revbranchcache = None 540 self._revbranchcache = None
2394 base, name = os.path.split(fn) 2379 base, name = os.path.split(fn)
2395 assert name.startswith('journal') 2380 assert name.startswith('journal')
2396 return os.path.join(base, name.replace('journal', 'undo', 1)) 2381 return os.path.join(base, name.replace('journal', 'undo', 1))
2397 2382
2398 def instance(ui, path, create, intents=None): 2383 def instance(ui, path, create, intents=None):
2399 return localrepository(ui, util.urllocalpath(path), create, 2384 if create:
2400 intents=intents) 2385 vfs = vfsmod.vfs(path, expandpath=True, realpath=True)
2386
2387 if vfs.exists('.hg'):
2388 raise error.RepoError(_('repository %s already exists') % path)
2389
2390 createrepository(ui, vfs)
2391
2392 return localrepository(ui, util.urllocalpath(path), intents=intents)
2401 2393
2402 def islocal(path): 2394 def islocal(path):
2403 return True 2395 return True
2404 2396
2405 def newreporequirements(ui): 2397 def newreporequirements(ui):
2445 # experimental config: format.internal-phase 2437 # experimental config: format.internal-phase
2446 if ui.configbool('format', 'internal-phase'): 2438 if ui.configbool('format', 'internal-phase'):
2447 requirements.add('internal-phase') 2439 requirements.add('internal-phase')
2448 2440
2449 return requirements 2441 return requirements
2442
2443 def createrepository(ui, wdirvfs):
2444 """Create a new repository in a vfs.
2445
2446 ``wdirvfs`` is a vfs instance pointing at the working directory.
2447 ``requirements`` is a set of requirements for the new repository.
2448 """
2449 requirements = newreporequirements(ui)
2450
2451 if not wdirvfs.exists():
2452 wdirvfs.makedirs()
2453
2454 hgvfs = vfsmod.vfs(wdirvfs.join(b'.hg'))
2455 hgvfs.makedir(notindexed=True)
2456
2457 if b'store' in requirements:
2458 hgvfs.mkdir(b'store')
2459
2460 # We create an invalid changelog outside the store so very old
2461 # Mercurial versions (which didn't know about the requirements
2462 # file) encounter an error on reading the changelog. This
2463 # effectively locks out old clients and prevents them from
2464 # mucking with a repo in an unknown format.
2465 #
2466 # The revlog header has version 2, which won't be recognized by
2467 # such old clients.
2468 hgvfs.append(b'00changelog.i',
2469 b'\0\0\0\2 dummy changelog to prevent using the old repo '
2470 b'layout')
2471
2472 scmutil.writerequires(hgvfs, requirements)