bgneal@697: """s3.py
bgneal@697: 
bgneal@700: This module provides Amazon S3 convenience wrappers.
bgneal@697: 
bgneal@697: """
bgneal@697: from boto.s3.connection import S3Connection
bgneal@697: from boto.s3.key import Key
bgneal@697: 
bgneal@697: 
bgneal@697: class S3Bucket(object):
bgneal@697:     """This class abstracts an Amazon S3 bucket.
bgneal@697: 
bgneal@697:     """
bgneal@700:     def __init__(self, access_key, secret_key, base_url, bucket_name):
bgneal@697:         self.conn = S3Connection(access_key, secret_key)
bgneal@697:         self.bucket = self.conn.get_bucket(bucket_name, validate=False)
bgneal@700:         self.base_url = base_url
bgneal@700:         if not base_url.endswith('/'):
bgneal@700:             self.base_url += '/'
bgneal@700:         self.name = bucket_name
bgneal@700: 
bgneal@700:     def upload_from_file(self, key_name, fp, metadata=None, public=True):
bgneal@700:         """Uploads data from the file object fp to a new key named
bgneal@700:         key_name. metadata, if not None, must be a dict of metadata key / value
bgneal@700:         pairs which will be added to the key.
bgneal@700: 
bgneal@700:         If public is True, the key will be made public after the upload.
bgneal@700: 
bgneal@700:         Returns the URL to the uploaded file.
bgneal@700: 
bgneal@700:         """
bgneal@700:         key = self._make_key(key_name, metadata)
bgneal@700:         key.set_contents_from_file(fp)
bgneal@700:         if public:
bgneal@700:             key.make_public()
bgneal@700:         return '{}{}/{}'.format(self.base_url, self.name, key_name)
bgneal@697: 
bgneal@697:     def upload_from_filename(self, key_name, filename, metadata=None,
bgneal@697:             public=True):
bgneal@697:         """Uploads data from the file named by filename to a new key named
bgneal@697:         key_name. metadata, if not None, must be a dict of metadata key / value
bgneal@697:         pairs which will be added to the key.
bgneal@697: 
bgneal@697:         If public is True, the key will be made public after the upload.
bgneal@697: 
bgneal@700:         Returns the URL to the uploaded file.
bgneal@700: 
bgneal@697:         """
bgneal@697:         key = self._make_key(key_name, metadata)
bgneal@697:         key.set_contents_from_filename(filename)
bgneal@697:         if public:
bgneal@697:             key.make_public()
bgneal@700:         return '{}{}/{}'.format(self.base_url, self.name, key_name)
bgneal@697: 
bgneal@697:     def upload_from_string(self, key_name, content, metadata=None,
bgneal@697:             public=True):
bgneal@697:         """Creates a new key with the given key_name, and uploads the string
bgneal@697:         content to it. metadata, if not None, must be a dict of metadata key /
bgneal@697:         value pairs which will be added to the key.
bgneal@697: 
bgneal@697:         If public is True, the key will be made public after the upload.
bgneal@697: 
bgneal@700:         Returns the URL to the uploaded file.
bgneal@700: 
bgneal@697:         """
bgneal@697:         key = self._make_key(key_name, metadata)
bgneal@697:         key.set_contents_from_string(content)
bgneal@697:         if public:
bgneal@697:             key.make_public()
bgneal@700:         return '{}{}/{}'.format(self.base_url, self.name, key_name)
bgneal@697: 
bgneal@718:     def delete_keys(self, key_urls):
bgneal@718:         """Deletes a set of keys, specified as a list of URLs. The URLs could
bgneal@718:         have been returned by one or more of the upload_* methods.
bgneal@718: 
bgneal@718:         Returns the number of keys that were successfully deleted.
bgneal@718: 
bgneal@718:         """
bgneal@718:         if len(key_urls) == 0:
bgneal@718:             return 0
bgneal@718: 
bgneal@718:         prefix = '{}{}/'.format(self.base_url, self.name)
bgneal@718:         prefix_len = len(prefix)
bgneal@718: 
bgneal@718:         keys = []
bgneal@718:         for url in key_urls:
bgneal@718:             if url.startswith(prefix):
bgneal@718:                 key = url[prefix_len:]
bgneal@718:                 keys.append(key)
bgneal@718: 
bgneal@718:         response = self.bucket.delete_keys(keys, quiet=True)
bgneal@718:         return len(key_urls) - len(response.errors)
bgneal@718: 
bgneal@697:     def _make_key(self, key_name, metadata):
bgneal@697:         """Private method to create a key and optionally apply metadata to
bgneal@697:         it.
bgneal@697: 
bgneal@697:         """
bgneal@697:         key = Key(self.bucket)
bgneal@697:         key.key = key_name
bgneal@697:         if metadata:
bgneal@697:             for k, v in metadata.iteritems():
bgneal@697:                 key.set_metadata(k, v)
bgneal@697:         return key