[PATCH 01 of 16 V3] largefiles: move basestore._openstore into new module to remove cycle

liscju piotr.listkiewicz at gmail.com
Sat Jun 4 11:23:27 EDT 2016


# HG changeset patch
# User liscju <piotr.listkiewicz at gmail.com>
# Date 1465052024 -7200
#      Sat Jun 04 16:53:44 2016 +0200
# Node ID b37877a19b851acd4a598f8b8214593651bd9089
# Parent  7bcfb9090c86d99b4eeb4e02cdda7ca3cb3373d9
largefiles: move basestore._openstore into new module to remove cycle

diff --git a/hgext/largefiles/basestore.py b/hgext/largefiles/basestore.py
--- a/hgext/largefiles/basestore.py
+++ b/hgext/largefiles/basestore.py
@@ -8,9 +8,7 @@
 
 '''base class for store implementations and store-related utility code'''
 
-import re
-
-from mercurial import util, node, hg, error
+from mercurial import util, node
 from mercurial.i18n import _
 
 import lfutil
@@ -164,63 +162,3 @@ class basestore(object):
         Returns _true_ if any problems are found!
         '''
         raise NotImplementedError('abstract method')
-
-import localstore, wirestore
-
-_storeprovider = {
-    'file':  [localstore.localstore],
-    'http':  [wirestore.wirestore],
-    'https': [wirestore.wirestore],
-    'ssh': [wirestore.wirestore],
-    }
-
-_scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
-
-# During clone this function is passed the src's ui object
-# but it needs the dest's ui object so it can read out of
-# the config file. Use repo.ui instead.
-def _openstore(repo, remote=None, put=False):
-    ui = repo.ui
-
-    if not remote:
-        lfpullsource = getattr(repo, 'lfpullsource', None)
-        if lfpullsource:
-            path = ui.expandpath(lfpullsource)
-        elif put:
-            path = ui.expandpath('default-push', 'default')
-        else:
-            path = ui.expandpath('default')
-
-        # ui.expandpath() leaves 'default-push' and 'default' alone if
-        # they cannot be expanded: fallback to the empty string,
-        # meaning the current directory.
-        if path == 'default-push' or path == 'default':
-            path = ''
-            remote = repo
-        else:
-            path, _branches = hg.parseurl(path)
-            remote = hg.peer(repo, {}, path)
-
-    # The path could be a scheme so use Mercurial's normal functionality
-    # to resolve the scheme to a repository and use its path
-    path = util.safehasattr(remote, 'url') and remote.url() or remote.path
-
-    match = _scheme_re.match(path)
-    if not match:                       # regular filesystem path
-        scheme = 'file'
-    else:
-        scheme = match.group(1)
-
-    try:
-        storeproviders = _storeprovider[scheme]
-    except KeyError:
-        raise error.Abort(_('unsupported URL scheme %r') % scheme)
-
-    for classobj in storeproviders:
-        try:
-            return classobj(ui, repo, remote)
-        except lfutil.storeprotonotcapable:
-            pass
-
-    raise error.Abort(_('%s does not appear to be a largefile store') %
-                     util.hidepassword(path))
diff --git a/hgext/largefiles/lfcommands.py b/hgext/largefiles/lfcommands.py
--- a/hgext/largefiles/lfcommands.py
+++ b/hgext/largefiles/lfcommands.py
@@ -20,7 +20,7 @@ from hgext.convert import convcmd
 from hgext.convert import filemap
 
 import lfutil
-import basestore
+import storefactory
 
 # -- Commands ----------------------------------------------------------
 
@@ -337,7 +337,7 @@ def uploadlfiles(ui, rsrc, rdst, files):
     if not files:
         return
 
-    store = basestore._openstore(rsrc, rdst, put=True)
+    store = storefactory._openstore(rsrc, rdst, put=True)
 
     at = 0
     ui.debug("sending statlfile command for %d largefiles\n" % len(files))
@@ -368,7 +368,7 @@ def verifylfiles(ui, repo, all=False, co
     else:
         revs = ['.']
 
-    store = basestore._openstore(repo)
+    store = storefactory._openstore(repo)
     return store.verify(revs, contents=contents)
 
 def cachelfiles(ui, repo, node, filelist=None):
@@ -394,7 +394,7 @@ def cachelfiles(ui, repo, node, filelist
             toget.append((lfile, expectedhash))
 
     if toget:
-        store = basestore._openstore(repo)
+        store = storefactory._openstore(repo)
         ret = store.get(toget)
         return ret
 
diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -17,7 +17,7 @@ from mercurial.i18n import _
 
 import lfutil
 import lfcommands
-import basestore
+import storefactory
 
 # -- Utility functions: commonly/repeatedly needed functionality ---------------
 
@@ -1109,7 +1109,7 @@ def _getoutgoings(repo, other, missing, 
             lfhashes.add(lfhash)
     lfutil.getlfilestoupload(repo, missing, dedup)
     if lfhashes:
-        lfexists = basestore._openstore(repo, other).exists(lfhashes)
+        lfexists = storefactory._openstore(repo, other).exists(lfhashes)
         for fn, lfhash in knowns:
             if not lfexists[lfhash]: # lfhash doesn't exist on "other"
                 addfunc(fn, lfhash)
@@ -1338,7 +1338,7 @@ def overridecat(orig, ui, repo, file1, *
         else:
             hash = lfutil.readstandin(repo, lf, ctx.rev())
             if not lfutil.inusercache(repo.ui, hash):
-                store = basestore._openstore(repo)
+                store = storefactory._openstore(repo)
                 success, missing = store.get([(lf, hash)])
                 if len(success) != 1:
                     raise error.Abort(
diff --git a/hgext/largefiles/basestore.py b/hgext/largefiles/storefactory.py
copy from hgext/largefiles/basestore.py
copy to hgext/largefiles/storefactory.py
--- a/hgext/largefiles/basestore.py
+++ b/hgext/largefiles/storefactory.py
@@ -1,180 +1,23 @@
-# Copyright 2009-2010 Gregory P. Ward
-# Copyright 2009-2010 Intelerad Medical Systems Incorporated
-# Copyright 2010-2011 Fog Creek Software
-# Copyright 2010-2011 Unity Technologies
-#
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-'''base class for store implementations and store-related utility code'''
+from __future__ import absolute_import
 
 import re
 
-from mercurial import util, node, hg, error
 from mercurial.i18n import _
 
-import lfutil
-
-class StoreError(Exception):
-    '''Raised when there is a problem getting files from or putting
-    files to a central store.'''
-    def __init__(self, filename, hash, url, detail):
-        self.filename = filename
-        self.hash = hash
-        self.url = url
-        self.detail = detail
-
-    def longmessage(self):
-        return (_("error getting id %s from url %s for file %s: %s\n") %
-                 (self.hash, util.hidepassword(self.url), self.filename,
-                  self.detail))
-
-    def __str__(self):
-        return "%s: %s" % (util.hidepassword(self.url), self.detail)
-
-class basestore(object):
-    def __init__(self, ui, repo, url):
-        self.ui = ui
-        self.repo = repo
-        self.url = url
-
-    def put(self, source, hash):
-        '''Put source file into the store so it can be retrieved by hash.'''
-        raise NotImplementedError('abstract method')
-
-    def exists(self, hashes):
-        '''Check to see if the store contains the given hashes. Given an
-        iterable of hashes it returns a mapping from hash to bool.'''
-        raise NotImplementedError('abstract method')
-
-    def get(self, files):
-        '''Get the specified largefiles from the store and write to local
-        files under repo.root.  files is a list of (filename, hash)
-        tuples.  Return (success, missing), lists of files successfully
-        downloaded and those not found in the store.  success is a list
-        of (filename, hash) tuples; missing is a list of filenames that
-        we could not get.  (The detailed error message will already have
-        been presented to the user, so missing is just supplied as a
-        summary.)'''
-        success = []
-        missing = []
-        ui = self.ui
-
-        at = 0
-        available = self.exists(set(hash for (_filename, hash) in files))
-        for filename, hash in files:
-            ui.progress(_('getting largefiles'), at, unit=_('files'),
-                total=len(files))
-            at += 1
-            ui.note(_('getting %s:%s\n') % (filename, hash))
-
-            if not available.get(hash):
-                ui.warn(_('%s: largefile %s not available from %s\n')
-                        % (filename, hash, util.hidepassword(self.url)))
-                missing.append(filename)
-                continue
-
-            if self._gethash(filename, hash):
-                success.append((filename, hash))
-            else:
-                missing.append(filename)
-
-        ui.progress(_('getting largefiles'), None)
-        return (success, missing)
-
-    def _gethash(self, filename, hash):
-        """Get file with the provided hash and store it in the local repo's
-        store and in the usercache.
-        filename is for informational messages only.
-        """
-        util.makedirs(lfutil.storepath(self.repo, ''))
-        storefilename = lfutil.storepath(self.repo, hash)
-
-        tmpname = storefilename + '.tmp'
-        tmpfile = util.atomictempfile(tmpname,
-                                      createmode=self.repo.store.createmode)
+from mercurial import (
+    error,
+    hg,
+    util,
+)
 
-        try:
-            gothash = self._getfile(tmpfile, filename, hash)
-        except StoreError as err:
-            self.ui.warn(err.longmessage())
-            gothash = ""
-        tmpfile.close()
-
-        if gothash != hash:
-            if gothash != "":
-                self.ui.warn(_('%s: data corruption (expected %s, got %s)\n')
-                             % (filename, hash, gothash))
-            util.unlink(tmpname)
-            return False
-
-        util.rename(tmpname, storefilename)
-        lfutil.linktousercache(self.repo, hash)
-        return True
-
-    def verify(self, revs, contents=False):
-        '''Verify the existence (and, optionally, contents) of every big
-        file revision referenced by every changeset in revs.
-        Return 0 if all is well, non-zero on any errors.'''
-
-        self.ui.status(_('searching %d changesets for largefiles\n') %
-                       len(revs))
-        verified = set()                # set of (filename, filenode) tuples
-        filestocheck = []               # list of (cset, filename, expectedhash)
-        for rev in revs:
-            cctx = self.repo[rev]
-            cset = "%d:%s" % (cctx.rev(), node.short(cctx.node()))
-
-            for standin in cctx:
-                filename = lfutil.splitstandin(standin)
-                if filename:
-                    fctx = cctx[standin]
-                    key = (filename, fctx.filenode())
-                    if key not in verified:
-                        verified.add(key)
-                        expectedhash = fctx.data()[0:40]
-                        filestocheck.append((cset, filename, expectedhash))
-
-        failed = self._verifyfiles(contents, filestocheck)
-
-        numrevs = len(verified)
-        numlfiles = len(set([fname for (fname, fnode) in verified]))
-        if contents:
-            self.ui.status(
-                _('verified contents of %d revisions of %d largefiles\n')
-                % (numrevs, numlfiles))
-        else:
-            self.ui.status(
-                _('verified existence of %d revisions of %d largefiles\n')
-                % (numrevs, numlfiles))
-        return int(failed)
-
-    def _getfile(self, tmpfile, filename, hash):
-        '''Fetch one revision of one file from the store and write it
-        to tmpfile.  Compute the hash of the file on-the-fly as it
-        downloads and return the hash.  Close tmpfile.  Raise
-        StoreError if unable to download the file (e.g. it does not
-        exist in the store).'''
-        raise NotImplementedError('abstract method')
-
-    def _verifyfiles(self, contents, filestocheck):
-        '''Perform the actual verification of files in the store.
-        'contents' controls verification of content hash.
-        'filestocheck' is list of files to check.
-        Returns _true_ if any problems are found!
-        '''
-        raise NotImplementedError('abstract method')
-
-import localstore, wirestore
-
-_storeprovider = {
-    'file':  [localstore.localstore],
-    'http':  [wirestore.wirestore],
-    'https': [wirestore.wirestore],
-    'ssh': [wirestore.wirestore],
-    }
-
-_scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
+from . import (
+    lfutil,
+    localstore,
+    wirestore,
+)
 
 # During clone this function is passed the src's ui object
 # but it needs the dest's ui object so it can read out of
@@ -224,3 +67,12 @@ def _openstore(repo, remote=None, put=Fa
 
     raise error.Abort(_('%s does not appear to be a largefile store') %
                      util.hidepassword(path))
+
+_storeprovider = {
+    'file':  [localstore.localstore],
+    'http':  [wirestore.wirestore],
+    'https': [wirestore.wirestore],
+    'ssh': [wirestore.wirestore],
+    }
+
+_scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
diff --git a/tests/test-check-module-imports.t b/tests/test-check-module-imports.t
--- a/tests/test-check-module-imports.t
+++ b/tests/test-check-module-imports.t
@@ -162,5 +162,3 @@ outputs, which should be fixed later.
   > -X tests/test-hgweb-no-request-uri.t \
   > -X tests/test-hgweb-non-interactive.t \
   > | sed 's-\\-/-g' | python "$import_checker" -
-  Import cycle: hgext.largefiles.basestore -> hgext.largefiles.localstore -> hgext.largefiles.basestore
-  [1]


More information about the Mercurial-devel mailing list