diff options
Diffstat (limited to 'storages/backends/gs.py')
| -rw-r--r-- | storages/backends/gs.py | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/storages/backends/gs.py b/storages/backends/gs.py new file mode 100644 index 0000000..d9ef483 --- /dev/null +++ b/storages/backends/gs.py @@ -0,0 +1,99 @@ +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO # noqa + +from django.core.exceptions import ImproperlyConfigured + +from storages.backends.s3boto import S3BotoStorage, S3BotoStorageFile +from storages.utils import setting + +try: + from boto.gs.connection import GSConnection, SubdomainCallingFormat + from boto.exception import GSResponseError + from boto.gs.key import Key as GSKey +except ImportError: + raise ImproperlyConfigured("Could not load Boto's Google Storage bindings.\n" + "See https://github.com/boto/boto") + + +class GSBotoStorageFile(S3BotoStorageFile): + + def write(self, content): + if 'w' not in self._mode: + raise AttributeError("File was not opened in write mode.") + self.file = StringIO(content) + self._is_dirty = True + + def close(self): + if self._is_dirty: + provider = self.key.bucket.connection.provider + upload_headers = {provider.acl_header: self._storage.default_acl} + upload_headers.update(self._storage.headers) + self._storage._save_content(self.key, self.file, upload_headers) + self.key.close() + + +class GSBotoStorage(S3BotoStorage): + connection_class = GSConnection + connection_response_error = GSResponseError + file_class = GSBotoStorageFile + key_class = GSKey + + access_key_names = ['GS_ACCESS_KEY_ID'] + secret_key_names = ['GS_SECRET_ACCESS_KEY'] + + access_key = setting('GS_ACCESS_KEY_ID') + secret_key = setting('GS_SECRET_ACCESS_KEY') + file_overwrite = setting('GS_FILE_OVERWRITE', True) + headers = setting('GS_HEADERS', {}) + bucket_name = setting('GS_BUCKET_NAME', None) + auto_create_bucket = setting('GS_AUTO_CREATE_BUCKET', False) + default_acl = setting('GS_DEFAULT_ACL', 'public-read') + bucket_acl = setting('GS_BUCKET_ACL', default_acl) + querystring_auth = setting('GS_QUERYSTRING_AUTH', True) + querystring_expire = setting('GS_QUERYSTRING_EXPIRE', 3600) + durable_reduced_availability = setting('GS_DURABLE_REDUCED_AVAILABILITY', False) + location = setting('GS_LOCATION', '') + custom_domain = setting('GS_CUSTOM_DOMAIN') + calling_format = setting('GS_CALLING_FORMAT', SubdomainCallingFormat()) + secure_urls = setting('GS_SECURE_URLS', True) + file_name_charset = setting('GS_FILE_NAME_CHARSET', 'utf-8') + is_gzipped = setting('GS_IS_GZIPPED', False) + preload_metadata = setting('GS_PRELOAD_METADATA', False) + gzip_content_types = setting('GS_GZIP_CONTENT_TYPES', ( + 'text/css', + 'application/javascript', + 'application/x-javascript', + )) + url_protocol = setting('GS_URL_PROTOCOL', 'http:') + + def _save_content(self, key, content, headers): + # only pass backwards incompatible arguments if they vary from the default + options = {} + if self.encryption: + options['encrypt_key'] = self.encryption + key.set_contents_from_file(content, headers=headers, + policy=self.default_acl, + rewind=True, **options) + + def _get_or_create_bucket(self, name): + """ + Retrieves a bucket if it exists, otherwise creates it. + """ + if self.durable_reduced_availability: + storage_class = 'DURABLE_REDUCED_AVAILABILITY' + else: + storage_class = 'STANDARD' + try: + return self.connection.get_bucket(name, + validate=self.auto_create_bucket) + except self.connection_response_error: + if self.auto_create_bucket: + bucket = self.connection.create_bucket(name, storage_class=storage_class) + bucket.set_acl(self.bucket_acl) + return bucket + raise ImproperlyConfigured("Bucket %s does not exist. Buckets " + "can be automatically created by " + "setting GS_AUTO_CREATE_BUCKET to " + "``True``." % name) |
