# Path: alibuild_helpers/sync.py
# class NoRemoteSync:
# class PartialDownloadError(Exception):
# class HttpRemoteSync:
# class RsyncRemoteSync:
# class S3RemoteSync:
# class Boto3RemoteSync:
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, downloaded, size):
#   def __str__(self):
#   def __init__(self, remoteStore, architecture, workdir, insecure):
#   def getRetry(self, url, dest=None, returnResult=False, log=True, session=None):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, remoteStore, writeStore, architecture, workdir):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, remoteStore, writeStore, architecture, workdir):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, remoteStore, writeStore, architecture, workdir):
#   def _s3_init(self):
#   def _s3_listdir(self, dirname):
#   def _s3_key_exists(self, key):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
# 
# Path: alibuild_helpers/utilities.py
# def resolve_links_path(architecture, package):
#   """Return the path where symlinks for the given package are to be stored.
# 
#   The returned path is relative to the working directory (normally sw/) or the
#   root of the remote store.
#   """
#   return "/".join(("TARS", architecture, package))
# 
# def resolve_store_path(architecture, spec_hash):
#   """Return the path where a tarball with the given hash is to be stored.
# 
#   The returned path is relative to the working directory (normally sw/) or the
#   root of the remote store.
#   """
#   return "/".join(("TARS", architecture, "store", spec_hash[:2], spec_hash))


import sys
import unittest
from io import BytesIO
    from unittest.mock import patch, MagicMock   # In Python 3, mock is built-in
    from mock import patch, MagicMock   # Python 2
from alibuild_helpers import sync
from alibuild_helpers.utilities import resolve_links_path, resolve_store_path
        from botocore.exceptions import ClientError
                                          if method == "list_objects_v2"
                                          else NotImplemented),
            head_object=head_object,
            download_file=download_file,
            get_object=get_object,
        )

    @patch("alibuild_helpers.sync.execute", new=lambda cmd, printer=None: 0)
    @patch("alibuild_helpers.sync.glob.glob", new=lambda path: [])
    @patch("alibuild_helpers.sync.os.listdir", new=lambda path: [])
    @patch("alibuild_helpers.sync.Boto3RemoteSync._s3_init", new=lambda _: None)
    @patch("alibuild_helpers.sync.os")
    def test_boto3(self, mock_os):
        if sys.version_info < (3, 6):
            return
        # file does not exist locally: force download
        mock_os.path.exists.side_effect = lambda path: False
        mock_os.path.islink.side_effect = lambda path: False
        mock_os.path.isfile.side_effect = lambda path: False

        b3sync = sync.Boto3RemoteSync(
            remoteStore="b3://localhost", writeStore="b3://localhost",
            architecture="slc7_x86-64", workdir="/sw")
        b3sync.s3 = self.mock_s3()

        for test_hash in (GOOD_HASH, BAD_HASH, NONEXISTENT_HASH):
            self.spec["hash"] = self.spec["remote_revision_hash"] = test_hash
            self.spec["remote_hashes"] = [test_hash]
            b3sync.syncToLocal("zlib", self.spec)
            b3sync.syncToRemote("zlib", self.spec)

# Path: alibuild_helpers/sync.py
# class NoRemoteSync:
# class PartialDownloadError(Exception):
# class HttpRemoteSync:
# class RsyncRemoteSync:
# class S3RemoteSync:
# class Boto3RemoteSync:
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, downloaded, size):
#   def __str__(self):
#   def __init__(self, remoteStore, architecture, workdir, insecure):
#   def getRetry(self, url, dest=None, returnResult=False, log=True, session=None):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, remoteStore, writeStore, architecture, workdir):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, remoteStore, writeStore, architecture, workdir):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
#   def __init__(self, remoteStore, writeStore, architecture, workdir):
#   def _s3_init(self):
#   def _s3_listdir(self, dirname):
#   def _s3_key_exists(self, key):
#   def syncToLocal(self, p, spec):
#   def syncToRemote(self, p, spec):
#   def syncDistLinksToRemote(self, link_dir):
# 
# Path: alibuild_helpers/utilities.py
# def resolve_links_path(architecture, package):
#   """Return the path where symlinks for the given package are to be stored.
# 
#   The returned path is relative to the working directory (normally sw/) or the
#   root of the remote store.
#   """
#   return "/".join(("TARS", architecture, package))
# 
# def resolve_store_path(architecture, spec_hash):
#   """Return the path where a tarball with the given hash is to be stored.
# 
#   The returned path is relative to the working directory (normally sw/) or the
#   root of the remote store.
#   """
#   return "/".join(("TARS", architecture, "store", spec_hash[:2], spec_hash))


# Path: tests/test_sync.py
import sys
import unittest
from io import BytesIO
    from unittest.mock import patch, MagicMock   # In Python 3, mock is built-in
    from mock import patch, MagicMock   # Python 2
from alibuild_helpers import sync
from alibuild_helpers.utilities import resolve_links_path, resolve_store_path
        from botocore.exceptions import ClientError

                                          if method == "list_objects_v2"
                                          else NotImplemented),
            head_object=head_object,
            download_file=download_file,
            get_object=get_object,
        )

    @patch("alibuild_helpers.sync.execute", new=lambda cmd, printer=None: 0)
    @patch("alibuild_helpers.sync.glob.glob", new=lambda path: [])
    @patch("alibuild_helpers.sync.os.listdir", new=lambda path: [])
    @patch("alibuild_helpers.sync.Boto3RemoteSync._s3_init", new=lambda _: None)
    @patch("alibuild_helpers.sync.os")
    def test_boto3(self, mock_os):
        if sys.version_info < (3, 6):
            return
        # file does not exist locally: force download
        mock_os.path.exists.side_effect = lambda path: False
        mock_os.path.islink.side_effect = lambda path: False
        mock_os.path.isfile.side_effect = lambda path: False

        b3sync = sync.Boto3RemoteSync(
            remoteStore="b3://localhost", writeStore="b3://localhost",
            architecture="slc7_x86-64", workdir="/sw")
        b3sync.s3 = self.mock_s3()

        for test_hash in (GOOD_HASH, BAD_HASH, NONEXISTENT_HASH):
            self.spec["hash"] = self.spec["remote_revision_hash"] = test_hash
            self.spec["remote_hashes"] = [test_hash]
            b3sync.syncToLocal("zlib", self.spec)
            b3sync.syncToRemote("zlib", self.spec)

            b3sync.syncDistLinksToRemote("/sw/dist")