simple_aws 1.0.0.pre1 → 1.0.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +16 -15
- data/lib/aws/api.rb +16 -5
- data/lib/aws/cloud_front.rb +65 -4
- data/lib/aws/core/connection.rb +16 -0
- data/lib/aws/import_export.rb +1 -1
- data/lib/aws/s3.rb +101 -17
- data/samples/s3.rb +6 -6
- data/samples/s3_batch_download.rb +53 -0
- data/simple_aws.gemspec +1 -1
- data/test/aws/s3_test.rb +10 -2
- metadata +7 -6
data/README.md
CHANGED
@@ -1,40 +1,36 @@
|
|
1
1
|
SimpleAWS [![Travis CI Build Status](https://secure.travis-ci.org/jameskilton/simple_aws.png)](http://travis-ci.org/jameskilton/simple_aws)
|
2
2
|
=========
|
3
3
|
|
4
|
-
A thin, simple, forward compatible Ruby wrapper around the various Amazon
|
4
|
+
A thin, simple, forward compatible Ruby wrapper around the various Amazon Web Service APIs.
|
5
5
|
|
6
6
|
What?! Why?
|
7
7
|
-----------
|
8
8
|
|
9
9
|
Do we really need another Ruby library to talk to Amazon Web Services? Aren't there enough libraries out there that could just use some more help to make them better? What about [fog](http://fog.io), or [aws-sdk](http://rubygems.org/gems/aws-sdk), or [aws](http://rubygems.org/gems/aws), or [right_aws](http://rubygems.org/gems/right_aws)?
|
10
10
|
|
11
|
-
While there are a number of well used libraries, I feel they have all fallen prey to the same two problems:
|
11
|
+
While there are a number of well used libraries, I feel they have all fallen prey to the same two problems: they are far too complex for what they are and they all lack forward compatibility.
|
12
12
|
|
13
13
|
### Complexity
|
14
14
|
|
15
|
-
Every Ruby AWS library in use today is simply too complex.
|
15
|
+
Every Ruby AWS library in use today is simply too complex. Each one I've tried to use has ended up hurting my productivity as I often found myself diving into the library's code to figure out how to call the API method in question. Instead of just working with Amazon's API, I end up fighting the library, constantly having to re-learn whatever abstraction said library is trying to provide. Every library mentioned either hard-codes parameter lists, has it's own mapping from hash keys to AWS parameters, or wraps up an Object API around everything, leading to confusion and more lost productivity when that abstraction leaks. Software is supposed to be simple to use; it's supposed to make your life easier. I've yet to find an AWS library that does this.
|
16
16
|
|
17
17
|
### Forward Compatibility
|
18
18
|
|
19
|
-
|
19
|
+
Outside of the pervasive complexity of these libraries, what finally drove me to create this library is the complete lack of forward compatibility in all of them. Any time I wanted to use a new parameter, new action, or new API, I would need to jump into the library itself to implement the missing pieces. In normal OSS fashion, this is of course to be lauded, contributing back to libraries is what makes software better. However, in the case of API wrappers, this very quickly becomes a frustration.
|
20
20
|
|
21
|
-
Amazon constantly updates AWS APIs, adding parameters and actions, and at times entire new APIs. An AWS library should work *with* the API in question, not fight against it. The only thing a hard-coded parameter list does is add confusion
|
21
|
+
Amazon constantly updates AWS APIs, adding parameters and actions, and at times entire new APIs. An AWS library should work *with* the API in question, not fight against it. The only thing a hard-coded parameter list does is add confusion. When you have to figure out how AWS parameters map to library parameters, or hash keys, your productivity drops. When you have to figure out how an object is calling an AWS library, and how you're supposed to use that object, your productivity drops. Likewise when you finally realize that the library does not currently support the action, parameter, or API you're trying to use at the time, your productivity is now at a complete stop.
|
22
22
|
|
23
|
-
The name SimpleAWS isn't a wish or hope, it's the core philosophy. This library focuses on being a very thin communication layer between your Ruby code and Amazon's AWS APIs. Let SimpleAWS handle the messy communication details so your code can do what it needs to do letting you be more productive.
|
24
|
-
|
25
|
-
In short, it's the Unix philosophy, SimpleAWS does one thing and does it well and nothing else.
|
23
|
+
SimpleAWS simply says no, no more leaky abstractions and confusing APIs. Just use the names of the API methods and parameters as defined in Amazon's documentation! If a new parameter is added to the API you're using, just use it. The name SimpleAWS isn't a wish or hope, it's the core philosophy. This library focuses on being a very thin communication layer between your Ruby code and Amazon's AWS APIs. Let SimpleAWS handle the messy communication details so your code can do what it needs to do letting you be more productive.
|
26
24
|
|
27
25
|
|
28
26
|
Surely SimpleAWS isn't just `curl`?
|
29
27
|
-----------------------------------
|
30
28
|
|
31
|
-
It's well know that AWS has its share of warts and wtfs. SimpleAWS doesn't try to fix these
|
32
|
-
|
33
|
-
What SimpleAWS does do is add some logic to ensure it follows the Principle of Least Surprise.
|
29
|
+
It's well know that AWS has its share of warts and wtfs. SimpleAWS doesn't try to fix these. What SimpleAWS does do is add as little logic as possible to make you productive and to ensure it follows the Principle of Least Surprise.
|
34
30
|
|
35
31
|
### Calling
|
36
32
|
|
37
|
-
First of all, calling actions are implemented as ruby methods, handled through mainly through `method_missing` (S3 and CloudFront are the two exceptions). You can call the AWS actions by AWSName or by ruby_name, they both work:
|
33
|
+
First of all, calling actions are implemented as ruby methods, handled through mainly through `method_missing` (S3 and CloudFront are the two current exceptions). You can call the AWS actions by AWSName or by ruby_name, they both work:
|
38
34
|
|
39
35
|
```ruby
|
40
36
|
ec2 = AWS::EC2.new key, secret
|
@@ -50,7 +46,7 @@ ec2.DescribeInstances
|
|
50
46
|
|
51
47
|
### Parameters
|
52
48
|
|
53
|
-
|
49
|
+
Adding parameters to your method calls follows similar rules, with some Quality of Life improvements. The following three are equivalent:
|
54
50
|
|
55
51
|
#### Just Call It
|
56
52
|
|
@@ -92,9 +88,9 @@ ec2.describe_instances({
|
|
92
88
|
|
93
89
|
### Response Parsing
|
94
90
|
|
95
|
-
All requests return an AWS::Response which does a few cleanup tasks on the resulting XML to make it easier to query and to hide some of the worst warts an XML body tends to have.
|
91
|
+
All requests return an AWS::Response object which does a few cleanup tasks on the resulting XML to make it easier to query and to hide some of the worst warts an XML body tends to have.
|
96
92
|
|
97
|
-
First of all, wherever AWS returns a list of items, they
|
93
|
+
First of all, wherever AWS returns a list of items, they often get wrapped up in an `<item>` or `<member>` wrapper tag. AWS::Response gets rid of those tags and gives you a flat array to work with.
|
98
94
|
|
99
95
|
Second, the resulting XML can have one or two wrapper objects that do nothing but encapsulate the information you're interested in. AWS::Response also jumps past these wrapper objects so you have direct access to the data in the response.
|
100
96
|
|
@@ -123,6 +119,11 @@ These are the Amazon APIs that SimpleAWS currently handles:
|
|
123
119
|
* {AWS::SES SES}
|
124
120
|
* {AWS::CloudFront CloudFront}
|
125
121
|
|
122
|
+
Not Currently Implemented
|
123
|
+
-------------------------
|
124
|
+
|
125
|
+
* DynamoDB (API docs aren't up yet, and the samples are hard to follow)
|
126
|
+
|
126
127
|
Currently Out-Of-Scope
|
127
128
|
----------------------
|
128
129
|
|
data/lib/aws/api.rb
CHANGED
@@ -11,12 +11,15 @@ module AWS
|
|
11
11
|
# implementing various APIs:
|
12
12
|
#
|
13
13
|
# http://docs.amazonwebservices.com/general/latest/gr/index.html?rande.html
|
14
|
+
#
|
14
15
|
##
|
15
16
|
class API
|
16
17
|
class << self
|
17
18
|
|
18
19
|
##
|
19
20
|
# Define the AWS endpoint for the API being wrapped.
|
21
|
+
#
|
22
|
+
# @param endpoint [String] Subdomain endpoint for this API. E.g. "s3" for Amazon's S3
|
20
23
|
##
|
21
24
|
def endpoint(endpoint)
|
22
25
|
@endpoint = endpoint
|
@@ -24,8 +27,8 @@ module AWS
|
|
24
27
|
|
25
28
|
##
|
26
29
|
# Specify a default region for all requests for this API.
|
27
|
-
#
|
28
|
-
#
|
30
|
+
#
|
31
|
+
# @param region [String] Specify the region this API defaults to
|
29
32
|
##
|
30
33
|
def default_region(region)
|
31
34
|
@default_region = region
|
@@ -35,13 +38,17 @@ module AWS
|
|
35
38
|
# Specify whether this API uses HTTPS for requests. If not set,
|
36
39
|
# the system will use HTTP. Some API endpoints are not available under
|
37
40
|
# HTTP and some are only HTTP.
|
41
|
+
#
|
42
|
+
# @param value [Boolean] Set whether this API uses HTTPS by default or not
|
38
43
|
##
|
39
44
|
def use_https(value)
|
40
45
|
@use_https = value
|
41
46
|
end
|
42
47
|
|
43
48
|
##
|
44
|
-
# Specify the AWS version of the API in question.
|
49
|
+
# Specify the AWS version of the API in question.
|
50
|
+
#
|
51
|
+
# @param version [String] The version this API currently uses.
|
45
52
|
##
|
46
53
|
def version(version)
|
47
54
|
@version = version
|
@@ -53,8 +60,10 @@ module AWS
|
|
53
60
|
|
54
61
|
##
|
55
62
|
# Construct a new access object for the API in question.
|
56
|
-
#
|
57
|
-
#
|
63
|
+
#
|
64
|
+
# @param access_key [String] Amazon access key
|
65
|
+
# @param secret_key [String] Amazon secret key
|
66
|
+
# @param region [String] Give a specific region to talk to
|
58
67
|
##
|
59
68
|
def initialize(access_key, secret_key, region = nil)
|
60
69
|
@access_key = access_key
|
@@ -68,6 +77,8 @@ module AWS
|
|
68
77
|
|
69
78
|
##
|
70
79
|
# Get the full host name for the current API
|
80
|
+
#
|
81
|
+
# @return [String] Full URI for this API
|
71
82
|
##
|
72
83
|
def uri
|
73
84
|
return @uri if @uri
|
data/lib/aws/cloud_front.rb
CHANGED
@@ -63,12 +63,73 @@ module AWS
|
|
63
63
|
super(key, secret)
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
##
|
67
|
+
# Send a request using HTTP GET
|
68
|
+
#
|
69
|
+
# @param path [String] The path of the resource at hand
|
70
|
+
# @param options [Hash] Options as defined above
|
71
|
+
#
|
72
|
+
# @return [AWS::Response] The results of the request
|
73
|
+
#
|
74
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
75
|
+
##
|
76
|
+
def get(path, options = {})
|
77
|
+
call :get, path, options
|
70
78
|
end
|
71
79
|
|
80
|
+
##
|
81
|
+
# Send a request using HTTP POST
|
82
|
+
#
|
83
|
+
# @param path [String] The path of the resource at hand
|
84
|
+
# @param options [Hash] Options as defined above
|
85
|
+
#
|
86
|
+
# @return [AWS::Response] The results of the request
|
87
|
+
#
|
88
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
89
|
+
##
|
90
|
+
def post(path, options = {})
|
91
|
+
call :post, path, options
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Send a request using HTTP PUT
|
96
|
+
#
|
97
|
+
# @param path [String] The path of the resource at hand
|
98
|
+
# @param options [Hash] Options as defined above
|
99
|
+
#
|
100
|
+
# @return [AWS::Response] The results of the request
|
101
|
+
#
|
102
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
103
|
+
##
|
104
|
+
def put(path, options = {})
|
105
|
+
call :put, path, options
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Send a request using HTTP DELETE
|
110
|
+
#
|
111
|
+
# @param path [String] The path of the resource at hand
|
112
|
+
# @param options [Hash] Options as defined above
|
113
|
+
#
|
114
|
+
# @return [AWS::Response] The results of the request
|
115
|
+
#
|
116
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
117
|
+
##
|
118
|
+
def delete(path, options = {})
|
119
|
+
call :delete, path, options
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Execute an HTTP request against CloudFront.
|
124
|
+
#
|
125
|
+
# @param method [Symbol, String] The HTTP method to use
|
126
|
+
# @param path [String] The path of the resource at hand
|
127
|
+
# @param options [Hash] Options as defined above
|
128
|
+
#
|
129
|
+
# @return [AWS::Response] The results of the request
|
130
|
+
#
|
131
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
132
|
+
##
|
72
133
|
def call(method, path, options = {})
|
73
134
|
request = AWS::Request.new method, self.uri, "/#{self.version}#{path}"
|
74
135
|
|
data/lib/aws/core/connection.rb
CHANGED
@@ -29,8 +29,24 @@ end
|
|
29
29
|
|
30
30
|
module AWS
|
31
31
|
|
32
|
+
##
|
33
|
+
# Custom response parser to handle the various craziness of the AWS API
|
34
|
+
##
|
35
|
+
class SimpleAWSParser < HTTParty::Parser
|
36
|
+
def parse
|
37
|
+
if supports_format?
|
38
|
+
super
|
39
|
+
elsif body =~ %r{<\?xml}
|
40
|
+
xml
|
41
|
+
else
|
42
|
+
body
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
32
47
|
class HTTP
|
33
48
|
include HTTParty
|
49
|
+
parser SimpleAWSParser
|
34
50
|
end
|
35
51
|
|
36
52
|
##
|
data/lib/aws/import_export.rb
CHANGED
@@ -10,7 +10,7 @@ module AWS
|
|
10
10
|
# http://docs.amazonwebservices.com/AWSImportExport/latest/API/Welcome.html
|
11
11
|
#
|
12
12
|
# All requests are POST and always through HTTPS.
|
13
|
-
# This API does not support region specifiers
|
13
|
+
# This API does not support region specifiers.
|
14
14
|
#
|
15
15
|
# @see AWS::CallTypes::ActionParam Calling rules
|
16
16
|
# @see AWS::Response Response handling
|
data/lib/aws/s3.rb
CHANGED
@@ -55,7 +55,13 @@ module AWS
|
|
55
55
|
# As such, this API does not offer streaming downloads of file data from S3.
|
56
56
|
# That is up to you to implement at this time, by running a HEAD to get
|
57
57
|
# Content-Length then repeated GETs using the "Range:bytes" header to specify
|
58
|
-
# which parts to download next.
|
58
|
+
# which parts to download next. You can see an example of this in samples/s3_batch_download.rb.
|
59
|
+
#
|
60
|
+
# Quality of Life note: if you forget the leading / (forward slash) in the path
|
61
|
+
# of a resource when# working with a bucket, this library will recognize this and
|
62
|
+
# fix the path for you. Thus, the following is also a valid call:
|
63
|
+
#
|
64
|
+
# s3.put "object/name.txt", :bucket => "bucket_name", :body => File.open()
|
59
65
|
#
|
60
66
|
# Raw file data in a response will be available in the #body method on the Response
|
61
67
|
# returned by the method call.
|
@@ -67,12 +73,18 @@ module AWS
|
|
67
73
|
|
68
74
|
##
|
69
75
|
# Build a full URL for the resource at +path+.
|
70
|
-
# If options includes :expires, this url will be a signed url. :expires
|
71
|
-
# needs to be the raw Unix timestamp at which this URL will expire, as
|
72
|
-
# defined in the S3 documentation.
|
73
76
|
#
|
74
|
-
#
|
75
|
-
#
|
77
|
+
# @param path [String] The path of the resource that needs a URL
|
78
|
+
# @param options [Hash] Options on how this URL will be generated.
|
79
|
+
#
|
80
|
+
# If options includes +:expires+, this url will be a signed url. +:expires+
|
81
|
+
# needs to be the raw Unix timestamp at which this URL will expire, as
|
82
|
+
# defined in the S3 documentation.
|
83
|
+
#
|
84
|
+
# Otherwise, +options+ can take anything as described above, but it
|
85
|
+
# will not use +:headers+ or anything related to +:body+.
|
86
|
+
#
|
87
|
+
# @return [String] The URL to the requested resource
|
76
88
|
##
|
77
89
|
def url_for(path, options = {})
|
78
90
|
request = build_request(:get, path, options)
|
@@ -88,7 +100,8 @@ module AWS
|
|
88
100
|
|
89
101
|
if expires_at = options[:expires]
|
90
102
|
# Small hack, expires is in the Date section of the
|
91
|
-
# signing string, so we just do that here
|
103
|
+
# signing string, so we just do that here so that we don't
|
104
|
+
# muddy up build_signature_for
|
92
105
|
request.headers["Date"] = expires_at.to_i
|
93
106
|
|
94
107
|
signature = "Signature=#{build_signature_for(request)}"
|
@@ -101,18 +114,92 @@ module AWS
|
|
101
114
|
url
|
102
115
|
end
|
103
116
|
|
104
|
-
|
105
|
-
|
106
|
-
|
117
|
+
##
|
118
|
+
# Send a request using HTTP GET
|
119
|
+
#
|
120
|
+
# @param path [String] The path of the resource at hand
|
121
|
+
# @param options [Hash] Options as defined above
|
122
|
+
#
|
123
|
+
# @return [AWS::Response] The results of the request
|
124
|
+
#
|
125
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
126
|
+
##
|
127
|
+
def get(path, options = {})
|
128
|
+
call :get, path, options
|
129
|
+
end
|
107
130
|
|
108
|
-
|
109
|
-
|
110
|
-
|
131
|
+
##
|
132
|
+
# Send a request using HTTP PUT
|
133
|
+
#
|
134
|
+
# @param path [String] The path of the resource at hand
|
135
|
+
# @param options [Hash] Options as defined above
|
136
|
+
#
|
137
|
+
# @return [AWS::Response] The results of the request
|
138
|
+
#
|
139
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
140
|
+
##
|
141
|
+
def put(path, options = {})
|
142
|
+
call :put, path, options
|
111
143
|
end
|
112
144
|
|
145
|
+
##
|
146
|
+
# Send a request using HTTP DELETE
|
147
|
+
#
|
148
|
+
# @param path [String] The path of the resource at hand
|
149
|
+
# @param options [Hash] Options as defined above
|
150
|
+
#
|
151
|
+
# @return [AWS::Response] The results of the request
|
152
|
+
#
|
153
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
154
|
+
##
|
155
|
+
def delete(path, options = {})
|
156
|
+
call :delete, path, options
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Send a request using HTTP HEAD
|
161
|
+
#
|
162
|
+
# @param path [String] The path of the resource at hand
|
163
|
+
# @param options [Hash] Options as defined above
|
164
|
+
#
|
165
|
+
# @return [AWS::Response] The results of the request
|
166
|
+
#
|
167
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
168
|
+
##
|
169
|
+
def head(path, options = {})
|
170
|
+
call :head, path, options
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Execute an HTTP request against S3.
|
175
|
+
#
|
176
|
+
# @param method [Symbol, String] The HTTP method to use
|
177
|
+
# @param path [String] The path of the resource at hand
|
178
|
+
# @param options [Hash] Options as defined above
|
179
|
+
#
|
180
|
+
# @return [AWS::Response] The results of the request
|
181
|
+
#
|
182
|
+
# @raise [AWS::UnsuccessfulResponse, AWS::UnknownErrorResponse] on response errors
|
183
|
+
##
|
184
|
+
def call(method, path, options = {})
|
185
|
+
request = self.build_request method, path, options
|
186
|
+
|
187
|
+
connection = AWS::Connection.new
|
188
|
+
connection.call finish_and_sign_request(request)
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Build a request but do not send it. Helpful for debugging.
|
193
|
+
#
|
194
|
+
# @param method [Symbol, String] The HTTP method to use
|
195
|
+
# @param path [String] The path of the resource at hand
|
196
|
+
# @param options [Hash] Options as defined above
|
197
|
+
#
|
198
|
+
# @return [AWS::Request] Completed but not yet signed request object
|
199
|
+
##
|
113
200
|
def build_request(method, path, options = {})
|
114
201
|
if options[:bucket]
|
115
|
-
path =
|
202
|
+
path = "/#{options[:bucket]}/#{path}".gsub("//", "/")
|
116
203
|
end
|
117
204
|
|
118
205
|
request = AWS::Request.new method, self.uri, path
|
@@ -156,9 +243,6 @@ module AWS
|
|
156
243
|
request
|
157
244
|
end
|
158
245
|
|
159
|
-
##
|
160
|
-
# S3 handles region endpoints a little differently
|
161
|
-
##
|
162
246
|
def uri
|
163
247
|
return @uri if @uri
|
164
248
|
|
data/samples/s3.rb
CHANGED
@@ -45,15 +45,15 @@ puts "", "Uploading #{file_name} to #{bucket_name}:", ""
|
|
45
45
|
bad_usage unless file_name
|
46
46
|
uploaded_file_name = File.basename file_name
|
47
47
|
|
48
|
-
p s3.put(
|
48
|
+
p s3.put(uploaded_file_name, :bucket => bucket_name, :file => File.open(file_name))
|
49
49
|
|
50
50
|
puts "", "Checking that the file now exists...", ""
|
51
51
|
|
52
|
-
p s3.head(
|
52
|
+
p s3.head(uploaded_file_name, :bucket => bucket_name)
|
53
53
|
|
54
54
|
puts "", "Getting file again", ""
|
55
55
|
|
56
|
-
p s3.get(
|
56
|
+
p s3.get(uploaded_file_name, :bucket => bucket_name,
|
57
57
|
:params => {
|
58
58
|
"response-content-disposition" => "attachment",
|
59
59
|
"response-content-type" => "text/ruby",
|
@@ -61,18 +61,18 @@ p s3.get("/#{uploaded_file_name}", :bucket => bucket_name,
|
|
61
61
|
|
62
62
|
puts "", "Signed, expiring URL for this resource: ", ""
|
63
63
|
|
64
|
-
puts s3.url_for(
|
64
|
+
puts s3.url_for(uploaded_file_name, :bucket => bucket_name,
|
65
65
|
:expires => Time.now.to_i + 120,
|
66
66
|
:params => { "response-content-disposition" => "attachment" })
|
67
67
|
|
68
68
|
puts "", "Deleting the file from S3", ""
|
69
69
|
|
70
|
-
p s3.delete(
|
70
|
+
p s3.delete(uploaded_file_name, :bucket => bucket_name)
|
71
71
|
|
72
72
|
puts "", "Checking that file is no longer in S3...", ""
|
73
73
|
|
74
74
|
begin
|
75
|
-
p s3.head(
|
75
|
+
p s3.head(uploaded_file_name, :bucket => bucket_name)
|
76
76
|
rescue => ex
|
77
77
|
puts "Not found: #{ex.message}"
|
78
78
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
$: << File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'aws/s3'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Expects your Amazon keys to be in the environment, something like
|
7
|
+
#
|
8
|
+
# export AWS_KEY="KEY"
|
9
|
+
# export AWS_SECRET="SECRET"
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
# ruby sample/s3.rb [resource path] [file to save to]
|
13
|
+
#
|
14
|
+
# This script shows one way to work with batch downloading big files from S3.
|
15
|
+
# Ensure the resource path starts with the bucket in question.
|
16
|
+
##
|
17
|
+
|
18
|
+
def bad_usage
|
19
|
+
puts ""
|
20
|
+
puts "Usage:"
|
21
|
+
puts " ruby sample/s3_batch_download.rb [bucket name] [file to use]"
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
s3 = AWS::S3.new ENV["AWS_KEY"], ENV["AWS_SECRET"]
|
26
|
+
|
27
|
+
s3_resource = ARGV[0]
|
28
|
+
save_to = ARGV[1]
|
29
|
+
batch_size = 1_000_000
|
30
|
+
|
31
|
+
|
32
|
+
# First, get the full size of the file in question
|
33
|
+
file_size = s3.head(s3_resource).headers["content-length"].to_i
|
34
|
+
|
35
|
+
puts "File is #{file_size} bytes"
|
36
|
+
puts "Now downloading in batches of #{batch_size} bytes"
|
37
|
+
|
38
|
+
chunk_count = 0
|
39
|
+
bytes_start = 0
|
40
|
+
bytes_to = batch_size
|
41
|
+
|
42
|
+
File.open save_to, "w+" do |file|
|
43
|
+
while bytes_start < file_size
|
44
|
+
puts "Chunk #{chunk_count} : #{bytes_start} - #{bytes_to}"
|
45
|
+
file.write s3.get(s3_resource, :headers => {"Range" => "bytes=#{bytes_start}-#{bytes_to}" }).body
|
46
|
+
|
47
|
+
bytes_start = bytes_to + 1
|
48
|
+
bytes_to += batch_size
|
49
|
+
chunk_count += 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
puts "Done"
|
data/simple_aws.gemspec
CHANGED
data/test/aws/s3_test.rb
CHANGED
@@ -71,16 +71,24 @@ describe AWS::S3 do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
it "rebuilds the
|
74
|
+
it "rebuilds the path if :bucket given" do
|
75
75
|
AWS::Connection.any_instance.expects(:call).with do |request|
|
76
76
|
request.path.must_equal "/bucket-name/"
|
77
|
-
request.host.must_equal "https://s3.amazonaws.com"
|
78
77
|
true
|
79
78
|
end
|
80
79
|
|
81
80
|
@api.get "/", :bucket => "bucket-name"
|
82
81
|
end
|
83
82
|
|
83
|
+
it "auto-fixes path names if not preceeded by a /" do
|
84
|
+
AWS::Connection.any_instance.expects(:call).with do |request|
|
85
|
+
request.path.must_equal "/bucket-name/object_name/that_thing.jpg"
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
@api.get "object_name/that_thing.jpg", :bucket => "bucket-name"
|
90
|
+
end
|
91
|
+
|
84
92
|
it "takes parameters" do
|
85
93
|
AWS::Connection.any_instance.expects(:call).with do |request|
|
86
94
|
request.params["Parameter1"].must_equal "Value2"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_aws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre2
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
|
-
requirement: &
|
16
|
+
requirement: &70269561987000 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.5.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70269561987000
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: httparty
|
27
|
-
requirement: &
|
27
|
+
requirement: &70269561981040 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 0.8.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70269561981040
|
36
36
|
description: SimpleAWS is a clean, simple, and forward compatible library for talking
|
37
37
|
to Amazon's AWS APIs.
|
38
38
|
email:
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- samples/elb.rb
|
78
78
|
- samples/iam.rb
|
79
79
|
- samples/s3.rb
|
80
|
+
- samples/s3_batch_download.rb
|
80
81
|
- samples/sqs.rb
|
81
82
|
- samples/turk.rb
|
82
83
|
- simple_aws.gemspec
|