コード例 #1
0
    def _protocol_version(self):
        """Returns the protocol version that should be used.

        If the version wasn't established yet, asks the server what
        versions it supports and picks the highest one.
        """
        if hasattr(self, '_protocol_ver'):
            return self._protocol_ver

        response = requests.get(self.base_url + '/version/')

        if response.status_code == 404:
            server_versions = {1}
        elif response.status_code == 200:
            server_versions = set(response.json()['protocol_versions'])
            if not server_versions:
                raise FiletrackerError(
                    'Server hasn\'t reported any supported protocols'
                )
        else:
            response.raise_for_status()

        common_versions = _SUPPORTED_VERSIONS.intersection(server_versions)
        if not common_versions:
            raise FiletrackerError(
                'Couldn\'t agree on protocol version: client supports '
                '{}, server supports {}.'.format(
                    _PROTOCOL_CAPABILITIES, server_versions
                )
            )

        self._protocol_ver = max(common_versions)
        print('Settled for protocol version {}'.format(self._protocol_ver))

        return self._protocol_ver
コード例 #2
0
    def wrapped(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except requests.exceptions.RequestException as e:
            if e.response is None:
                raise FiletrackerError('Error making HTTP request: %s' % e)

            code = e.response.status_code
            message = e.response.headers.get('x-exception', str(e))
            stacktrace = e.response.text
            raise FiletrackerError('HTTP/%d: %s\n%s' % (code, message, stacktrace))
コード例 #3
0
    def file_size(self, name, force_refresh=False):
        """Returns the size of the file.

        For efficiency this operation does not use locking, so may return
        inconsistent data. Use it for informational purposes.
        """

        uname, version = split_name(name)

        t = time.time()
        logger.debug('    querying size of %s', name)
        try:
            if not self.remote_store or (version is not None and not force_refresh):
                try:
                    if self.local_store and self.local_store.exists(name):
                        return self.local_store.file_size(name)
                except Exception:
                    if self.remote_store:
                        logger.warning(
                            "Error getting '%s' from local store", name, exc_info=True
                        )
                    else:
                        raise
            if self.remote_store:
                return self.remote_store.file_size(name)
            raise FiletrackerError("File not available: %s" % name)
        finally:
            logger.debug('    processed %s in %.2fs', name, time.time() - t)
コード例 #4
0
    def get_stream(self, name):
        url, version = self._parse_name(name)
        response = requests.get(url, stream=True)
        response.raise_for_status()

        remote_version = self._parse_last_modified(response)
        if version is not None and remote_version is not None \
                and version != remote_version:
            raise FiletrackerError("Version %s not available. Server has %s" \
                    % (name, remote_version))
        name, version = split_name(name)

        stream = _FileLikeFromResponse(response)
        return stream, versioned_name(name, remote_version)
コード例 #5
0
    def get_stream(self, name, force_refresh=False, serve_from_cache=False):
        """Retrieves file identified by ``name`` in streaming mode.

           Works like :meth:`get_file`, except that returns a tuple
           (file-like object, versioned name).

           When both remote_store and local_store are present, serve_from_cache
           can be used to ensure that the file will be downloaded and served
           from a local cache. If a full version is specified and the file
           exists in the cache a file will be always served locally.
        """

        uname, version = split_name(name)

        lock = None
        if self.local_store:
            lock = self.lock_manager.lock_for(uname)
            lock.lock_shared()

        try:
            if not self.remote_store or (version is not None
                                         and not force_refresh):
                try:
                    if self.local_store and self.local_store.exists(name):
                        return self.local_store.get_stream(name)
                except Exception:
                    if self.remote_store:
                        logger.warning("Error getting '%s' from local store",
                                       name,
                                       exc_info=True)
                    else:
                        raise
            if self.remote_store:
                if self.local_store and serve_from_cache:
                    if version is None:
                        version = self.remote_store.file_version(name)
                        if version:
                            name = versioned_name(uname, version)
                    if force_refresh or not self.local_store.exists(name):
                        (stream, vname) = self.remote_store.get_stream(name)
                        name = self.local_store.add_stream(vname, stream)
                    return self.local_store.get_stream(name)
                return self.remote_store.get_stream(name)
            raise FiletrackerError("File not available: %s" % name)
        finally:
            if lock:
                lock.close()
コード例 #6
0
 def file_size(self, name):
     path, version = self._parse_name(name)
     size = _file_size(path)
     if version is not None and _file_version(path) != version:
         raise FiletrackerError("Version not found: " + name)
     return size
コード例 #7
0
 def get_stream(self, name):
     path, version = self._parse_name(name)
     if not os.path.exists(path):
         raise FiletrackerError("File not found: " + path)
     return open(path, 'rb'), versioned_name(name, _file_version(path))
コード例 #8
0
    def get_file(
        self,
        name,
        save_to,
        add_to_cache=True,
        force_refresh=False,
        _lock_exclusive=False,
    ):
        """Retrieves file identified by ``name``.

        The file is saved as ``save_to``. If ``add_to_cache`` is ``True``,
        the file is added to the local store. If ``force_refresh`` is
        ``True``, local cache is not examined if a remote store is
        configured.

        If a remote store is configured, but ``name`` does not contain a
        version, the local data store is not used, as we cannot guarantee
        that the version there is fresh.

        Local data store implemented in :class:`LocalDataStore` tries to not
        copy the entire file to ``save_to`` if possible, but instead uses
        hardlinking. Therefore you should not modify the file if you don't
        want to totally blow something.

        This method returns the full versioned name of the retrieved file.
        """

        uname, version = split_name(name)

        lock = None
        if self.local_store:
            lock = self.lock_manager.lock_for(uname)
            if _lock_exclusive:
                lock.lock_exclusive()
            else:
                lock.lock_shared()
        else:
            add_to_cache = False

        t = time.time()
        logger.debug('    downloading %s', name)
        try:
            if not self.remote_store or (version is not None and not force_refresh):
                try:
                    if self.local_store and self.local_store.exists(name):
                        return self.local_store.get_file(name, save_to)
                except Exception:
                    if self.remote_store:
                        logger.warning(
                            "Error getting '%s' from local store", name, exc_info=True
                        )
                    else:
                        raise
            if self.remote_store:
                if not _lock_exclusive and add_to_cache:
                    if lock:
                        lock.unlock()
                    return self.get_file(
                        name, save_to, add_to_cache, _lock_exclusive=True
                    )
                vname = self.remote_store.get_file(name, save_to)
                if add_to_cache:
                    self._add_to_cache(vname, save_to)
                return vname
            raise FiletrackerError("File not available: %s" % name)
        finally:
            if lock:
                lock.close()
            logger.debug('    processed %s in %.2fs', name, time.time() - t)