fog 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Gemfile.lock +1 -1
  2. data/README.rdoc +1 -0
  3. data/fog.gemspec +44 -1
  4. data/lib/fog.rb +2 -1
  5. data/lib/fog/bin.rb +2 -0
  6. data/lib/fog/google.rb +22 -0
  7. data/lib/fog/google/bin.rb +20 -0
  8. data/lib/fog/google/models/storage/directories.rb +43 -0
  9. data/lib/fog/google/models/storage/directory.rb +48 -0
  10. data/lib/fog/google/models/storage/file.rb +87 -0
  11. data/lib/fog/google/models/storage/files.rb +94 -0
  12. data/lib/fog/google/parsers/storage/access_control_list.rb +46 -0
  13. data/lib/fog/google/parsers/storage/copy_object.rb +22 -0
  14. data/lib/fog/google/parsers/storage/get_bucket.rb +46 -0
  15. data/lib/fog/google/parsers/storage/get_bucket_logging.rb +40 -0
  16. data/lib/fog/google/parsers/storage/get_bucket_object_versions.rb +88 -0
  17. data/lib/fog/google/parsers/storage/get_bucket_versioning.rb +24 -0
  18. data/lib/fog/google/parsers/storage/get_request_payment.rb +20 -0
  19. data/lib/fog/google/parsers/storage/get_service.rb +32 -0
  20. data/lib/fog/google/requests/storage/copy_object.rb +72 -0
  21. data/lib/fog/google/requests/storage/delete_bucket.rb +46 -0
  22. data/lib/fog/google/requests/storage/delete_object.rb +50 -0
  23. data/lib/fog/google/requests/storage/get_bucket.rb +110 -0
  24. data/lib/fog/google/requests/storage/get_bucket_acl.rb +55 -0
  25. data/lib/fog/google/requests/storage/get_object.rb +104 -0
  26. data/lib/fog/google/requests/storage/get_object_acl.rb +66 -0
  27. data/lib/fog/google/requests/storage/get_object_torrent.rb +55 -0
  28. data/lib/fog/google/requests/storage/get_object_url.rb +54 -0
  29. data/lib/fog/google/requests/storage/get_service.rb +53 -0
  30. data/lib/fog/google/requests/storage/head_object.rb +64 -0
  31. data/lib/fog/google/requests/storage/put_bucket.rb +68 -0
  32. data/lib/fog/google/requests/storage/put_bucket_acl.rb +80 -0
  33. data/lib/fog/google/requests/storage/put_object.rb +71 -0
  34. data/lib/fog/google/requests/storage/put_object_url.rb +54 -0
  35. data/lib/fog/google/storage.rb +192 -0
  36. data/spec/google/models/storage/directories_spec.rb +49 -0
  37. data/spec/google/models/storage/directory_spec.rb +83 -0
  38. data/spec/google/models/storage/file_spec.rb +121 -0
  39. data/spec/google/models/storage/files_spec.rb +141 -0
  40. data/spec/google/requests/storage/copy_object_spec.rb +61 -0
  41. data/spec/google/requests/storage/delete_bucket_spec.rb +35 -0
  42. data/spec/google/requests/storage/delete_object_spec.rb +38 -0
  43. data/spec/google/requests/storage/get_bucket_spec.rb +110 -0
  44. data/spec/google/requests/storage/get_object_spec.rb +58 -0
  45. data/spec/google/requests/storage/get_service_spec.rb +32 -0
  46. data/spec/google/requests/storage/head_object_spec.rb +26 -0
  47. data/spec/google/requests/storage/put_bucket_spec.rb +21 -0
  48. data/spec/google/requests/storage/put_object_spec.rb +43 -0
  49. metadata +45 -2
@@ -0,0 +1,110 @@
1
+ require 'pp'
2
+ module Fog
3
+ module Google
4
+ class Storage
5
+ class Real
6
+
7
+ require 'fog/google/parsers/storage/get_bucket'
8
+
9
+ # List information about objects in an Google Storage bucket
10
+ #
11
+ # ==== Parameters
12
+ # * bucket_name<~String> - name of bucket to list object keys from
13
+ # * options<~Hash> - config arguments for list. Defaults to {}.
14
+ # * 'delimiter'<~String> - causes keys with the same string between the prefix
15
+ # value and the first occurence of delimiter to be rolled up
16
+ # * 'marker'<~String> - limits object keys to only those that appear
17
+ # lexicographically after its value.
18
+ # * 'max-keys'<~Integer> - limits number of object keys returned
19
+ # * 'prefix'<~String> - limits object keys to those beginning with its value.
20
+ #
21
+ # ==== Returns
22
+ # * response<~Excon::Response>:
23
+ # * body<~Hash>:
24
+ # * 'Delimeter'<~String> - Delimiter specified for query
25
+ # * 'IsTruncated'<~Boolean> - Whether or not the listing is truncated
26
+ # * 'Marker'<~String> - Marker specified for query
27
+ # * 'MaxKeys'<~Integer> - Maximum number of keys specified for query
28
+ # * 'Name'<~String> - Name of the bucket
29
+ # * 'Prefix'<~String> - Prefix specified for query
30
+ # * 'Contents'<~Array>:
31
+ # * 'ETag'<~String>: Etag of object
32
+ # * 'Key'<~String>: Name of object
33
+ # * 'LastModified'<~String>: Timestamp of last modification of object
34
+ # * 'Owner'<~Hash>:
35
+ # * 'DisplayName'<~String> - Display name of object owner
36
+ # * 'ID'<~String> - Id of object owner
37
+ # * 'Size'<~Integer> - Size of object
38
+ # * 'StorageClass'<~String> - Storage class of object
39
+ #
40
+ def get_bucket(bucket_name, options = {})
41
+ unless bucket_name
42
+ raise ArgumentError.new('bucket_name is required')
43
+ end
44
+ request({
45
+ :expects => 200,
46
+ :headers => {},
47
+ :host => "#{bucket_name}.#{@host}",
48
+ :idempotent => true,
49
+ :method => 'GET',
50
+ :parser => Fog::Parsers::Google::Storage::GetBucket.new,
51
+ :query => options
52
+ })
53
+ end
54
+
55
+ end
56
+
57
+ class Mock
58
+
59
+ def get_bucket(bucket_name, options = {})
60
+ unless bucket_name
61
+ raise ArgumentError.new('bucket_name is required')
62
+ end
63
+ response = Excon::Response.new
64
+ name = /(\w+\.?)*/.match(bucket_name)
65
+ if bucket_name == name.to_s
66
+ if bucket = @data[:buckets][bucket_name]
67
+ contents = bucket[:objects].values.sort {|x,y| x['Key'] <=> y['Key']}.reject do |object|
68
+ (options['prefix'] && object['Key'][0...options['prefix'].length] != options['prefix']) ||
69
+ (options['marker'] && object['Key'] <= options['marker'])
70
+ end.map do |object|
71
+ data = object.reject {|key, value| !['ETag', 'Key', 'LastModified', 'Size', 'StorageClass'].include?(key)}
72
+ data.merge!({
73
+ 'LastModified' => Time.parse(data['LastModified']),
74
+ 'Owner' => bucket['Owner'],
75
+ 'Size' => data['Size'].to_i
76
+ })
77
+ data
78
+ end
79
+ max_keys = options['max-keys'] || 1000
80
+ size = [max_keys, 1000].min
81
+ truncated_contents = contents[0...size]
82
+
83
+ response.status = 200
84
+ response.body = {
85
+ 'Contents' => truncated_contents,
86
+ 'IsTruncated' => truncated_contents.size != contents.size,
87
+ 'Marker' => options['marker'],
88
+ 'MaxKeys' => max_keys,
89
+ 'Name' => bucket['Name'],
90
+ 'Prefix' => options['prefix']
91
+ }
92
+ if options['max-keys'] && options['max-keys'] < response.body['Contents'].length
93
+ response.body['IsTruncated'] = true
94
+ response.body['Contents'] = response.body['Contents'][0...options['max-keys']]
95
+ end
96
+ else
97
+ response.status = 404
98
+ raise(Excon::Errors.status_error({:expects => 200}, response))
99
+ end
100
+ else
101
+ response.status = 400
102
+ raise(Excon::Errors.status_error({:expects => 200}, response))
103
+ end
104
+ response
105
+ end
106
+
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,55 @@
1
+ module Fog
2
+ module Google
3
+ class Storage
4
+ class Real
5
+
6
+ require 'fog/google/parsers/storage/access_control_list'
7
+
8
+ # Get access control list for an Google Storage bucket
9
+ #
10
+ # ==== Parameters
11
+ # * bucket_name<~String> - name of bucket to get access control list for
12
+ #
13
+ # ==== Returns
14
+ # * response<~Excon::Response>:
15
+ # * body<~Hash>:
16
+ # * 'AccessControlPolicy'<~Hash>
17
+ # * 'Owner'<~Hash>:
18
+ # * 'DisplayName'<~String> - Display name of object owner
19
+ # * 'ID'<~String> - Id of object owner
20
+ # * 'AccessControlList'<~Array>:
21
+ # * 'Grant'<~Hash>:
22
+ # * 'Grantee'<~Hash>:
23
+ # * 'DisplayName'<~String> - Display name of grantee
24
+ # * 'ID'<~String> - Id of grantee
25
+ # or
26
+ # * 'URI'<~String> - URI of group to grant access for
27
+ # * 'Permission'<~String> - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP]
28
+ #
29
+ def get_bucket_acl(bucket_name)
30
+ unless bucket_name
31
+ raise ArgumentError.new('bucket_name is required')
32
+ end
33
+ request({
34
+ :expects => 200,
35
+ :headers => {},
36
+ :host => "#{bucket_name}.#{@host}",
37
+ :idempotent => true,
38
+ :method => 'GET',
39
+ :parser => Fog::Parsers::Google::Storage::AccessControlList.new,
40
+ :query => {'acl' => nil}
41
+ })
42
+ end
43
+
44
+ end
45
+
46
+ class Mock
47
+
48
+ def get_bucket_acl(bucket_name)
49
+ Fog::Mock.not_implemented
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,104 @@
1
+ module Fog
2
+ module Google
3
+ class Storage
4
+ class Real
5
+
6
+ # Get an object from Google Storage
7
+ #
8
+ # ==== Parameters
9
+ # * bucket_name<~String> - Name of bucket to read from
10
+ # * object_name<~String> - Name of object to read
11
+ # * options<~Hash>:
12
+ # * 'If-Match'<~String> - Returns object only if its etag matches this value, otherwise returns 412 (Precondition Failed).
13
+ # * 'If-Modified-Since'<~Time> - Returns object only if it has been modified since this time, otherwise returns 304 (Not Modified).
14
+ # * 'If-None-Match'<~String> - Returns object only if its etag differs from this value, otherwise returns 304 (Not Modified)
15
+ # * 'If-Unmodified-Since'<~Time> - Returns object only if it has not been modified since this time, otherwise returns 412 (Precodition Failed).
16
+ # * 'Range'<~String> - Range of object to download
17
+ # * 'versionId'<~String> - specify a particular version to retrieve
18
+ #
19
+ # ==== Returns
20
+ # * response<~Excon::Response>:
21
+ # * body<~String> - Contents of object
22
+ # * headers<~Hash>:
23
+ # * 'Content-Length'<~String> - Size of object contents
24
+ # * 'Content-Type'<~String> - MIME type of object
25
+ # * 'ETag'<~String> - Etag of object
26
+ # * 'Last-Modified'<~String> - Last modified timestamp for object
27
+ #
28
+ def get_object(bucket_name, object_name, options = {}, &block)
29
+ unless bucket_name
30
+ raise ArgumentError.new('bucket_name is required')
31
+ end
32
+ unless object_name
33
+ raise ArgumentError.new('object_name is required')
34
+ end
35
+ if version_id = options.delete('versionId')
36
+ query = {'versionId' => version_id}
37
+ end
38
+ headers = {}
39
+ headers['If-Modified-Since'] = options['If-Modified-Since'].utc.strftime("%a, %d %b %Y %H:%M:%S +0000") if options['If-Modified-Since']
40
+ headers['If-Unmodified-Since'] = options['If-Unmodified-Since'].utc.strftime("%a, %d %b %Y %H:%M:%S +0000") if options['If-Modified-Since']
41
+ headers.merge!(options)
42
+ request({
43
+ :expects => 200,
44
+ :headers => headers,
45
+ :host => "#{bucket_name}.#{@host}",
46
+ :idempotent => true,
47
+ :method => 'GET',
48
+ :path => CGI.escape(object_name),
49
+ :query => query
50
+ }, &block)
51
+ end
52
+
53
+ end
54
+
55
+ class Mock
56
+
57
+ def get_object(bucket_name, object_name, options = {}, &block)
58
+ unless bucket_name
59
+ raise ArgumentError.new('bucket_name is required')
60
+ end
61
+ unless object_name
62
+ raise ArgumentError.new('object_name is required')
63
+ end
64
+ response = Excon::Response.new
65
+ if (bucket = @data[:buckets][bucket_name]) && (object = bucket[:objects][object_name])
66
+ if options['If-Match'] && options['If-Match'] != object['ETag']
67
+ response.status = 412
68
+ elsif options['If-Modified-Since'] && options['If-Modified-Since'] > Time.parse(object['LastModified'])
69
+ response.status = 304
70
+ elsif options['If-None-Match'] && options['If-None-Match'] == object['ETag']
71
+ response.status = 304
72
+ elsif options['If-Unmodified-Since'] && options['If-Unmodified-Since'] < Time.parse(object['LastModified'])
73
+ response.status = 412
74
+ else
75
+ response.status = 200
76
+ response.headers = {
77
+ 'Content-Length' => object['Size'],
78
+ 'Content-Type' => object['Content-Type'],
79
+ 'ETag' => object['ETag'],
80
+ 'Last-Modified' => object['LastModified']
81
+ }
82
+ unless block_given?
83
+ response.body = object[:body]
84
+ else
85
+ data = StringIO.new(object[:body])
86
+ remaining = data.length
87
+ while remaining > 0
88
+ chunk = data.read([remaining, Excon::CHUNK_SIZE].min)
89
+ block.call(chunk)
90
+ remaining -= Excon::CHUNK_SIZE
91
+ end
92
+ end
93
+ end
94
+ else
95
+ response.status = 404
96
+ raise(Excon::Errors.status_error({:expects => 200}, response))
97
+ end
98
+ response
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,66 @@
1
+ module Fog
2
+ module Google
3
+ class Storage
4
+ class Real
5
+
6
+ require 'fog/google/parsers/storage/access_control_list'
7
+
8
+ # Get access control list for an Google Storage object
9
+ #
10
+ # ==== Parameters
11
+ # * bucket_name<~String> - name of bucket containing object
12
+ # * object_name<~String> - name of object to get access control list for
13
+ # * options<~Hash>:
14
+ # * 'versionId'<~String> - specify a particular version to retrieve
15
+ #
16
+ # ==== Returns
17
+ # * response<~Excon::Response>:
18
+ # * body<~Hash>:
19
+ # * 'AccessControlPolicy'<~Hash>
20
+ # * 'Owner'<~Hash>:
21
+ # * 'DisplayName'<~String> - Display name of object owner
22
+ # * 'ID'<~String> - Id of object owner
23
+ # * 'AccessControlList'<~Array>:
24
+ # * 'Grant'<~Hash>:
25
+ # * 'Grantee'<~Hash>:
26
+ # * 'DisplayName'<~String> - Display name of grantee
27
+ # * 'ID'<~String> - Id of grantee
28
+ # or
29
+ # * 'URI'<~String> - URI of group to grant access for
30
+ # * 'Permission'<~String> - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP]
31
+ #
32
+ def get_object_acl(bucket_name, object_name, options = {})
33
+ unless bucket_name
34
+ raise ArgumentError.new('bucket_name is required')
35
+ end
36
+ unless object_name
37
+ raise ArgumentError.new('object_name is required')
38
+ end
39
+ query = {'acl' => nil}
40
+ if version_id = options.delete('versionId')
41
+ query['versionId'] = version_id
42
+ end
43
+ request({
44
+ :expects => 200,
45
+ :headers => {},
46
+ :host => "#{bucket_name}.#{@host}",
47
+ :idempotent => true,
48
+ :method => 'GET',
49
+ :parser => Fog::Parsers::Google::Storage::AccessControlList.new,
50
+ :path => CGI.escape(object_name),
51
+ :query => query
52
+ })
53
+ end
54
+
55
+ end
56
+
57
+ class Mock
58
+
59
+ def get_object_acl(bucket_name, object_name)
60
+ Fog::Mock.not_implemented
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,55 @@
1
+ module Fog
2
+ module Google
3
+ class Storage
4
+ class Real
5
+
6
+ # Get torrent for an Google Storage object
7
+ #
8
+ # ==== Parameters
9
+ # * bucket_name<~String> - name of bucket containing object
10
+ # * object_name<~String> - name of object to get torrent for
11
+ #
12
+ # ==== Returns
13
+ # * response<~Excon::Response>:
14
+ # * body<~Hash>:
15
+ # * 'AccessControlPolicy'<~Hash>
16
+ # * 'Owner'<~Hash>:
17
+ # * 'DisplayName'<~String> - Display name of object owner
18
+ # * 'ID'<~String> - Id of object owner
19
+ # * 'AccessControlList'<~Array>:
20
+ # * 'Grant'<~Hash>:
21
+ # * 'Grantee'<~Hash>:
22
+ # * 'DisplayName'<~String> - Display name of grantee
23
+ # * 'ID'<~String> - Id of grantee
24
+ # * 'Permission'<~String> - Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP]
25
+ #
26
+ def get_object_torrent(bucket_name, object_name)
27
+ unless bucket_name
28
+ raise ArgumentError.new('bucket_name is required')
29
+ end
30
+ unless object_name
31
+ raise ArgumentError.new('object_name is required')
32
+ end
33
+ request({
34
+ :expects => 200,
35
+ :headers => {},
36
+ :host => "#{bucket_name}.#{@host}",
37
+ :idempotent => true,
38
+ :method => 'GET',
39
+ :path => CGI.escape(object_name),
40
+ :query => {'torrent' => nil}
41
+ })
42
+ end
43
+
44
+ end
45
+
46
+ class Mock
47
+
48
+ def get_object_object(bucket_name, object_name)
49
+ Fog::Mock.not_implemented
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ module Fog
2
+ module Google
3
+ class Storage
4
+ class Real
5
+
6
+ # Get an expiring object url from Google Storage
7
+ #
8
+ # ==== Parameters
9
+ # * bucket_name<~String> - Name of bucket containing object
10
+ # * object_name<~String> - Name of object to get expiring url for
11
+ # * expires<~Time> - An expiry time for this url
12
+ #
13
+ # ==== Returns
14
+ # * response<~Excon::Response>:
15
+ # * body<~String> - url for object
16
+ #
17
+ def get_object_url(bucket_name, object_name, expires)
18
+ unless bucket_name
19
+ raise ArgumentError.new('bucket_name is required')
20
+ end
21
+ unless object_name
22
+ raise ArgumentError.new('object_name is required')
23
+ end
24
+ url({
25
+ :headers => {},
26
+ :host => "#{bucket_name}.#{@host}",
27
+ :method => 'GET',
28
+ :path => CGI.escape(object_name)
29
+ }, expires)
30
+ end
31
+
32
+ end
33
+
34
+ class Mock
35
+
36
+ def get_object_url(bucket_name, object_name, expires)
37
+ unless bucket_name
38
+ raise ArgumentError.new('bucket_name is required')
39
+ end
40
+ unless object_name
41
+ raise ArgumentError.new('object_name is required')
42
+ end
43
+ url({
44
+ :headers => {},
45
+ :host => "#{bucket_name}.#{@host}",
46
+ :method => 'GET',
47
+ :path => CGI.escape(object_name)
48
+ }, expires)
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end