# Copyright (C) 2012-2015 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . import cliapp import logging import urllib import urllib2 import urlparse class HeadRequest(urllib2.Request): # pragma: no cover def get_method(self): return 'HEAD' class GetError(cliapp.AppException): def __init__(self, cache, artifact): cliapp.AppException.__init__( self, 'Failed to get the artifact %s ' 'from the artifact cache %s' % (artifact.basename(), cache)) class GetArtifactMetadataError(GetError): def __init__(self, cache, artifact, name): cliapp.AppException.__init__( self, 'Failed to get metadata %s for the artifact %s ' 'from the artifact cache %s' % (name, artifact.basename(), cache)) class GetSourceMetadataError(GetError): def __init__(self, cache, source, cache_key, name): cliapp.AppException.__init__( self, 'Failed to get metadata %s for source %s ' 'and cache key %s from the artifact cache %s' % (name, source, cache_key, cache)) class RemoteArtifactCache(object): def __init__(self, server_url): self.server_url = server_url self.name = urlparse.urlparse(server_url).hostname try: self.method = self._get_method() except urllib2.URLError: self.method = 'tarball' except Exception as e: # pragma: no cover logging.debug('Failed to determine cache method: %s' % e) raise cliapp.AppException('Failed to determine method used by ' 'remote cache.') if self.method == 'ostree': # pragma: no cover self.ostree_url = 'http://%s:%s/' % (self.name, self._get_ostree_info()) def has(self, artifact): return self._has_file(artifact.basename()) def has_artifact_metadata(self, artifact, name): return self._has_file(artifact.metadata_basename(name)) def has_source_metadata(self, source, cachekey, name): filename = '%s.%s' % (cachekey, name) return self._has_file(filename) def get(self, artifact, log=logging.error): try: return self._get_file(artifact.basename()) except urllib2.URLError as e: log(str(e)) raise GetError(self, artifact) def get_artifact_metadata(self, artifact, name, log=logging.error): try: return self._get_file(artifact.metadata_basename(name)) except urllib2.URLError as e: log(str(e)) raise GetArtifactMetadataError(self, artifact, name) def get_source_metadata(self, source, cachekey, name): filename = '%s.%s' % (cachekey, name) try: return self._get_file(filename) except urllib2.URLError: raise GetSourceMetadataError(self, source, cachekey, name) def _has_file(self, filename): # pragma: no cover url = self._request_url(filename) logging.debug('RemoteArtifactCache._has_file: url=%s' % url) request = HeadRequest(url) try: urllib2.urlopen(request) return True except (urllib2.HTTPError, urllib2.URLError): return False def _get_file(self, filename): # pragma: no cover url = self._request_url(filename) logging.debug('RemoteArtifactCache._get_file: url=%s' % url) return urllib2.urlopen(url) def _request_url(self, filename): # pragma: no cover server_url = self.server_url if not server_url.endswith('/'): server_url += '/' return urlparse.urljoin( server_url, '/1.0/artifacts?filename=%s' % urllib.quote(filename)) def _get_method(self): # pragma: no cover logging.debug('Getting cache method of %s' % self.server_url) request_url = urlparse.urljoin(self.server_url, '/1.0/method') req = urllib2.urlopen(request_url) return req.read() def _get_ostree_info(self): # pragma: no cover logging.debug('Getting OSTree repo info.') request_url = urlparse.urljoin(self.server_url, '/1.0/ostreeinfo') logging.debug('sending %s' % request_url) req = urllib2.urlopen(request_url) return req.read() def __str__(self): # pragma: no cover return self.server_url