hgext/infinitepush/store.py
changeset 50803 609a3b8058c3
parent 50802 cf0502231d56
child 50806 337bc83c1275
--- a/hgext/infinitepush/store.py	Fri Jun 23 13:27:09 2023 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-# based on bundleheads extension by Gregory Szorc <gps@mozilla.com>
-
-
-import abc
-import os
-import subprocess
-
-from mercurial.node import hex
-from mercurial.pycompat import open
-from mercurial import pycompat
-from mercurial.utils import (
-    hashutil,
-    procutil,
-)
-
-
-class BundleWriteException(Exception):
-    pass
-
-
-class BundleReadException(Exception):
-    pass
-
-
-class abstractbundlestore:  # pytype: disable=ignored-metaclass
-    """Defines the interface for bundle stores.
-
-    A bundle store is an entity that stores raw bundle data. It is a simple
-    key-value store. However, the keys are chosen by the store. The keys can
-    be any Python object understood by the corresponding bundle index (see
-    ``abstractbundleindex`` below).
-    """
-
-    __metaclass__ = abc.ABCMeta
-
-    @abc.abstractmethod
-    def write(self, data):
-        """Write bundle data to the store.
-
-        This function receives the raw data to be written as a str.
-        Throws BundleWriteException
-        The key of the written data MUST be returned.
-        """
-
-    @abc.abstractmethod
-    def read(self, key):
-        """Obtain bundle data for a key.
-
-        Returns None if the bundle isn't known.
-        Throws BundleReadException
-        The returned object should be a file object supporting read()
-        and close().
-        """
-
-
-class filebundlestore:
-    """bundle store in filesystem
-
-    meant for storing bundles somewhere on disk and on network filesystems
-    """
-
-    def __init__(self, ui, repo):
-        self.ui = ui
-        self.repo = repo
-        self.storepath = ui.configpath(b'scratchbranch', b'storepath')
-        if not self.storepath:
-            self.storepath = self.repo.vfs.join(
-                b"scratchbranches", b"filebundlestore"
-            )
-        if not os.path.exists(self.storepath):
-            os.makedirs(self.storepath)
-
-    def _dirpath(self, hashvalue):
-        """First two bytes of the hash are the name of the upper
-        level directory, next two bytes are the name of the
-        next level directory"""
-        return os.path.join(self.storepath, hashvalue[0:2], hashvalue[2:4])
-
-    def _filepath(self, filename):
-        return os.path.join(self._dirpath(filename), filename)
-
-    def write(self, data):
-        filename = hex(hashutil.sha1(data).digest())
-        dirpath = self._dirpath(filename)
-
-        if not os.path.exists(dirpath):
-            os.makedirs(dirpath)
-
-        with open(self._filepath(filename), b'wb') as f:
-            f.write(data)
-
-        return filename
-
-    def read(self, key):
-        try:
-            with open(self._filepath(key), b'rb') as f:
-                return f.read()
-        except IOError:
-            return None
-
-
-def format_placeholders_args(args, filename=None, handle=None):
-    """Formats `args` with Infinitepush replacements.
-
-    Hack to get `str.format()`-ed strings working in a BC way with
-    bytes.
-    """
-    formatted_args = []
-    for arg in args:
-        if filename and arg == b'{filename}':
-            formatted_args.append(filename)
-        elif handle and arg == b'{handle}':
-            formatted_args.append(handle)
-        else:
-            formatted_args.append(arg)
-    return formatted_args
-
-
-class externalbundlestore(abstractbundlestore):
-    def __init__(self, put_binary, put_args, get_binary, get_args):
-        """
-        `put_binary` - path to binary file which uploads bundle to external
-            storage and prints key to stdout
-        `put_args` - format string with additional args to `put_binary`
-                     {filename} replacement field can be used.
-        `get_binary` - path to binary file which accepts filename and key
-            (in that order), downloads bundle from store and saves it to file
-        `get_args` - format string with additional args to `get_binary`.
-                     {filename} and {handle} replacement field can be used.
-        """
-
-        self.put_args = put_args
-        self.get_args = get_args
-        self.put_binary = put_binary
-        self.get_binary = get_binary
-
-    def _call_binary(self, args):
-        p = subprocess.Popen(
-            pycompat.rapply(procutil.tonativestr, args),
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            close_fds=True,
-        )
-        stdout, stderr = p.communicate()
-        returncode = p.returncode
-        return returncode, stdout, stderr
-
-    def write(self, data):
-        # Won't work on windows because you can't open file second time without
-        # closing it
-        # TODO: rewrite without str.format() and replace NamedTemporaryFile()
-        # with pycompat.namedtempfile()
-        with pycompat.namedtempfile() as temp:
-            temp.write(data)
-            temp.flush()
-            temp.seek(0)
-            formatted_args = format_placeholders_args(
-                self.put_args, filename=temp.name
-            )
-            returncode, stdout, stderr = self._call_binary(
-                [self.put_binary] + formatted_args
-            )
-
-            if returncode != 0:
-                raise BundleWriteException(
-                    b'Failed to upload to external store: %s' % stderr
-                )
-            stdout_lines = stdout.splitlines()
-            if len(stdout_lines) == 1:
-                return stdout_lines[0]
-            else:
-                raise BundleWriteException(
-                    b'Bad output from %s: %s' % (self.put_binary, stdout)
-                )
-
-    def read(self, handle):
-        # Won't work on windows because you can't open file second time without
-        # closing it
-        with pycompat.namedtempfile() as temp:
-            formatted_args = format_placeholders_args(
-                self.get_args, filename=temp.name, handle=handle
-            )
-            returncode, stdout, stderr = self._call_binary(
-                [self.get_binary] + formatted_args
-            )
-
-            if returncode != 0:
-                raise BundleReadException(
-                    b'Failed to download from external store: %s' % stderr
-                )
-            return temp.read()