s3cp 1.0.6 → 1.1.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +45 -33
- data/bin/s3buckets +3 -0
- data/lib/s3cp/#Untitled-1# +35 -0
- data/lib/s3cp/s3buckets.rb +41 -0
- data/lib/s3cp/s3cat.rb +6 -14
- data/lib/s3cp/s3cp.rb +42 -51
- data/lib/s3cp/s3du.rb +18 -32
- data/lib/s3cp/s3ls.rb +34 -45
- data/lib/s3cp/s3mod.rb +2 -9
- data/lib/s3cp/s3rm.rb +14 -31
- data/lib/s3cp/s3stat.rb +5 -13
- data/lib/s3cp/s3up.rb +9 -7
- data/lib/s3cp/utils.rb +82 -2
- data/lib/s3cp/version.rb +1 -1
- metadata +22 -33
data/History.txt
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
+
=== 1.1.0 / (Pending)
|
2
|
+
|
3
|
+
* Changed: Underlying AWS library has been changed from 'right-aws' to the official
|
4
|
+
AWS SDK ('aws-sdk'). The main driver for this is to stay current on the
|
5
|
+
latest features, including instance-specific roles, temporary credentials,
|
6
|
+
etc.
|
7
|
+
|
8
|
+
* Added: New 's3buckets' command displays all S3 buckets associated with the
|
9
|
+
account.
|
10
|
+
|
11
|
+
* Added: New '--acl PERMISSION' option to 's3cp' and 's3up' commands.
|
12
|
+
|
1
13
|
=== 1.0.6 / (2012-07-23)
|
2
14
|
|
3
15
|
* Fixed: s3cp would exit with errorlevel 0 despite errors when running in
|
4
|
-
|
16
|
+
interactive mode.
|
5
17
|
|
6
18
|
=== 1.0.5 / (2012-06-25)
|
7
19
|
|
@@ -15,15 +27,15 @@
|
|
15
27
|
|
16
28
|
* Added: Exponential backoff for `s3cp` command based on the formula:
|
17
29
|
|
18
|
-
|
30
|
+
delay = initial_retry_delay * (factor ^ retries)
|
19
31
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
32
|
+
where:
|
33
|
+
- `initial_retry_delay` is 1 second by default.
|
34
|
+
- `factor` is 1.4142 by default
|
35
|
+
(retry delay doubles every two retries)
|
36
|
+
- max. number of retries is now 20 by default.
|
25
37
|
|
26
|
-
|
38
|
+
(which means s3cp retries for roughly 58 minutes by default)
|
27
39
|
|
28
40
|
* Fixed: `s3ls` and `s3du` now properly handle Errno::EPIPE
|
29
41
|
|
@@ -33,18 +45,18 @@
|
|
33
45
|
|
34
46
|
* Added: `s3up` now outputs uploaded file size to STDERR, e.g.,
|
35
47
|
|
36
|
-
|
37
|
-
|
48
|
+
% ls | s3up s3://bucket/path/to/file
|
49
|
+
s3://bucket/path/to/file => 214B
|
38
50
|
|
39
51
|
=== 1.0.1 / 2012-03-9
|
40
52
|
|
41
53
|
* Added: New command `s3up` to upload STDIN to S3
|
42
|
-
|
54
|
+
e.g. some_cmd | s3up s3://bucket/path/to/destination
|
43
55
|
|
44
56
|
Note: `s3up` does not yet directly stream data to S3 since right_aws gem
|
45
|
-
|
46
|
-
|
47
|
-
|
57
|
+
requires the upload size to be known in advance. `s3up` currently
|
58
|
+
persists STDIN into a temp file although this may change in the
|
59
|
+
future.
|
48
60
|
|
49
61
|
=== 1.0.0 / 2012-03-9
|
50
62
|
|
@@ -58,27 +70,27 @@ bugs -- but at least all known bugs have been addressed.
|
|
58
70
|
Probably worth mentioning: there are two outstanding experimental features,
|
59
71
|
|
60
72
|
1) s3cp --sync: Does not handle missing files. It's basically
|
61
|
-
|
73
|
+
a faster copy; not a true "sync" at this point.
|
62
74
|
|
63
75
|
2) Bash command-line completion is still very rough.
|
64
76
|
|
65
77
|
=== 0.2.7 / 2012-03-09
|
66
78
|
|
67
79
|
* Fixed #3: s3cp adds extra slash when copying to the root of a bucket.
|
68
|
-
|
80
|
+
e.g. s3://myBucket//someFile or s3://myBucket//someFolderToCopy/someFile
|
69
81
|
|
70
82
|
=== 0.2.6 / 2012-03-06
|
71
83
|
|
72
84
|
* Fixed: Possible division-by-zero error in s3du if it encounters
|
73
|
-
|
85
|
+
zero-length files.
|
74
86
|
|
75
87
|
=== 0.2.5 / 2012-03-02
|
76
88
|
|
77
89
|
* Added: "s3du" command to calculate disk usage.
|
78
|
-
|
90
|
+
Supports --depth, --regex, --unit parameters and more!
|
79
91
|
|
80
92
|
* Changed: "s3ls -l" command now accepts --unit and --precision to configure
|
81
|
-
|
93
|
+
file size display. Uses "smart" unit by default.
|
82
94
|
|
83
95
|
* Changed: "s3ls -l" will now use S3CP_DATE_FORMAT environment if set.
|
84
96
|
|
@@ -120,12 +132,12 @@ Probably worth mentioning: there are two outstanding experimental features,
|
|
120
132
|
* Added: Progress bars during upload/download if $stdout.isatty
|
121
133
|
|
122
134
|
* Fixed: s3cat now handles broken pipes properly
|
123
|
-
|
135
|
+
e.g. "s3cat bucket:some/file | head" will now terminate early.
|
124
136
|
|
125
137
|
=== 0.2.1 / (2012-02-20)
|
126
138
|
|
127
139
|
* Added: Bash completion now supports exclusions through S3CP_EXCLUDES
|
128
|
-
|
140
|
+
and defaults to excluding keys containing "_$folder$".
|
129
141
|
|
130
142
|
* Changed: s3dir and s3ls --delimiter now display both directories and files
|
131
143
|
|
@@ -134,15 +146,15 @@ Probably worth mentioning: there are two outstanding experimental features,
|
|
134
146
|
* Added: s3stat command to display S3 object properties
|
135
147
|
|
136
148
|
* Added: s3dir as a shortcut for "s3ls --delimiter / ..."
|
137
|
-
|
149
|
+
(default to character in S3CP_DELIMITER environment variable or "/" if not defined)
|
138
150
|
|
139
151
|
* Added: s3cp defaults can now be set using environment variables
|
140
|
-
|
152
|
+
S3CP_OVERWRITE, S3CP_CHECKSUM, S3CP_RETRIES, S3CP_RETRY_DELAY
|
141
153
|
|
142
154
|
* Added: Support for Bash command-line completion of S3 URLs (see below).
|
143
155
|
|
144
156
|
* Fixed: Skip checksum verification for S3 objects with invalid MD5's
|
145
|
-
|
157
|
+
(details @ https://forums.aws.amazon.com/message.jspa?messageID=234538)
|
146
158
|
|
147
159
|
To install Bash completion for S3 URLs, add the following to ~/.bashrc:
|
148
160
|
|
@@ -153,10 +165,10 @@ To install Bash completion for S3 URLs, add the following to ~/.bashrc:
|
|
153
165
|
=== 0.1.15 / (2012-02-17)
|
154
166
|
|
155
167
|
* Added: s3cp now automatically checks MD5 checksums during download/upload
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
168
|
+
and retries up to 5 times by default if the checksum fails.
|
169
|
+
The number of attempts may be configured using --max-attempts,
|
170
|
+
the retry delay may be changed with --retry-delay and the check
|
171
|
+
may be disabled completely using --no-checksum.
|
160
172
|
|
161
173
|
=== 0.1.14 / (2012-02-09)
|
162
174
|
|
@@ -178,7 +190,7 @@ To install Bash completion for S3 URLs, add the following to ~/.bashrc:
|
|
178
190
|
|
179
191
|
* Fixed: --max-keys now works correctly with --delimiter
|
180
192
|
* Fixed: do not display any keys if there are no common-prefix
|
181
|
-
|
193
|
+
delimiter-matching keys
|
182
194
|
|
183
195
|
=== 0.1.9 / (2012-01-23)
|
184
196
|
|
@@ -187,18 +199,18 @@ To install Bash completion for S3 URLs, add the following to ~/.bashrc:
|
|
187
199
|
=== 0.1.8 / (2011-12-29)
|
188
200
|
|
189
201
|
* Fixed: Apparently, File.new(path, File::CREAT|File::WRONLY) does not
|
190
|
-
|
202
|
+
truncate existing files; use File.new(path, "wb") instead.
|
191
203
|
|
192
204
|
=== 0.1.7 / (2011-12-29)
|
193
205
|
|
194
206
|
* Fixed: s3cp would not truncate existing files when overwriting, possibly
|
195
|
-
|
207
|
+
resulting in corrupted files.
|
196
208
|
|
197
209
|
=== 0.1.6 / (2011-12-16)
|
198
210
|
|
199
211
|
* Changed: s3rm now uses multi-object delete operation for faster deletes
|
200
212
|
* Changed: dependency on 'aboisvert-aws' instead of 'right-aws' until
|
201
|
-
|
213
|
+
it supports multi-object delete.
|
202
214
|
|
203
215
|
=== 0.1.5 / 2011-10-17
|
204
216
|
|
@@ -211,7 +223,7 @@ To install Bash completion for S3 URLs, add the following to ~/.bashrc:
|
|
211
223
|
=== 0.1.3 / 2011-09-29
|
212
224
|
|
213
225
|
* Fixed: s3cp --headers names are now converted to lowercase since underlying
|
214
|
-
|
226
|
+
RightAWS gem expects lowercase header names.
|
215
227
|
|
216
228
|
=== 0.1.2 / 2011-09-29
|
217
229
|
|
data/bin/s3buckets
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
def set_header_options(options, headers)
|
2
|
+
return options unless headers
|
3
|
+
|
4
|
+
# legacy options that were previously passed as headers
|
5
|
+
# are now passed explicitly as options/metadata.
|
6
|
+
mappings = {
|
7
|
+
"Content-Type" => :content_type,
|
8
|
+
"x-amz-acl" => :acl,
|
9
|
+
"Cache-Control" => :cache_control,
|
10
|
+
"x-amz-storage-class" => :reduced_redundancy
|
11
|
+
}
|
12
|
+
|
13
|
+
lambdas = {
|
14
|
+
"x-amz-storage-class" => lambda { |v| (v =~ /^REDUCED_REDUNDANCY$/i) ? true : false }
|
15
|
+
}
|
16
|
+
|
17
|
+
remaining = headers.dup
|
18
|
+
headers.each do |hk, hv|
|
19
|
+
mappings.each do |mk, mv|
|
20
|
+
if hk.to_s =~ /^#{mk}$/i
|
21
|
+
lambda = lambdas[mk]
|
22
|
+
options[mv] = lambda ? lambda.call(hv) : hv
|
23
|
+
remaining.delete(hk)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
options[:metadata] = remaining unless remaining.empty?
|
30
|
+
|
31
|
+
options
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
set_header_options({}, { "Content-type" => "foo ", 'x-amz-acl' => 'private', 'foo' => 'bar', 'x-amz-storage-class' => 'REDUCED_REDUNDANCY'})
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright (C) 2010-2012 Alex Boisvert and Bizo Inc. / All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. The ASF licenses this
|
6
|
+
# file to you under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
|
18
|
+
require 's3cp/utils'
|
19
|
+
|
20
|
+
# Parse arguments
|
21
|
+
options = {}
|
22
|
+
|
23
|
+
op = OptionParser.new do |opts|
|
24
|
+
opts.banner = "s3buckets"
|
25
|
+
|
26
|
+
opts.on("--verbose", "Verbose mode") do
|
27
|
+
options[:verbose] = true
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
31
|
+
puts op
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
op.parse!(ARGV)
|
36
|
+
|
37
|
+
s3 = S3CP.connect()
|
38
|
+
s3.buckets.each do |bucket|
|
39
|
+
puts bucket.name
|
40
|
+
end
|
41
|
+
|
data/lib/s3cp/s3cat.rb
CHANGED
@@ -15,16 +15,9 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
|
-
require 'date'
|
23
|
-
require 'highline/import'
|
24
|
-
require 'tempfile'
|
25
|
-
require 'progressbar'
|
26
|
-
|
27
18
|
require 's3cp/utils'
|
19
|
+
require 'progressbar'
|
20
|
+
require 'tempfile'
|
28
21
|
|
29
22
|
# Parse arguments
|
30
23
|
options = {}
|
@@ -64,12 +57,11 @@ end
|
|
64
57
|
@bucket, @prefix = S3CP.bucket_and_key(url)
|
65
58
|
fail "Your URL looks funny, doesn't it?" unless @bucket
|
66
59
|
|
67
|
-
@s3 = S3CP.connect().
|
60
|
+
@s3 = S3CP.connect().buckets[@bucket]
|
68
61
|
|
69
62
|
if options[:tty]
|
70
63
|
# store contents to file to display with PAGER
|
71
|
-
|
72
|
-
size = metadata["content-length"].to_i
|
64
|
+
size = @s3.objects[@prefix].content_length
|
73
65
|
|
74
66
|
progress_bar = ProgressBar.new(File.basename(@prefix), size).tap do |p|
|
75
67
|
p.file_transfer_mode
|
@@ -78,7 +70,7 @@ if options[:tty]
|
|
78
70
|
file = Tempfile.new('s3cat')
|
79
71
|
out = File.new(file.path, "wb")
|
80
72
|
begin
|
81
|
-
@s3.
|
73
|
+
@s3.objects[@prefix].read_as_stream do |chunk|
|
82
74
|
out.write(chunk)
|
83
75
|
progress_bar.inc chunk.size
|
84
76
|
end
|
@@ -89,7 +81,7 @@ if options[:tty]
|
|
89
81
|
exec "#{ENV['PAGER'] || 'less'} #{file.path}"
|
90
82
|
file.delete()
|
91
83
|
else
|
92
|
-
@s3.
|
84
|
+
@s3.objects[@prefix].read_as_stream do |chunk|
|
93
85
|
begin
|
94
86
|
STDOUT.print(chunk)
|
95
87
|
rescue Errno::EPIPE
|
data/lib/s3cp/s3cp.rb
CHANGED
@@ -15,17 +15,8 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
|
-
require 'date'
|
23
|
-
require 'highline/import'
|
24
|
-
require 'fileutils'
|
25
|
-
require 'digest'
|
26
|
-
require 'progressbar'
|
27
|
-
|
28
18
|
require 's3cp/utils'
|
19
|
+
require 'progressbar'
|
29
20
|
|
30
21
|
# Parse arguments
|
31
22
|
options = {}
|
@@ -103,6 +94,10 @@ op = OptionParser.new do |opts|
|
|
103
94
|
options[:headers] = h
|
104
95
|
end
|
105
96
|
|
97
|
+
opts.on("--acl PERMISSION", "One of 'private', 'authenticated-read', 'public-read', 'public-read-write'") do |permission|
|
98
|
+
options[:acl] = S3CP.validate_acl(permission)
|
99
|
+
end
|
100
|
+
|
106
101
|
opts.separator " e.g.,"
|
107
102
|
opts.separator " HTTP headers: \'Content-Type: image/jpg\'"
|
108
103
|
opts.separator " AMZ headers: \'x-amz-acl: public-read\'"
|
@@ -243,12 +238,16 @@ end
|
|
243
238
|
|
244
239
|
def s3_to_s3(bucket_from, key, bucket_to, dest, options = {})
|
245
240
|
log(with_headers("Copy s3://#{bucket_from}/#{key} to s3://#{bucket_to}/#{dest}"))
|
246
|
-
|
247
|
-
|
241
|
+
s3_source = @s3.buckets[bucket_from].objects[key]
|
242
|
+
s3_dest = @s3.buckets[bucket_to].objects[dest]
|
243
|
+
s3_options = {}
|
244
|
+
S3CP.set_header_options(s3_, @headers)
|
245
|
+
s3_options[:acl] = options[:acl]
|
246
|
+
unless options[:move]
|
247
|
+
s3_source.copy_to(s3_dest, s3_options)
|
248
248
|
else
|
249
|
-
|
249
|
+
s3_source.move_to(s3_dest, s3_options)
|
250
250
|
end
|
251
|
-
@s3.interface.delete(bucket_from, key) if options[:move]
|
252
251
|
end
|
253
252
|
|
254
253
|
def local_to_s3(bucket_to, key, file, options = {})
|
@@ -279,37 +278,33 @@ def local_to_s3(bucket_to, key, file, options = {})
|
|
279
278
|
end
|
280
279
|
if retries > 0
|
281
280
|
delay = options[:retry_delay] * (options[:retry_backoff] ** retries)
|
282
|
-
STDERR.puts "Sleeping #{delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
|
281
|
+
STDERR.puts "Sleeping #{"%0.2f" % delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
|
283
282
|
sleep delay
|
284
283
|
end
|
285
284
|
|
286
|
-
f = File.open(file)
|
287
285
|
begin
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
286
|
+
s3_options = {
|
287
|
+
:bucket_name => bucket_to,
|
288
|
+
:key => key
|
289
|
+
}
|
290
|
+
S3CP.set_header_options(s3_options, @headers)
|
291
|
+
s3_options[:acl] = options[:acl]
|
292
|
+
s3_options[:content_length] = File.size(file)
|
293
|
+
|
294
|
+
progress_bar = ProgressBar.new(File.basename(file), File.size(file)).tap do |p|
|
295
|
+
p.file_transfer_mode
|
296
|
+
end
|
297
|
+
|
298
|
+
meta = @s3.client.put_object(s3_options) do |buffer|
|
299
|
+
File.open(file) do |io|
|
300
|
+
while !io.eof?
|
301
|
+
result = io.read(32 * 1024)
|
302
|
+
progress_bar.inc result.length if result
|
303
|
+
buffer.write(result)
|
305
304
|
end
|
306
305
|
end
|
307
|
-
f.progress_bar = progress_bar
|
308
|
-
else
|
309
|
-
progress_bar = nil
|
310
306
|
end
|
311
307
|
|
312
|
-
meta = @s3.interface.put(bucket_to, key, f, @headers)
|
313
308
|
progress_bar.finish if progress_bar
|
314
309
|
|
315
310
|
if options[:checksum]
|
@@ -329,10 +324,8 @@ def local_to_s3(bucket_to, key, file, options = {})
|
|
329
324
|
progress_bar.clear
|
330
325
|
puts "Error copying #{file} to s3://#{bucket_to}/#{key}"
|
331
326
|
end
|
332
|
-
raise e if !options[:checksum] || e.
|
327
|
+
raise e if !options[:checksum] || e.is_a?(AWS::S3::Errors::AccessDenied)
|
333
328
|
STDERR.puts e
|
334
|
-
ensure
|
335
|
-
f.close()
|
336
329
|
end
|
337
330
|
retries += 1
|
338
331
|
end until options[:checksum] == false || actual_md5.nil? || expected_md5 == actual_md5
|
@@ -353,7 +346,8 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
|
|
353
346
|
end
|
354
347
|
if retries > 0
|
355
348
|
delay = options[:retry_delay] * (options[:retry_backoff] ** retries)
|
356
|
-
|
349
|
+
delay = delay.to_i
|
350
|
+
STDERR.puts "Sleeping #{"%0.2f" % delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
|
357
351
|
sleep delay
|
358
352
|
end
|
359
353
|
begin
|
@@ -383,7 +377,7 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
|
|
383
377
|
p.file_transfer_mode
|
384
378
|
end
|
385
379
|
end
|
386
|
-
@s3.
|
380
|
+
@s3.buckets[bucket_from].objects[key_from].read_as_stream do |chunk|
|
387
381
|
f.write(chunk)
|
388
382
|
progress_bar.inc chunk.size if progress_bar
|
389
383
|
end
|
@@ -413,25 +407,23 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
|
|
413
407
|
retries += 1
|
414
408
|
end until options[:checksum] == false || expected_md5.nil? || md5(dest) == expected_md5
|
415
409
|
|
416
|
-
@s3.
|
410
|
+
@s3.buckets[bucket_from].objects[key_from].delete() if options[:move]
|
417
411
|
end
|
418
412
|
|
419
413
|
def s3_exist?(bucket, key)
|
420
|
-
|
421
|
-
#puts "exist? #{bucket} #{key} => #{metadata != nil}"
|
422
|
-
(metadata != nil)
|
414
|
+
@s3.buckets[bucket].objects[key].exist?
|
423
415
|
end
|
424
416
|
|
425
417
|
def s3_checksum(bucket, key)
|
426
418
|
begin
|
427
|
-
metadata = @s3.
|
419
|
+
metadata = @s3.buckets[bucket].objects[key].head()
|
428
420
|
return :not_found unless metadata
|
429
421
|
rescue => e
|
430
|
-
return :not_found if e.is_a?(
|
422
|
+
return :not_found if e.is_a?(AWS::S3::Errors::NoSuchKey)
|
431
423
|
raise e
|
432
424
|
end
|
433
425
|
|
434
|
-
md5 = metadata[
|
426
|
+
md5 = metadata[:etag] or fail "Unable to get etag/md5 for #{bucket_to}:#{key}"
|
435
427
|
return :invalid unless md5
|
436
428
|
|
437
429
|
md5 = md5.sub(/^"/, "").sub(/"$/, "") # strip beginning and trailing quotes
|
@@ -449,8 +441,7 @@ def key_path(prefix, key)
|
|
449
441
|
end
|
450
442
|
|
451
443
|
def s3_size(bucket, key)
|
452
|
-
|
453
|
-
metadata["content-length"].to_i
|
444
|
+
@s3.buckets[bucket].objects[key].content_length
|
454
445
|
end
|
455
446
|
|
456
447
|
def copy(from, to, options)
|
data/lib/s3cp/s3du.rb
CHANGED
@@ -15,13 +15,6 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
|
-
require 'date'
|
23
|
-
require 'highline/import'
|
24
|
-
|
25
18
|
require 's3cp/utils'
|
26
19
|
|
27
20
|
# Parse arguments
|
@@ -72,9 +65,6 @@ fail "Your URL looks funny, doesn't it?" unless @bucket
|
|
72
65
|
|
73
66
|
@s3 = S3CP.connect()
|
74
67
|
|
75
|
-
s3_options = Hash.new
|
76
|
-
s3_options[:prefix] = @prefix
|
77
|
-
|
78
68
|
def depth(path)
|
79
69
|
path.count("/")
|
80
70
|
end
|
@@ -103,29 +93,25 @@ def print(key, size)
|
|
103
93
|
end
|
104
94
|
|
105
95
|
begin
|
106
|
-
@s3.
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
current_key = if actual_depth
|
115
|
-
pos = nth_occurrence(key, "/", actual_depth)
|
116
|
-
(pos != -1) ? key[0..pos-1] : key
|
117
|
-
end
|
118
|
-
|
119
|
-
if (last_key && last_key != current_key)
|
120
|
-
print(last_key, subtotal_size)
|
121
|
-
subtotal_size = size
|
122
|
-
else
|
123
|
-
subtotal_size += size
|
124
|
-
end
|
125
|
-
|
126
|
-
last_key = current_key
|
127
|
-
total_size += size
|
96
|
+
@s3.buckets[@bucket].objects.with_prefix(@prefix).each do |entry|
|
97
|
+
key = entry.key
|
98
|
+
size = entry.content_length
|
99
|
+
|
100
|
+
if options[:regex].nil? || options[:regex].match(key)
|
101
|
+
current_key = if actual_depth
|
102
|
+
pos = nth_occurrence(key, "/", actual_depth)
|
103
|
+
(pos != -1) ? key[0..pos-1] : key
|
128
104
|
end
|
105
|
+
|
106
|
+
if (last_key && last_key != current_key)
|
107
|
+
print(last_key, subtotal_size)
|
108
|
+
subtotal_size = size
|
109
|
+
else
|
110
|
+
subtotal_size += size
|
111
|
+
end
|
112
|
+
|
113
|
+
last_key = current_key
|
114
|
+
total_size += size
|
129
115
|
end
|
130
116
|
end
|
131
117
|
|
data/lib/s3cp/s3ls.rb
CHANGED
@@ -15,19 +15,12 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
|
-
require 'date'
|
23
|
-
require 'highline/import'
|
24
|
-
|
25
18
|
require 's3cp/utils'
|
26
19
|
|
27
20
|
# Parse arguments
|
28
21
|
options = {}
|
29
22
|
options[:date_format] = ENV['S3CP_DATE_FORMAT'] || '%x %X'
|
30
|
-
options[:rows_per_page] = $terminal.output_rows if $stdout.isatty
|
23
|
+
options[:rows_per_page] = ($terminal.output_rows - 1) if $stdout.isatty
|
31
24
|
options[:precision] = 0
|
32
25
|
|
33
26
|
op = OptionParser.new do |opts|
|
@@ -93,53 +86,49 @@ if options[:verbose]
|
|
93
86
|
puts "key #{@key}"
|
94
87
|
end
|
95
88
|
|
96
|
-
@s3 = S3CP.connect()
|
89
|
+
@s3 = S3CP.connect().buckets[@bucket]
|
97
90
|
|
98
91
|
keys = 0
|
99
92
|
rows = 0
|
100
93
|
|
101
|
-
s3_options = Hash.new
|
102
|
-
s3_options[:prefix] = @key
|
103
|
-
s3_options["max-keys"] = options[:max_keys] if options[:max_keys] && !options[:delimiter]
|
104
|
-
s3_options[:delimiter] = options[:delimiter] if options[:delimiter]
|
105
|
-
|
106
94
|
begin
|
107
|
-
|
108
|
-
|
109
|
-
if options[:
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
95
|
+
display = lambda do |entry|
|
96
|
+
key = entry.key ? "s3://#{@bucket}/#{entry.key}" : "---"
|
97
|
+
if options[:long_format] && entry.last_modified && entry.content_length
|
98
|
+
size = entry.content_length
|
99
|
+
size = S3CP.format_filesize(size, :unit => options[:unit], :precision => options[:precision])
|
100
|
+
size = ("%#{7 + options[:precision]}s " % size)
|
101
|
+
puts "#{entry.last_modified.strftime(options[:date_format])} #{size} #{key}"
|
102
|
+
else
|
103
|
+
puts key
|
115
104
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
end
|
133
|
-
if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
|
134
|
-
begin
|
135
|
-
print "Continue? (Y/n) "
|
136
|
-
response = STDIN.gets.chomp.downcase
|
137
|
-
end until response == 'n' || response == 'y' || response == ''
|
138
|
-
exit if response == 'n'
|
105
|
+
rows += 1
|
106
|
+
keys += 1
|
107
|
+
if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
|
108
|
+
begin
|
109
|
+
print "Continue? (Y/n) "
|
110
|
+
response = STDIN.gets.chomp.downcase
|
111
|
+
end until response == 'n' || response == 'y' || response == ''
|
112
|
+
exit if response == 'n'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if options[:delimiter]
|
117
|
+
@s3.objects.with_prefix(@key).as_tree(:delimier => options[:delimiter], :append => false).children.each do |entry|
|
118
|
+
if entry.leaf?
|
119
|
+
entry = @s3.objects[entry.key]
|
120
|
+
break if display.call(entry)
|
139
121
|
end
|
140
122
|
end
|
123
|
+
else
|
124
|
+
s3_options = Hash.new
|
125
|
+
s3_options[:limit] = options[:max_keys] if options[:max_keys]
|
126
|
+
@s3.objects.with_prefix(@key).each(s3_options) do |entry|
|
127
|
+
break if display.call(entry)
|
128
|
+
end
|
141
129
|
end
|
142
130
|
rescue Errno::EPIPE
|
143
131
|
# ignore
|
132
|
+
break
|
144
133
|
end
|
145
134
|
|
data/lib/s3cp/s3mod.rb
CHANGED
@@ -15,10 +15,6 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
18
|
require 's3cp/utils'
|
23
19
|
|
24
20
|
op = OptionParser.new do |opts|
|
@@ -48,14 +44,11 @@ end
|
|
48
44
|
|
49
45
|
def update_permissions(s3, bucket, key, permission)
|
50
46
|
puts "Setting #{permission} on s3://#{bucket}/#{key}"
|
51
|
-
s3.
|
47
|
+
s3.buckets[bucket].objects[key].acl = permission
|
52
48
|
end
|
53
49
|
|
54
50
|
source = ARGV[0]
|
55
|
-
permission = ARGV.last
|
56
|
-
|
57
|
-
LEGAL_MODS = %w{private authenticated-read public-read public-read-write}
|
58
|
-
raise "Permissions must be one of the following values: #{LEGAL_MODS}" unless LEGAL_MODS.include?(permission)
|
51
|
+
permission = S3CP.validate_acl(ARGV.last)
|
59
52
|
|
60
53
|
@s3 = S3CP.connect()
|
61
54
|
bucket,key = S3CP.bucket_and_key(source)
|
data/lib/s3cp/s3rm.rb
CHANGED
@@ -15,13 +15,6 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
|
-
require 'date'
|
23
|
-
require 'highline/import'
|
24
|
-
|
25
18
|
require 's3cp/utils'
|
26
19
|
|
27
20
|
# Parse arguments
|
@@ -110,20 +103,18 @@ exclude_regex = options[:exclude_regex] ? Regexp.new(options[:exclude_regex]) :
|
|
110
103
|
if options[:recursive]
|
111
104
|
matching_keys = []
|
112
105
|
|
113
|
-
@s3.
|
114
|
-
|
115
|
-
key = "s3://#{@bucket}/#{entry[:key]}"
|
106
|
+
@s3.buckets[@bucket].objects.with_prefix(@key).each do |entry|
|
107
|
+
key = "s3://#{@bucket}/#{entry.key}"
|
116
108
|
|
117
|
-
|
118
|
-
|
119
|
-
|
109
|
+
matching = true
|
110
|
+
matching = false if include_regex && !include_regex.match(entry.key)
|
111
|
+
matching = false if exclude_regex && exclude_regex.match(entry.key)
|
120
112
|
|
121
|
-
|
113
|
+
puts "#{key} => #{matching}" if options[:verbose]
|
122
114
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
115
|
+
if matching
|
116
|
+
matching_keys << entry.key
|
117
|
+
puts key unless options[:silent] || options[:verbose]
|
127
118
|
end
|
128
119
|
end
|
129
120
|
|
@@ -132,28 +123,20 @@ if options[:recursive]
|
|
132
123
|
exit(1)
|
133
124
|
end
|
134
125
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
if errors.length > 0
|
139
|
-
puts "Errors during deletion:"
|
140
|
-
errors.each do |error|
|
141
|
-
puts "#{error[:key]} #{error[:code]} #{error[:message]}"
|
142
|
-
end
|
143
|
-
exit(1)
|
144
|
-
end
|
126
|
+
# if any of the objects failed to delete, a BatchDeleteError will be raised with a summary of the errors
|
127
|
+
@s3.buckets[@bucket].objects.delete(matching_keys) unless options[:test]
|
145
128
|
else
|
146
129
|
# delete a single file; check if it exists
|
147
|
-
if options[:fail_if_not_exist] &&
|
130
|
+
if options[:fail_if_not_exist] && !@s3.buckets[@bucket].objects[@key].exist?
|
148
131
|
key = "s3://#{@bucket}/#{@key}"
|
149
132
|
puts "#{key} does not exist."
|
150
133
|
exit(1)
|
151
134
|
end
|
152
135
|
|
153
136
|
begin
|
154
|
-
@s3.
|
137
|
+
@s3.buckets[@bucket].objects[@key].delete() unless options[:test]
|
155
138
|
rescue => e
|
156
139
|
puts e.to_s
|
157
|
-
raise e unless e.
|
140
|
+
raise e unless e.is_a? AWS::S3::Errors::NoSuchKey
|
158
141
|
end
|
159
142
|
end
|
data/lib/s3cp/s3stat.rb
CHANGED
@@ -15,10 +15,6 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
18
|
require 's3cp/utils'
|
23
19
|
|
24
20
|
op = OptionParser.new do |opts|
|
@@ -40,15 +36,11 @@ end
|
|
40
36
|
source = ARGV[0]
|
41
37
|
permission = ARGV.last
|
42
38
|
|
43
|
-
@
|
39
|
+
@bucket, @key = S3CP.bucket_and_key(source)
|
40
|
+
@s3 = S3CP.connect().buckets[@bucket]
|
44
41
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
puts "#{"%20s" % k} #{v}"
|
49
|
-
end
|
42
|
+
metadata = @s3.objects[@key].head
|
43
|
+
metadata.keys.sort { |k1, k2| k1.to_s <=> k2.to_s}.each do |k|
|
44
|
+
puts "#{"%30s" % k} #{metadata[k]}"
|
50
45
|
end
|
51
46
|
|
52
|
-
bucket,key = S3CP.bucket_and_key(source)
|
53
|
-
get_metadata(bucket, key)
|
54
|
-
|
data/lib/s3cp/s3up.rb
CHANGED
@@ -15,13 +15,8 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require 'rubygems'
|
19
|
-
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
-
require 'right_aws'
|
21
|
-
require 'optparse'
|
22
|
-
require 'tempfile'
|
23
|
-
|
24
18
|
require 's3cp/utils'
|
19
|
+
require 'tempfile'
|
25
20
|
|
26
21
|
# Parse arguments
|
27
22
|
options = {}
|
@@ -37,6 +32,10 @@ op = OptionParser.new do |opts|
|
|
37
32
|
options[:headers] = h
|
38
33
|
end
|
39
34
|
|
35
|
+
opts.on("--acl PERMISSION", "One of 'private', 'authenticated-read', 'public-read', 'public-read-write'") do |permission|
|
36
|
+
options[:acl] = S3CP.validate_acl(permission)
|
37
|
+
end
|
38
|
+
|
40
39
|
opts.separator " e.g.,"
|
41
40
|
opts.separator " HTTP headers: \'Content-Type: image/jpg\'"
|
42
41
|
opts.separator " AMZ headers: \'x-amz-acl: public-read\'"
|
@@ -78,7 +77,10 @@ temp.open
|
|
78
77
|
|
79
78
|
# upload temp file
|
80
79
|
begin
|
81
|
-
|
80
|
+
s3_options = {}
|
81
|
+
S3CP.set_header_options(s3_options, @headers)
|
82
|
+
s3_options[:acl] = options[:acl]
|
83
|
+
@s3.buckets[bucket].objects[key].write(temp, s3_options)
|
82
84
|
STDERR.puts "s3://#{bucket}/#{key} => #{S3CP.format_filesize(temp.size)} "
|
83
85
|
ensure
|
84
86
|
# cleanup
|
data/lib/s3cp/utils.rb
CHANGED
@@ -15,19 +15,37 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
+
require 'rubygems'
|
19
|
+
require 'extensions/kernel' if RUBY_VERSION =~ /1.8/
|
20
|
+
require 'aws/s3'
|
21
|
+
require 'optparse'
|
22
|
+
require 'date'
|
23
|
+
require 'highline/import'
|
24
|
+
|
18
25
|
module S3CP
|
19
26
|
extend self
|
20
27
|
|
21
28
|
# Valid units for file size formatting
|
22
29
|
UNITS = %w{B KB MB GB TB EB ZB YB BB}
|
23
30
|
|
31
|
+
LEGAL_MODS = %w{
|
32
|
+
private
|
33
|
+
public-read
|
34
|
+
public-read-write
|
35
|
+
authenticated-read
|
36
|
+
bucket_owner_read
|
37
|
+
bucket_owner_full_control
|
38
|
+
}
|
39
|
+
|
24
40
|
# Connect to AWS S3
|
25
41
|
def connect()
|
26
42
|
access_key = ENV["AWS_ACCESS_KEY_ID"] || raise("Missing environment variable AWS_ACCESS_KEY_ID")
|
27
43
|
secret_key = ENV["AWS_SECRET_ACCESS_KEY"] || raise("Missing environment variable AWS_SECRET_ACCESS_KEY")
|
28
44
|
|
29
|
-
|
30
|
-
|
45
|
+
::AWS::S3.new(
|
46
|
+
:access_key_id => access_key,
|
47
|
+
:secret_access_key => secret_key
|
48
|
+
)
|
31
49
|
end
|
32
50
|
|
33
51
|
# Parse URL and return bucket and key.
|
@@ -100,5 +118,67 @@ module S3CP
|
|
100
118
|
end
|
101
119
|
end
|
102
120
|
|
121
|
+
def set_header_options(options, headers)
|
122
|
+
return options unless headers
|
123
|
+
|
124
|
+
# legacy options that were previously passed as headers
|
125
|
+
# are now passed explicitly as options/metadata.
|
126
|
+
mappings = {
|
127
|
+
"Content-Type" => :content_type,
|
128
|
+
"x-amz-acl" => :acl,
|
129
|
+
"Cache-Control" => :cache_control,
|
130
|
+
"x-amz-storage-class" => :reduced_redundancy
|
131
|
+
}
|
132
|
+
|
133
|
+
lambdas = {
|
134
|
+
"x-amz-storage-class" => lambda { |v| (v =~ /^REDUCED_REDUNDANCY$/i) ? true : false }
|
135
|
+
}
|
136
|
+
|
137
|
+
remaining = headers.dup
|
138
|
+
headers.each do |hk, hv|
|
139
|
+
mappings.each do |mk, mv|
|
140
|
+
if hk.to_s =~ /^#{mk}$/i
|
141
|
+
lambda = lambdas[mk]
|
142
|
+
options[mv] = lambda ? lambda.call(hv) : hv
|
143
|
+
remaining.delete(hk)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
options[:metadata] = remaining unless remaining.empty?
|
150
|
+
|
151
|
+
options
|
152
|
+
end
|
153
|
+
|
154
|
+
def validate_acl(permission)
|
155
|
+
if !LEGAL_MODS.include?(permission)
|
156
|
+
raise "Permissions must be one of the following values: #{LEGAL_MODS}"
|
157
|
+
end
|
158
|
+
permission
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Monkey-patch S3 object for download streaming
|
163
|
+
# https://forums.aws.amazon.com/thread.jspa?messageID=295587
|
164
|
+
module AWS
|
165
|
+
|
166
|
+
DEFAULT_STREAMING_CHUNK_SIZE = ENV["S3CP_STREAMING_CHUNK_SIZE"] ? ENV["S3CP_STREAMING_CHUNK_SIZE"].to_i : (512 * 1024)
|
167
|
+
|
168
|
+
class S3
|
169
|
+
class S3Object
|
170
|
+
def read_as_stream(options = nil, &blk)
|
171
|
+
options ||= {}
|
172
|
+
chunk_size = options[:chunk] || DEFAULT_STREAMING_CHUNK_SIZE
|
173
|
+
size = content_length
|
174
|
+
byte_offset = 0
|
175
|
+
while byte_offset < size
|
176
|
+
range = "bytes=#{byte_offset}-#{byte_offset + chunk_size - 1}"
|
177
|
+
yield read(:range => range)
|
178
|
+
byte_offset += chunk_size
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
103
183
|
end
|
104
184
|
|
data/lib/s3cp/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3cp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: -3842078234
|
5
|
+
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
-
|
10
|
-
|
10
|
+
- pre
|
11
|
+
- 1
|
12
|
+
version: 1.1.0.pre.1
|
11
13
|
platform: ruby
|
12
14
|
authors:
|
13
15
|
- Alex Boisvert
|
@@ -15,7 +17,7 @@ autorequire:
|
|
15
17
|
bindir: bin
|
16
18
|
cert_chain: []
|
17
19
|
|
18
|
-
date: 2012-07-
|
20
|
+
date: 2012-07-24 00:00:00 Z
|
19
21
|
dependencies:
|
20
22
|
- !ruby/object:Gem::Dependency
|
21
23
|
prerelease: false
|
@@ -50,40 +52,24 @@ dependencies:
|
|
50
52
|
type: :runtime
|
51
53
|
- !ruby/object:Gem::Dependency
|
52
54
|
prerelease: false
|
53
|
-
name:
|
55
|
+
name: aws-sdk
|
54
56
|
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
57
|
none: false
|
56
58
|
requirements:
|
57
59
|
- - ~>
|
58
60
|
- !ruby/object:Gem::Version
|
59
|
-
hash:
|
60
|
-
segments:
|
61
|
-
- 3
|
62
|
-
- 0
|
63
|
-
- 0
|
64
|
-
version: 3.0.0
|
65
|
-
requirement: *id003
|
66
|
-
type: :runtime
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
prerelease: false
|
69
|
-
name: right_http_connection
|
70
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
71
|
-
none: false
|
72
|
-
requirements:
|
73
|
-
- - ~>
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
hash: 27
|
61
|
+
hash: 13
|
76
62
|
segments:
|
77
63
|
- 1
|
78
|
-
-
|
79
|
-
-
|
80
|
-
version: 1.
|
81
|
-
requirement: *
|
64
|
+
- 5
|
65
|
+
- 7
|
66
|
+
version: 1.5.7
|
67
|
+
requirement: *id003
|
82
68
|
type: :runtime
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
prerelease: false
|
85
71
|
name: progressbar
|
86
|
-
version_requirements: &
|
72
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
87
73
|
none: false
|
88
74
|
requirements:
|
89
75
|
- - ~>
|
@@ -94,12 +80,12 @@ dependencies:
|
|
94
80
|
- 10
|
95
81
|
- 0
|
96
82
|
version: 0.10.0
|
97
|
-
requirement: *
|
83
|
+
requirement: *id004
|
98
84
|
type: :runtime
|
99
85
|
- !ruby/object:Gem::Dependency
|
100
86
|
prerelease: false
|
101
87
|
name: rspec
|
102
|
-
version_requirements: &
|
88
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
103
89
|
none: false
|
104
90
|
requirements:
|
105
91
|
- - ~>
|
@@ -110,12 +96,12 @@ dependencies:
|
|
110
96
|
- 5
|
111
97
|
- 0
|
112
98
|
version: 2.5.0
|
113
|
-
requirement: *
|
99
|
+
requirement: *id005
|
114
100
|
type: :development
|
115
101
|
- !ruby/object:Gem::Dependency
|
116
102
|
prerelease: false
|
117
103
|
name: rake
|
118
|
-
version_requirements: &
|
104
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
119
105
|
none: false
|
120
106
|
requirements:
|
121
107
|
- - ~>
|
@@ -126,7 +112,7 @@ dependencies:
|
|
126
112
|
- 8
|
127
113
|
- 7
|
128
114
|
version: 0.8.7
|
129
|
-
requirement: *
|
115
|
+
requirement: *id006
|
130
116
|
type: :development
|
131
117
|
description:
|
132
118
|
email:
|
@@ -157,7 +143,9 @@ files:
|
|
157
143
|
- lib/s3cp/s3mod.rb
|
158
144
|
- lib/s3cp/utils.rb
|
159
145
|
- lib/s3cp/s3cp.rb
|
146
|
+
- lib/s3cp/#Untitled-1#
|
160
147
|
- lib/s3cp/s3cat.rb
|
148
|
+
- lib/s3cp/s3buckets.rb
|
161
149
|
- lib/s3cp/s3rm.rb
|
162
150
|
- lib/s3cp/s3stat.rb
|
163
151
|
- lib/s3cp/s3up.rb
|
@@ -167,6 +155,7 @@ files:
|
|
167
155
|
- bin/s3mv
|
168
156
|
- bin/s3rm
|
169
157
|
- bin/s3dir
|
158
|
+
- bin/s3buckets
|
170
159
|
- bin/s3mod
|
171
160
|
- bin/s3du
|
172
161
|
- bin/s3cat
|