s3cp 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,21 @@
1
+ === 1.0.3 / (2012-05-11)
2
+
3
+ * Added: Exponential backoff for `s3cp` command based on the formula:
4
+
5
+ delay = initial_retry_delay * (factor ^ retries)
6
+
7
+ where:
8
+ - `initial_retry_delay` is 1 second by default.
9
+ - `factor` is 1.4142 by default
10
+ (retry delay doubles every two retries)
11
+ - max. number of retries is now 20 by default.
12
+
13
+ (which means s3cp retries for roughly 58 minutes by default)
14
+
15
+ * Fixed: `s3ls` and `s3du` now properly handle Errno::EPIPE
16
+
17
+ * Fixed: `s3du` would not display last character of files
18
+
1
19
  === 1.0.2 / 2012-03-9
2
20
 
3
21
  * Added: `s3up` now outputs uploaded file size to STDERR, e.g.,
data/lib/s3cp/s3cp.rb CHANGED
@@ -31,10 +31,12 @@ require 's3cp/utils'
31
31
  options = {}
32
32
  options[:verbose] = $stdout.isatty ? true : false
33
33
  options[:headers] = []
34
- options[:overwrite] = ENV["S3CP_RETRIES"] ? (ENV["S3CP_OVERWRITE"] =~ /y|yes|true|1|^\s*$/i ? true : false) : true
34
+ options[:overwrite] = ENV["S3CP_OVERWRITE"] ? (ENV["S3CP_OVERWRITE"] =~ /y|yes|true|1|^\s*$/i ? true : false) : true
35
35
  options[:checksum] = ENV["S3CP_CHECKSUM"] ? (ENV["S3CP_CHECKSUM"] =~ /y|yes|true|1|^\s*$/i ? true : false) : true
36
- options[:retries] = ENV["S3CP_RETRIES"] ? ENV["S3CP_RETRIES"].to_i : 5
36
+ options[:retries] = ENV["S3CP_RETRIES"] ? ENV["S3CP_RETRIES"].to_i : 18
37
37
  options[:retry_delay] = ENV["S3CP_RETRY_DELAY"] ? ENV["S3CP_RETRY_DELAY"].to_i : 1
38
+ options[:retry_backoff] = ENV["S3CP_BACKOFF"] ? ENV["S3CP_BACKOFF"].to_f : 1.4142 # double every 2 tries
39
+
38
40
  options[:include_regex] = []
39
41
  options[:exclude_regex] = []
40
42
  options[:sync] = false
@@ -82,6 +84,10 @@ op = OptionParser.new do |opts|
82
84
  options[:retry_delay] = delay.to_i
83
85
  end
84
86
 
87
+ opts.on("--retry-backoff FACTOR", "Exponential backoff factor (default #{options[:retry_backoff]})") do |factor|
88
+ options[:retry_backoff] = factor.to_f
89
+ end
90
+
85
91
  opts.on("--no-checksum", "Disable checksum checking") do
86
92
  options[:checksum] = false
87
93
  end
@@ -266,8 +272,9 @@ def local_to_s3(bucket_to, key, file, options = {})
266
272
  fail "Unable to upload to s3://#{bucket_to}/#{key} after #{retries} attempts."
267
273
  end
268
274
  if retries > 0
269
- STDERR.puts "Warning: failed checksum for s3://#{bucket_to}/#{bucket_to}. Retrying #{options[:retries] - retries} more time(s)."
270
- sleep options[:retry_delay]
275
+ delay = options[:retry_delay] * (options[:retry_backoff] ** retries)
276
+ STDERR.puts "Sleeping #{delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
277
+ sleep delay
271
278
  end
272
279
 
273
280
  f = File.open(file)
@@ -285,7 +292,7 @@ def local_to_s3(bucket_to, key, file, options = {})
285
292
  @progress_bar.inc result.length if result
286
293
  result
287
294
  rescue => e
288
- puts e
295
+ STDERR.puts e
289
296
  raise e
290
297
  end
291
298
  end
@@ -300,8 +307,12 @@ def local_to_s3(bucket_to, key, file, options = {})
300
307
 
301
308
  if options[:checksum]
302
309
  actual_md5 = s3_checksum(bucket_to, key)
303
- unless actual_md5.is_a? String
304
- STDERR.puts "Warning: invalid MD5 checksum in metadata; skipped checksum verification."
310
+ if actual_md5.is_a? String
311
+ if actual_md5 != expected_md5
312
+ STDERR.puts "Warning: invalid MD5 checksum. Expected: #{expected_md5} Actual: #{actual_md5}"
313
+ end
314
+ else
315
+ STDERR.puts "Warning: invalid MD5 checksum in metadata: #{actual_md5.inspect}; skipped checksum verification."
305
316
  actual_md5 = nil
306
317
  end
307
318
  end
@@ -328,8 +339,9 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
328
339
  fail "Unable to download s3://#{bucket_from}/#{key_from} after #{retries} attempts."
329
340
  end
330
341
  if retries > 0
331
- STDERR.puts "Warning: failed checksum for s3://#{bucket_from}/#{key_from}. Retrying #{options[:retries] - retries} more time(s)."
332
- sleep options[:retry_delay]
342
+ delay = options[:retry_delay] * (options[:retry_backoff] ** retries)
343
+ STDERR.puts "Sleeping #{delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
344
+ sleep delay
333
345
  end
334
346
  begin
335
347
  expected_md5 = if options[:checksum] || options[:sync]
@@ -377,6 +389,14 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
377
389
  raise e unless options[:checksum]
378
390
  STDERR.puts e
379
391
  end
392
+
393
+ if options[:checksum] && expected_md5 != nil
394
+ actual_md5 = md5(dest)
395
+ if actual_md5 != expected_md5
396
+ STDERR.puts "Warning: invalid MD5 checksum. Expected: #{expected_md5} Actual: #{actual_md5}"
397
+ end
398
+ end
399
+
380
400
  retries += 1
381
401
  end until options[:checksum] == false || expected_md5.nil? || md5(dest) == expected_md5
382
402
  end
data/lib/s3cp/s3du.rb CHANGED
@@ -102,39 +102,43 @@ def print(key, size)
102
102
  puts ("%#{7 + @options[:precision]}s " % size) + key
103
103
  end
104
104
 
105
- @s3.interface.incrementally_list_bucket(@bucket, s3_options) do |page|
106
-
107
- entries = page[:contents]
108
- entries.each do |entry|
109
- key = entry[:key]
110
- size = entry[:size]
111
-
112
- if options[:regex].nil? || options[:regex].match(key)
113
- current_key = if actual_depth
114
- pos = nth_occurrence(key, "/", actual_depth)
115
- pos ? key[0..pos-1] : prefix
105
+ begin
106
+ @s3.interface.incrementally_list_bucket(@bucket, s3_options) do |page|
107
+
108
+ entries = page[:contents]
109
+ entries.each do |entry|
110
+ key = entry[:key]
111
+ size = entry[:size]
112
+
113
+ if options[:regex].nil? || options[:regex].match(key)
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
116
128
  end
117
-
118
- if (last_key && last_key != current_key)
119
- print(last_key, subtotal_size)
120
- subtotal_size = size
121
- else
122
- subtotal_size += size
123
- end
124
-
125
- last_key = current_key
126
- total_size += size
127
129
  end
128
130
  end
129
- end
130
131
 
131
- if last_key != nil
132
- print(last_key, subtotal_size)
133
- end
132
+ if last_key != nil
133
+ print(last_key, subtotal_size)
134
+ end
134
135
 
135
- if options[:depth] > 0
136
- print("", total_size)
137
- else
138
- puts S3CP.format_filesize(total_size, :unit => options[:unit], :precision => options[:precision])
136
+ if options[:depth] > 0
137
+ print("", total_size)
138
+ else
139
+ puts S3CP.format_filesize(total_size, :unit => options[:unit], :precision => options[:precision])
140
+ end
141
+ rescue Errno::EPIPE
142
+ # ignore
139
143
  end
140
144
 
data/lib/s3cp/s3ls.rb CHANGED
@@ -103,39 +103,43 @@ s3_options[:prefix] = @key
103
103
  s3_options["max-keys"] = options[:max_keys] if options[:max_keys] && !options[:delimiter]
104
104
  s3_options[:delimiter] = options[:delimiter] if options[:delimiter]
105
105
 
106
- @s3.interface.incrementally_list_bucket(@bucket, s3_options) do |page|
107
- entries = []
108
- if options[:delimiter]
109
- entries << { :key => page[:contents][0][:key] } if page[:contents].length > 0 && entries.length > 0
110
- page[:common_prefixes].each do |entry|
111
- entries << { :key => entry }
106
+ begin
107
+ @s3.interface.incrementally_list_bucket(@bucket, s3_options) do |page|
108
+ entries = []
109
+ if options[:delimiter]
110
+ entries << { :key => page[:contents][0][:key] } if page[:contents].length > 0 && entries.length > 0
111
+ page[:common_prefixes].each do |entry|
112
+ entries << { :key => entry }
113
+ end
114
+ entries << { :key => nil }
112
115
  end
113
- entries << { :key => nil }
114
- end
115
- entries += page[:contents]
116
- entries.each do |entry|
117
- key = entry[:key] ? "s3://#{@bucket}/#{entry[:key]}" : "---"
118
- if options[:long_format] && entry[:last_modified] && entry[:size]
119
- last_modified = DateTime.parse(entry[:last_modified])
120
- size = entry[:size]
121
- size = S3CP.format_filesize(size, :unit => options[:unit], :precision => options[:precision])
122
- size = ("%#{7 + options[:precision]}s " % size)
123
- puts "#{last_modified.strftime(options[:date_format])} #{size} #{key}"
124
- else
125
- puts key
126
- end
127
- rows += 1
128
- keys += 1
129
- if options[:max_keys] && keys >= options[:max_keys]
130
- exit
131
- end
132
- if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
133
- begin
134
- print "Continue? (Y/n) "
135
- response = STDIN.gets.chomp.downcase
136
- end until response == 'n' || response == 'y' || response == ''
137
- exit if response == 'n'
116
+ entries += page[:contents]
117
+ entries.each do |entry|
118
+ key = entry[:key] ? "s3://#{@bucket}/#{entry[:key]}" : "---"
119
+ if options[:long_format] && entry[:last_modified] && entry[:size]
120
+ last_modified = DateTime.parse(entry[:last_modified])
121
+ size = entry[:size]
122
+ size = S3CP.format_filesize(size, :unit => options[:unit], :precision => options[:precision])
123
+ size = ("%#{7 + options[:precision]}s " % size)
124
+ puts "#{last_modified.strftime(options[:date_format])} #{size} #{key}"
125
+ else
126
+ puts key
127
+ end
128
+ rows += 1
129
+ keys += 1
130
+ if options[:max_keys] && keys >= options[:max_keys]
131
+ exit
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'
139
+ end
138
140
  end
139
141
  end
142
+ rescue Errno::EPIPE
143
+ # ignore
140
144
  end
141
145
 
data/lib/s3cp/version.rb CHANGED
@@ -16,5 +16,5 @@
16
16
  # the License.
17
17
 
18
18
  module S3CP
19
- VERSION = "1.0.2"
19
+ VERSION = "1.0.3"
20
20
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3cp
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 2
10
- version: 1.0.2
9
+ - 3
10
+ version: 1.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Boisvert
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-09 00:00:00 Z
18
+ date: 2012-05-11 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  prerelease: false