blob: 2f20cae5b9e958dba9ffa1791224a134b1ec5ded [file] [log] [blame]
# Copyright 2010 Google Inc.
# Copyright (c) 2011, Nexenta Systems Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
# File representation of key, for use with "file://" URIs.
import os, shutil, StringIO
import sys
class Key(object):
KEY_STREAM_READABLE = 0x01
KEY_STREAM_WRITABLE = 0x02
KEY_STREAM = (KEY_STREAM_READABLE | KEY_STREAM_WRITABLE)
KEY_REGULAR_FILE = 0x00
def __init__(self, bucket, name, fp=None, key_type=KEY_REGULAR_FILE):
self.bucket = bucket
self.full_path = name
if name == '-':
self.name = None
self.size = None
else:
self.name = name
self.size = os.stat(name).st_size
self.key_type = key_type
if key_type == self.KEY_STREAM_READABLE:
self.fp = sys.stdin
self.full_path = '<STDIN>'
elif key_type == self.KEY_STREAM_WRITABLE:
self.fp = sys.stdout
self.full_path = '<STDOUT>'
else:
self.fp = fp
def __str__(self):
return 'file://' + self.full_path
def get_file(self, fp, headers=None, cb=None, num_cb=10, torrent=False):
"""
Retrieves a file from a Key
:type fp: file
:param fp: File pointer to put the data into
:type headers: string
:param: ignored in this subclass.
:type cb: function
:param cb: ignored in this subclass.
:type cb: int
:param num_cb: ignored in this subclass.
"""
if self.key_type & self.KEY_STREAM_WRITABLE:
raise BotoClientError('Stream is not readable')
elif self.key_type & self.KEY_STREAM_READABLE:
key_file = self.fp
else:
key_file = open(self.full_path, 'rb')
try:
shutil.copyfileobj(key_file, fp)
finally:
key_file.close()
def set_contents_from_file(self, fp, headers=None, replace=True, cb=None,
num_cb=10, policy=None, md5=None):
"""
Store an object in a file using the name of the Key object as the
key in file URI and the contents of the file pointed to by 'fp' as the
contents.
:type fp: file
:param fp: the file whose contents to upload
:type headers: dict
:param headers: ignored in this subclass.
:type replace: bool
:param replace: If this parameter is False, the method
will first check to see if an object exists in the
bucket with the same key. If it does, it won't
overwrite it. The default value is True which will
overwrite the object.
:type cb: function
:param cb: ignored in this subclass.
:type cb: int
:param num_cb: ignored in this subclass.
:type policy: :class:`boto.s3.acl.CannedACLStrings`
:param policy: ignored in this subclass.
:type md5: A tuple containing the hexdigest version of the MD5 checksum
of the file as the first element and the Base64-encoded
version of the plain checksum as the second element.
This is the same format returned by the compute_md5 method.
:param md5: ignored in this subclass.
"""
if self.key_type & self.KEY_STREAM_READABLE:
raise BotoClientError('Stream is not writable')
elif self.key_type & self.KEY_STREAM_WRITABLE:
key_file = self.fp
else:
if not replace and os.path.exists(self.full_path):
return
key_file = open(self.full_path, 'wb')
try:
shutil.copyfileobj(fp, key_file)
finally:
key_file.close()
def get_contents_to_file(self, fp, headers=None, cb=None, num_cb=None,
torrent=False, version_id=None,
res_download_handler=None, response_headers=None):
"""
Copy contents from the current file to the file pointed to by 'fp'.
:type fp: File-like object
:param fp:
:type headers: dict
:param headers: Unused in this subclass.
:type cb: function
:param cb: Unused in this subclass.
:type cb: int
:param num_cb: Unused in this subclass.
:type torrent: bool
:param torrent: Unused in this subclass.
:type res_upload_handler: ResumableDownloadHandler
:param res_download_handler: Unused in this subclass.
:type response_headers: dict
:param response_headers: Unused in this subclass.
"""
shutil.copyfileobj(self.fp, fp)
def get_contents_as_string(self, headers=None, cb=None, num_cb=10,
torrent=False):
"""
Retrieve file data from the Key, and return contents as a string.
:type headers: dict
:param headers: ignored in this subclass.
:type cb: function
:param cb: ignored in this subclass.
:type cb: int
:param num_cb: ignored in this subclass.
:type cb: int
:param num_cb: ignored in this subclass.
:type torrent: bool
:param torrent: ignored in this subclass.
:rtype: string
:returns: The contents of the file as a string
"""
fp = StringIO.StringIO()
self.get_contents_to_file(fp)
return fp.getvalue()
def is_stream(self):
return (self.key_type & self.KEY_STREAM)
def close(self):
"""
Closes fp associated with underlying file.
Caller should call this method when done with this class, to avoid
using up OS resources (e.g., when iterating over a large number
of files).
"""
self.fp.close()