Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions gcloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,28 @@ def delete_keys(self, keys):
for key in keys:
self.delete_key(key)

def copy_key(self): # pragma NO COVER
raise NotImplementedError
def copy_key(self, key, destination_bucket, new_name=None):
"""Copy the given key to the given bucket, optionally with a new name.

:type key: string or :class:`gcloud.storage.key.Key`
:param key: The key to be copied.

:type destination_bucket: :class:`gcloud.storage.bucket.Bucket`
:param destination_bucket: The bucket into which the key should be
copied.

:type new_name: string
:param new_name: (optional) the new name for the copied file.

:rtype: :class:`gcloud.storage.key.Key`
:returns: The new Key.
"""
if new_name is None:
new_name = key.name
new_key = destination_bucket.new_key(new_name)
api_path = key.path + '/copyTo' + new_key.path
self.connection.api_request(method='POST', path=api_path)
return new_key

def upload_file(self, filename, key=None):
"""Shortcut method to upload a file into this bucket.
Expand Down
16 changes: 16 additions & 0 deletions gcloud/storage/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,22 @@ def exists(self):

return self.bucket.get_key(self.name) is not None

def rename(self, new_name):
"""Renames this key.

Effectively, copies key to the same bucket with a new name, then

This comment was marked as spam.

This comment was marked as spam.

deletes the key.

:type new_name: string
:param new_name: The new name for this key.

:rtype: :class:`Key`
:returns: The newly-copied key.
"""
new_key = self.bucket.copy_key(self, self.bucket, new_name)
self.bucket.delete_key(self)
return new_key

def delete(self):
"""Deletes a key from Cloud Storage.

Expand Down
44 changes: 44 additions & 0 deletions gcloud/storage/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,50 @@ def test_delete_keys_miss(self):
self.assertEqual(kw[1]['method'], 'DELETE')
self.assertEqual(kw[1]['path'], '/b/%s/o/%s' % (NAME, NONESUCH))

def test_copy_keys_wo_name(self):
SOURCE = 'source'
DEST = 'dest'
KEY = 'key'

class _Key(object):
name = KEY
path = '/b/%s/o/%s' % (SOURCE, KEY)

connection = _Connection({})
source = self._makeOne(connection, SOURCE)
dest = self._makeOne(connection, DEST)
key = _Key()
new_key = source.copy_key(key, dest)
self.assertTrue(new_key.bucket is dest)
self.assertEqual(new_key.name, KEY)
kw, = connection._requested
COPY_PATH = '/b/%s/o/%s/copyTo/b/%s/o/%s' % (SOURCE, KEY, DEST, KEY)
self.assertEqual(kw['method'], 'POST')
self.assertEqual(kw['path'], COPY_PATH)

def test_copy_keys_w_name(self):
SOURCE = 'source'
DEST = 'dest'
KEY = 'key'
NEW_NAME = 'new_name'

class _Key(object):
name = KEY
path = '/b/%s/o/%s' % (SOURCE, KEY)

connection = _Connection({})
source = self._makeOne(connection, SOURCE)
dest = self._makeOne(connection, DEST)
key = _Key()
new_key = source.copy_key(key, dest, NEW_NAME)
self.assertTrue(new_key.bucket is dest)
self.assertEqual(new_key.name, NEW_NAME)
kw, = connection._requested
COPY_PATH = (
'/b/%s/o/%s/copyTo/b/%s/o/%s' % (SOURCE, KEY, DEST, NEW_NAME))
self.assertEqual(kw['method'], 'POST')
self.assertEqual(kw['path'], COPY_PATH)

def test_upload_file_default_key(self):
from gcloud.test_credentials import _Monkey
from gcloud.storage import bucket as MUT
Expand Down
21 changes: 21 additions & 0 deletions gcloud/storage/test_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,21 @@ def test_exists_hit(self):
bucket._keys[KEY] = 1
self.assertTrue(key.exists())

def test_rename(self):
KEY = 'key'
NEW_NAME = 'new-name'
connection = _Connection()
bucket = _Bucket(connection)
key = self._makeOne(bucket, KEY)
bucket._keys[KEY] = 1
orig_key_path = key.path
new_key = key.rename(NEW_NAME)
self.assertEqual(key.name, KEY)
self.assertEqual(new_key.name, NEW_NAME)
self.assertFalse(KEY in bucket._keys)
self.assertTrue(KEY in bucket._deleted)
self.assertTrue(NEW_NAME in bucket._keys)

def test_delete(self):
KEY = 'key'
connection = _Connection()
Expand Down Expand Up @@ -590,9 +605,15 @@ class _Bucket(object):
def __init__(self, connection):
self.connection = connection
self._keys = {}
self._deleted = []

def get_key(self, key):
return self._keys.get(key) # XXX s.b. 'key.name'?

def copy_key(self, key, destination_bucket, new_name):
destination_bucket._keys[new_name] = self._keys[key.name]
return key.from_dict({'name': new_name}, bucket=destination_bucket)

def delete_key(self, key):
del self._keys[key.name] # XXX s.b. 'key'?
self._deleted.append(key.name)