Skip to content

Commit 1c80d61

Browse files
committed
Fix googleapis#64 - Add Bucket.copy_key() and Key.rename() methods.
1 parent af92e74 commit 1c80d61

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

gcloud/storage/bucket.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,28 @@ def delete_keys(self, keys):
194194
for key in keys:
195195
self.delete_key(key)
196196

197-
def copy_key(self):
198-
raise NotImplementedError
197+
def copy_key(self, key, destination_bucket, new_name=None):
198+
"""Copy the given key to the given bucket, optionally with a new name.
199+
200+
:type key: string or :class:`gcloud.storage.key.Key`
201+
:param key: The key to be copied.
202+
203+
:type destination_bucket: :class:`gcloud.storage.bucket.Bucket`
204+
:param destination_bucket: The bucket where the key should be copied into.
205+
206+
:type new_name: string
207+
:param new_name: (optional) the new name for the copied file.
208+
209+
:rtype: :class:`gcloud.storage.key.Key`
210+
:returns: The new Key.
211+
"""
212+
# TODO: Check that the user has WRITE permissions on the dst bucket?
213+
if new_name is None:
214+
new_name = key.name
215+
new_key = destination_bucket.new_key(new_name)
216+
api_path = key.path + '/copyTo' + new_key.path
217+
self.connection.api_request(method='POST', path=api_path)
218+
return new_key
199219

200220
def upload_file(self, filename, key=None):
201221
# TODO: What do we do about overwriting data?

gcloud/storage/key.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,19 @@ def exists(self):
132132

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

135+
def rename(self, new_name):
136+
"""Renames this key.
137+
138+
:type new_name: string
139+
:param new_name: The new name for this key.
140+
"""
141+
new_key = self.bucket.copy_key(self, self.bucket, new_name)
142+
self.delete()
143+
# This feels like a dirty hack, but since the bucket is the same we can
144+
# just change the name attribute of this instance to have it point to the
145+
# new key.
146+
self.name = new_key.name
147+
135148
def delete(self):
136149
"""Deletes a key from Cloud Storage.
137150

gcloud/storage/test_key.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import unittest2
2+
3+
from gcloud.storage.bucket import Bucket
4+
from gcloud.storage.connection import Connection
5+
from gcloud.storage.key import Key
6+
7+
8+
class TestKey(unittest2.TestCase):
9+
10+
def setUp(self):
11+
# Mock Connection.api_request with a method that just stores the HTTP
12+
# method, path and query params in an instance variable for later
13+
# inspection.
14+
# TODO: It'd be better to make the Connection talk to a local HTTP server
15+
# that we can inspect, but a simple test using a mock is certainly better
16+
# than no tests.
17+
self.connection = Connection('project-name')
18+
self.connection.api_request = self.mock_api_request
19+
self.api_request_calls = []
20+
21+
def mock_api_request(self, method, path=None, query_params=None,
22+
data=None, content_type=None,
23+
api_base_url=None, api_version=None,
24+
expect_json=True):
25+
self.api_request_calls.append([method, path, query_params])
26+
27+
def test_rename(self):
28+
bucket = Bucket(self.connection, 'bucket')
29+
key = Key(bucket, 'key')
30+
orig_key_path = key.path
31+
key.rename('new-name')
32+
expected = [
33+
['POST', orig_key_path + '/copyTo/b/bucket/o/new-name', None],
34+
['DELETE', orig_key_path, None]]
35+
self.assertEqual(key.name, 'new-name')
36+
self.assertEqual(self.api_request_calls, expected)

0 commit comments

Comments
 (0)