s3cp 1.1.29 → 1.1.30

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ === 1.1.30 (2013-05-15)
2
+
3
+ * Changed: Improved error handling -- all commands now exit with non-zero exit
4
+ code on error. [Alexis Midon / alexism@github / Pull request #11]
5
+
6
+ * Changed: s3cp properly fails when source key is not specified or does not exist.
7
+ [Alexis Midon / alexism@github / Pull request #11]
8
+
1
9
  === 1.1.29 (2013-05-15)
2
10
 
3
11
  * Added: s3buckets command may now be used to delete buckets and enable/suspend
@@ -58,10 +58,11 @@ op = OptionParser.new do |opts|
58
58
  end
59
59
  op.parse!(ARGV)
60
60
 
61
- S3CP.load_config()
61
+ S3CP.standard_exception_handling(options) do
62
+
63
+ S3CP.load_config()
64
+ s3 = S3CP.connect()
62
65
 
63
- s3 = S3CP.connect()
64
- begin
65
66
  if options[:create]
66
67
  name = options[:create]
67
68
  create_options = {}
@@ -82,10 +83,5 @@ begin
82
83
  puts bucket.name
83
84
  end
84
85
  end
85
- rescue => e
86
- $stderr.print "s3buckets: [#{e.class}] #{e.message}\n"
87
- if options[:debug]
88
- $stderr.print e.backtrace.join("\n") + "\n"
89
- end
90
86
  end
91
87
 
data/lib/s3cp/s3cat.rb CHANGED
@@ -73,7 +73,7 @@ if options[:debug]
73
73
  puts "Options: \n#{options.inspect}"
74
74
  end
75
75
 
76
- begin
76
+ S3CP.standard_exception_handling(options) do
77
77
  @bucket, @prefix = S3CP.bucket_and_key(url)
78
78
  fail "Your URL looks funny, doesn't it?" unless @bucket
79
79
 
@@ -134,17 +134,11 @@ begin
134
134
  else
135
135
  @s3.objects[@prefix].read_as_stream(read_options) do |chunk|
136
136
  begin
137
- STDOUT.print(chunk)
137
+ $stdout.print(chunk)
138
138
  rescue Errno::EPIPE
139
139
  break
140
140
  end
141
141
  end
142
142
  end
143
-
144
- rescue => e
145
- $stderr.print "s3cat: [#{e.class}] #{e.message}\n"
146
- if options[:debug]
147
- $stderr.print e.backtrace.join("\n") + "\n"
148
- end
149
143
  end
150
144
 
data/lib/s3cp/s3cp.rb CHANGED
@@ -148,12 +148,12 @@ if ARGV.size < 2
148
148
  end
149
149
 
150
150
  if options[:include_regex].any? && !options[:recursive]
151
- STDERR.puts "-i (--include regex) option requires -r (recursive) option."
151
+ $stderr.puts "-i (--include regex) option requires -r (recursive) option."
152
152
  exit(1)
153
153
  end
154
154
 
155
155
  if options[:exclude_regex].any? && !options[:recursive]
156
- STDERR.puts "-x (--exclude regex) option requires -r (recursive) option."
156
+ $stderr.puts "-x (--exclude regex) option requires -r (recursive) option."
157
157
  exit(1)
158
158
  end
159
159
 
@@ -161,9 +161,9 @@ destination = ARGV.last
161
161
  sources = ARGV[0..-2]
162
162
 
163
163
  if options[:debug]
164
- STDERR.puts "sources: #{sources.inspect}"
165
- STDERR.puts "destination: #{destination}"
166
- STDERR.puts "Options: \n#{options.inspect}"
164
+ $stderr.puts "sources: #{sources.inspect}"
165
+ $stderr.puts "destination: #{destination}"
166
+ $stderr.puts "Options: \n#{options.inspect}"
167
167
  end
168
168
 
169
169
  class ProxyIO
@@ -282,7 +282,7 @@ def local_to_s3(bucket_to, key, file, options = {})
282
282
  when :not_found
283
283
  nil
284
284
  when :invalid
285
- STDERR.puts "Warning: No MD5 checksum available and ETag not suitable due to multi-part upload; file will be force-copied."
285
+ $stderr.puts "Warning: No MD5 checksum available and ETag not suitable due to multi-part upload; file will be force-copied."
286
286
  nil
287
287
  else
288
288
  md5
@@ -297,7 +297,7 @@ def local_to_s3(bucket_to, key, file, options = {})
297
297
  end
298
298
  if retries > 0
299
299
  delay = options[:retry_delay] * (options[:retry_backoff] ** retries)
300
- STDERR.puts "Sleeping #{"%0.2f" % delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
300
+ $stderr.puts "Sleeping #{"%0.2f" % delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
301
301
  sleep delay
302
302
  end
303
303
 
@@ -338,10 +338,10 @@ def local_to_s3(bucket_to, key, file, options = {})
338
338
  actual_md5 = s3_checksum(bucket_to, key)
339
339
  if actual_md5.is_a? String
340
340
  if actual_md5 != expected_md5
341
- STDERR.puts "Warning: invalid MD5 checksum. Expected: #{expected_md5} Actual: #{actual_md5}"
341
+ $stderr.puts "Warning: invalid MD5 checksum. Expected: #{expected_md5} Actual: #{actual_md5}"
342
342
  end
343
343
  else
344
- STDERR.puts "Warning: invalid MD5 checksum in metadata: #{actual_md5.inspect}; skipped checksum verification."
344
+ $stderr.puts "Warning: invalid MD5 checksum in metadata: #{actual_md5.inspect}; skipped checksum verification."
345
345
  actual_md5 = nil
346
346
  end
347
347
  end
@@ -349,10 +349,10 @@ def local_to_s3(bucket_to, key, file, options = {})
349
349
  actual_md5 = "bad"
350
350
  if progress_bar
351
351
  progress_bar.clear
352
- STDERR.puts "Error copying #{file} to s3://#{bucket_to}/#{key}"
352
+ $stderr.puts "Error copying #{file} to s3://#{bucket_to}/#{key}"
353
353
  end
354
354
  raise e if !options[:checksum] || e.is_a?(AWS::S3::Errors::AccessDenied)
355
- STDERR.puts e
355
+ $stderr.puts e
356
356
  end
357
357
  retries += 1
358
358
  end until options[:checksum] == false || actual_md5.nil? || expected_md5 == actual_md5
@@ -364,6 +364,7 @@ end
364
364
 
365
365
  def s3_to_local(bucket_from, key_from, dest, options = {})
366
366
  log("#{operation(options)} s3://#{bucket_from}/#{key_from} to #{dest}")
367
+ raise ArgumentError, "source key may not be blank" if key_from.to_s.empty?
367
368
 
368
369
  retries = 0
369
370
  begin
@@ -374,17 +375,17 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
374
375
  if retries > 0
375
376
  delay = options[:retry_delay] * (options[:retry_backoff] ** retries)
376
377
  delay = delay.to_i
377
- STDERR.puts "Sleeping #{"%0.2f" % delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
378
+ $stderr.puts "Sleeping #{"%0.2f" % delay} seconds. Will retry #{options[:retries] - retries} more time(s)."
378
379
  sleep delay
379
380
  end
380
381
  begin
381
382
  expected_md5 = if options[:checksum] || options[:sync]
382
383
  md5 = s3_checksum(bucket_from, key_from)
383
384
  if options[:sync] && !md5.is_a?(String)
384
- STDERR.puts "Warning: invalid MD5 checksum in metadata; file will be force-copied."
385
+ $stderr.puts "Warning: invalid MD5 checksum in metadata; file will be force-copied."
385
386
  nil
386
387
  elsif !md5.is_a? String
387
- STDERR.puts "Warning: invalid MD5 checksum in metadata; skipped checksum verification."
388
+ $stderr.puts "Warning: invalid MD5 checksum in metadata; skipped checksum verification."
388
389
  nil
389
390
  else
390
391
  md5
@@ -420,14 +421,15 @@ def s3_to_local(bucket_from, key_from, dest, options = {})
420
421
  return
421
422
  end
422
423
  rescue => e
424
+ raise e if e.is_a?(AWS::S3::Errors::NoSuchKey)
423
425
  raise e unless options[:checksum]
424
- STDERR.puts e
426
+ $stderr.puts e
425
427
  end
426
428
 
427
429
  if options[:checksum] && expected_md5 != nil
428
430
  actual_md5 = S3CP.md5(dest)
429
431
  if actual_md5 != expected_md5
430
- STDERR.puts "Warning: invalid MD5 checksum. Expected: #{expected_md5} Actual: #{actual_md5}"
432
+ $stderr.puts "Warning: invalid MD5 checksum. Expected: #{expected_md5} Actual: #{actual_md5}"
431
433
  end
432
434
  end
433
435
 
@@ -487,7 +489,7 @@ def copy(from, to, options)
487
489
  if match(key)
488
490
  dest = key_path key_to, relative(key_from, key)
489
491
  if !options[:overwrite] && s3_exist?(bucket_to, dest)
490
- STDERR.puts "Skipping s3://#{bucket_to}/#{dest} - already exists."
492
+ $stderr.puts "Skipping s3://#{bucket_to}/#{dest} - already exists."
491
493
  else
492
494
  s3_to_s3(bucket_from, key, bucket_to, dest, options)
493
495
  end
@@ -496,7 +498,7 @@ def copy(from, to, options)
496
498
  else
497
499
  key_to += File.basename(key_from) if key_to[-1..-1] == "/"
498
500
  if !options[:overwrite] && s3_exist?(bucket_to, key_to)
499
- STDERR.puts "Skipping s3://#{bucket_to}/#{key_to} - already exists."
501
+ $stderr.puts "Skipping s3://#{bucket_to}/#{key_to} - already exists."
500
502
  else
501
503
  s3_to_s3(bucket_from, key_from, bucket_to, key_to, options)
502
504
  end
@@ -511,7 +513,7 @@ def copy(from, to, options)
511
513
  #puts "relative(from, f) #{relative(from, f)}"
512
514
  key = key_path key_to, relative(from, f)
513
515
  if !options[:overwrite] && s3_exist?(bucket_to, key)
514
- STDERR.puts "Skipping s3://#{bucket_to}/#{key} - already exists."
516
+ $stderr.puts "Skipping s3://#{bucket_to}/#{key} - already exists."
515
517
  else
516
518
  local_to_s3(bucket_to, key, File.expand_path(f), options)
517
519
  end
@@ -520,7 +522,7 @@ def copy(from, to, options)
520
522
  else
521
523
  key_to += File.basename(from) if key_to[-1..-1] == "/"
522
524
  if !options[:overwrite] && s3_exist?(bucket_to, key_to)
523
- STDERR.puts "Skipping s3://#{bucket_to}/#{key_to} - already exists."
525
+ $stderr.puts "Skipping s3://#{bucket_to}/#{key_to} - already exists."
524
526
  else
525
527
  local_to_s3(bucket_to, key_to, File.expand_path(from), options)
526
528
  end
@@ -539,7 +541,7 @@ def copy(from, to, options)
539
541
  FileUtils.mkdir_p dir unless File.exist? dir
540
542
  fail "Destination path is not a directory: #{dir}" unless File.directory?(dir)
541
543
  if !options[:overwrite] && File.exist?(dest)
542
- STDERR.puts "Skipping #{dest} - already exists."
544
+ $stderr.puts "Skipping #{dest} - already exists."
543
545
  else
544
546
  s3_to_local(bucket_from, key, dest, options)
545
547
  end
@@ -549,7 +551,7 @@ def copy(from, to, options)
549
551
  dest = File.expand_path(to)
550
552
  dest = File.join(dest, File.basename(key_from)) if File.directory?(dest)
551
553
  if !options[:overwrite] && File.exist?(dest)
552
- STDERR.puts "Skipping #{dest} - already exists."
554
+ $stderr.puts "Skipping #{dest} - already exists."
553
555
  else
554
556
  s3_to_local(bucket_from, key_from, dest, options)
555
557
  end
@@ -568,13 +570,8 @@ def copy(from, to, options)
568
570
  end
569
571
  end
570
572
 
571
- begin
573
+ S3CP.standard_exception_handling(options) do
572
574
  sources.each do |source|
573
575
  copy(source, destination, options)
574
576
  end
575
- rescue => e
576
- $stderr.print "s3cp: [#{e.class}] #{e.message}\n"
577
- if options[:debug]
578
- $stderr.print e.backtrace.join("\n") + "\n"
579
- end
580
577
  end
data/lib/s3cp/s3du.rb CHANGED
@@ -67,9 +67,6 @@ url = ARGV[0]
67
67
  @bucket, @prefix = S3CP.bucket_and_key(url)
68
68
  fail "Your URL looks funny, doesn't it?" unless @bucket
69
69
 
70
- S3CP.load_config()
71
-
72
- @s3 = S3CP.connect()
73
70
 
74
71
  def depth(path)
75
72
  path.count("/")
@@ -98,56 +95,57 @@ def print(key, size)
98
95
  puts ("%#{7 + @options[:precision]}s " % size) + key
99
96
  end
100
97
 
101
- begin
102
- s3_options = Hash.new
103
- s3_options[:bucket_name] = @bucket
104
- s3_options[:prefix] = @prefix
105
-
106
- begin
107
- response = @s3.client.list_objects(s3_options)
108
- response[:contents].each do |object|
109
-
110
- key = object[:key]
111
- size = object[:size].to_i
98
+ S3CP.standard_exception_handling(options) do
112
99
 
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
100
+ S3CP.load_config()
101
+ @s3 = S3CP.connect()
118
102
 
119
- if (last_key && last_key != current_key)
120
- print(last_key, subtotal_size)
121
- subtotal_size = size
122
- else
123
- subtotal_size += size
103
+ begin
104
+ s3_options = Hash.new
105
+ s3_options[:bucket_name] = @bucket
106
+ s3_options[:prefix] = @prefix
107
+
108
+ begin
109
+ response = @s3.client.list_objects(s3_options)
110
+ response[:contents].each do |object|
111
+
112
+ key = object[:key]
113
+ size = object[:size].to_i
114
+
115
+ if options[:regex].nil? || options[:regex].match(key)
116
+ current_key = if actual_depth
117
+ pos = nth_occurrence(key, "/", actual_depth)
118
+ (pos != -1) ? key[0..pos-1] : key
119
+ end
120
+
121
+ if (last_key && last_key != current_key)
122
+ print(last_key, subtotal_size)
123
+ subtotal_size = size
124
+ else
125
+ subtotal_size += size
126
+ end
127
+
128
+ last_key = current_key
129
+ total_size += size
124
130
  end
125
-
126
- last_key = current_key
127
- total_size += size
128
131
  end
129
- end
130
132
 
131
- break if response[:contents].empty?
133
+ break if response[:contents].empty?
132
134
 
133
- s3_options.merge!(:marker => response[:contents].last[:key])
134
- end while response[:truncated]
135
+ s3_options.merge!(:marker => response[:contents].last[:key])
136
+ end while response[:truncated]
135
137
 
136
- if last_key != nil
137
- print(last_key, subtotal_size)
138
- end
138
+ if last_key != nil
139
+ print(last_key, subtotal_size)
140
+ end
139
141
 
140
- if options[:depth] > 0
141
- print("", total_size)
142
- else
143
- puts S3CP.format_filesize(total_size, :unit => options[:unit], :precision => options[:precision])
144
- end
145
- rescue Errno::EPIPE
146
- # ignore
147
- rescue => e
148
- $stderr.print "s3du: [#{e.class}] #{e.message}\n"
149
- if options[:debug]
150
- $stderr.print e.backtrace.join("\n") + "\n"
142
+ if options[:depth] > 0
143
+ print("", total_size)
144
+ else
145
+ puts S3CP.format_filesize(total_size, :unit => options[:unit], :precision => options[:precision])
146
+ end
147
+ rescue Errno::EPIPE
148
+ # ignore
151
149
  end
152
150
  end
153
151
 
@@ -71,9 +71,6 @@ if ARGV.size == 0
71
71
  exit
72
72
  end
73
73
 
74
- S3CP.load_config()
75
- @s3 = S3CP.connect()
76
-
77
74
  def time_or_date_str(msg, t)
78
75
  if t.is_a?(Fixnum) || t.to_s =~ /^\d+$/
79
76
  "%s after %d days" % [msg, t.to_i]
@@ -91,83 +88,88 @@ def rule_to_str(r)
91
88
  [ r.prefix || "[root]", r.id, r.status, "???"]
92
89
  end
93
90
  end
91
+ S3CP.standard_exception_handling(options) do
92
+
93
+ S3CP.load_config()
94
+ @s3 = S3CP.connect()
95
+
96
+ paths.each do |path|
97
+ bucket,key = S3CP.bucket_and_key(path)
98
+ fail "Invalid bucket/key: #{path}" unless key
94
99
 
95
- paths.each do |path|
96
- bucket,key = S3CP.bucket_and_key(path)
97
- fail "Invalid bucket/key: #{path}" unless key
98
-
99
- case
100
-
101
- when options[:expire]
102
- @s3.buckets[bucket].lifecycle_configuration.update do
103
- rule_options = {}
104
- rule_options[:id] = options[:name] if options[:name]
105
- rule_options[:expiration_time] = S3CP.parse_days_or_date(options[:expire])
106
- add_rule(key, rule_options)
107
- end
108
-
109
- when options[:glacier]
110
- @s3.buckets[bucket].lifecycle_configuration.update do
111
- rule_options = {}
112
- rule_options[:id] = options[:name] if options[:name]
113
- rule_options[:glacier_transition_time] = S3CP.parse_days_or_date(options[:glacier])
114
- add_rule(key, rule_options)
115
- end
116
-
117
- when options[:enable]
118
- success = false
119
- @s3.buckets[bucket].lifecycle_configuration.update do
120
- self.rules.each do |r|
121
- if (r.prefix == key) || (r.id == options[:name])
122
- r.enable!
123
- puts "Enabled rule: "
124
- puts S3CP.tableify([rule_to_str(r)])
125
- success = true
100
+ case
101
+
102
+ when options[:expire]
103
+ @s3.buckets[bucket].lifecycle_configuration.update do
104
+ rule_options = {}
105
+ rule_options[:id] = options[:name] if options[:name]
106
+ rule_options[:expiration_time] = S3CP.parse_days_or_date(options[:expire])
107
+ add_rule(key, rule_options)
108
+ end
109
+
110
+ when options[:glacier]
111
+ @s3.buckets[bucket].lifecycle_configuration.update do
112
+ rule_options = {}
113
+ rule_options[:id] = options[:name] if options[:name]
114
+ rule_options[:glacier_transition_time] = S3CP.parse_days_or_date(options[:glacier])
115
+ add_rule(key, rule_options)
116
+ end
117
+
118
+ when options[:enable]
119
+ success = false
120
+ @s3.buckets[bucket].lifecycle_configuration.update do
121
+ self.rules.each do |r|
122
+ if (r.prefix == key) || (r.id == options[:name])
123
+ r.enable!
124
+ puts "Enabled rule: "
125
+ puts S3CP.tableify([rule_to_str(r)])
126
+ success = true
127
+ end
126
128
  end
127
129
  end
128
- end
129
- fail "Rule or prefix not found" unless success
130
-
131
- when options[:disable]
132
- success = false
133
- @s3.buckets[bucket].lifecycle_configuration.update do
134
- self.rules.each do |r|
135
- if (r.prefix == key) || (r.id == options[:name])
136
- r.disabled!
137
- puts "Disabled rule: "
138
- puts S3CP.tableify([rule_to_str(r)])
139
- success = true
130
+ fail "Rule or prefix not found" unless success
131
+
132
+ when options[:disable]
133
+ success = false
134
+ @s3.buckets[bucket].lifecycle_configuration.update do
135
+ self.rules.each do |r|
136
+ if (r.prefix == key) || (r.id == options[:name])
137
+ r.disabled!
138
+ puts "Disabled rule: "
139
+ puts S3CP.tableify([rule_to_str(r)])
140
+ success = true
141
+ end
140
142
  end
141
143
  end
142
- end
143
- fail "Rule or prefix not found" unless success
144
-
145
- when options[:delete]
146
- success = false
147
- @s3.buckets[bucket].lifecycle_configuration.update do
148
- self.rules.each do |r|
149
- if (r.prefix == key) || (r.id == options[:name])
150
- remove_rule(r)
151
- puts "Deleted rule: "
152
- puts S3CP.tableify([rule_to_str(r)])
153
- success = true
144
+ fail "Rule or prefix not found" unless success
145
+
146
+ when options[:delete]
147
+ success = false
148
+ @s3.buckets[bucket].lifecycle_configuration.update do
149
+ self.rules.each do |r|
150
+ if (r.prefix == key) || (r.id == options[:name])
151
+ remove_rule(r)
152
+ puts "Deleted rule: "
153
+ puts S3CP.tableify([rule_to_str(r)])
154
+ success = true
155
+ end
154
156
  end
155
157
  end
156
- end
157
- fail "Rule or prefix not found" unless success
158
+ fail "Rule or prefix not found" unless success
158
159
 
159
- else
160
- rules = @s3.buckets[bucket].lifecycle_configuration.rules.to_a
161
- if rules.empty?
162
- puts "#{bucket} - no lifecycle rules"
163
160
  else
164
- puts "#{bucket} - lifecycle rules:"
165
- begin
166
- puts S3CP.tableify(rules.map { |r| rule_to_str(r) })
167
- rescue => e
168
- puts rules.inspect
169
- raise e
161
+ rules = @s3.buckets[bucket].lifecycle_configuration.rules.to_a
162
+ if rules.empty?
163
+ puts "#{bucket} - no lifecycle rules"
164
+ else
165
+ puts "#{bucket} - lifecycle rules:"
166
+ begin
167
+ puts S3CP.tableify(rules.map { |r| rule_to_str(r) })
168
+ rescue => e
169
+ puts rules.inspect
170
+ raise e
171
+ end
170
172
  end
171
- end
173
+ end
172
174
  end
173
175
  end
data/lib/s3cp/s3ls.rb CHANGED
@@ -90,75 +90,74 @@ if options[:debug]
90
90
  puts "key #{@key}"
91
91
  end
92
92
 
93
- S3CP.load_config()
94
-
95
- @s3 = S3CP.connect()
96
93
 
97
94
  keys = 0
98
95
  rows = 0
99
96
  directories = true
100
97
 
101
- begin
102
- display = lambda do |entry|
103
- # add '---' separator line between directories and files
104
- if options[:delimiter] && directories && entry.is_a?(AWS::S3::Tree::LeafNode)
105
- directories = false
106
- puts "---"
98
+ S3CP.standard_exception_handling(options) do
99
+
100
+ S3CP.load_config()
101
+
102
+ @s3 = S3CP.connect()
103
+
104
+ begin
105
+ display = lambda do |entry|
106
+ # add '---' separator line between directories and files
107
+ if options[:delimiter] && directories && entry.is_a?(AWS::S3::Tree::LeafNode)
108
+ directories = false
109
+ puts "---"
110
+ end
111
+
112
+ key = "s3://#{@bucket}/#{entry.respond_to?(:key) ? entry.key : entry.prefix}"
113
+ if options[:long_format] && entry.last_modified && entry.content_length
114
+ size = entry.content_length
115
+ size = S3CP.format_filesize(size, :unit => options[:unit], :precision => options[:precision])
116
+ size = ("%#{7 + options[:precision]}s " % size)
117
+ puts "#{entry.last_modified.strftime(options[:date_format])} #{size} #{key}"
118
+ else
119
+ puts key
120
+ end
121
+ rows += 1
122
+ keys += 1
123
+ response = ''
124
+
125
+ if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
126
+ begin
127
+ print "Continue? (Y/n) "
128
+ response = STDIN.gets.chomp.downcase
129
+ end until response == 'n' || response == 'y' || response == ''
130
+ end
131
+ (response == 'n')
107
132
  end
108
133
 
109
- key = "s3://#{@bucket}/#{entry.respond_to?(:key) ? entry.key : entry.prefix}"
110
- if options[:long_format] && entry.last_modified && entry.content_length
111
- size = entry.content_length
112
- size = S3CP.format_filesize(size, :unit => options[:unit], :precision => options[:precision])
113
- size = ("%#{7 + options[:precision]}s " % size)
114
- puts "#{entry.last_modified.strftime(options[:date_format])} #{size} #{key}"
134
+ if options[:delimiter]
135
+ @s3.buckets[@bucket].objects.with_prefix(@key).as_tree(:delimier => options[:delimiter], :append => false).children.each do |entry|
136
+ break if display.call(entry)
137
+ end
115
138
  else
116
- puts key
117
- end
118
- rows += 1
119
- keys += 1
120
- response = ''
139
+ Struct.new("S3Entry", :key, :last_modified, :content_length)
121
140
 
122
- if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
123
- begin
124
- print "Continue? (Y/n) "
125
- response = STDIN.gets.chomp.downcase
126
- end until response == 'n' || response == 'y' || response == ''
127
- end
128
- (response == 'n')
129
- end
141
+ s3_options = Hash.new
142
+ s3_options[:bucket_name] = @bucket
143
+ s3_options[:prefix] = @key
144
+ s3_options[:limit] = options[:max_keys] if options[:max_keys]
130
145
 
131
- if options[:delimiter]
132
- @s3.buckets[@bucket].objects.with_prefix(@key).as_tree(:delimier => options[:delimiter], :append => false).children.each do |entry|
133
- break if display.call(entry)
146
+ stop = false
147
+
148
+ begin
149
+ response = @s3.client.list_objects(s3_options)
150
+ response[:contents].each do |object|
151
+ entry = Struct::S3Entry.new(object[:key], object[:last_modified], object[:size].to_i)
152
+ stop = display.call(entry)
153
+ break if stop
154
+ end
155
+ break if stop || response[:contents].empty?
156
+ s3_options.merge!(:marker => response[:contents].last[:key])
157
+ end while response[:truncated]
134
158
  end
135
- else
136
- Struct.new("S3Entry", :key, :last_modified, :content_length)
137
-
138
- s3_options = Hash.new
139
- s3_options[:bucket_name] = @bucket
140
- s3_options[:prefix] = @key
141
- s3_options[:limit] = options[:max_keys] if options[:max_keys]
142
-
143
- stop = false
144
-
145
- begin
146
- response = @s3.client.list_objects(s3_options)
147
- response[:contents].each do |object|
148
- entry = Struct::S3Entry.new(object[:key], object[:last_modified], object[:size].to_i)
149
- stop = display.call(entry)
150
- break if stop
151
- end
152
- break if stop || response[:contents].empty?
153
- s3_options.merge!(:marker => response[:contents].last[:key])
154
- end while response[:truncated]
155
- end
156
- rescue Errno::EPIPE
157
- # ignore
158
- rescue => e
159
- $stderr.print "s3ls: [#{e.class}] #{e.message}\n"
160
- if options[:debug]
161
- $stderr.print e.backtrace.join("\n") + "\n"
159
+ rescue Errno::EPIPE
160
+ # ignore
162
161
  end
163
162
  end
164
163
 
data/lib/s3cp/s3mod.rb CHANGED
@@ -91,7 +91,7 @@ if !options[:acl] && paths.size > 1 && S3CP::LEGAL_MODS.include?(paths.last)
91
91
  options[:acl] = S3CP.validate_acl(paths.pop);
92
92
  end
93
93
 
94
- begin
94
+ S3CP.standard_exception_handling(options) do
95
95
  S3CP.load_config()
96
96
  @s3 = S3CP.connect()
97
97
 
@@ -112,9 +112,4 @@ begin
112
112
  end
113
113
  }
114
114
  end
115
- rescue => e
116
- $stderr.print "s3mod: [#{e.class}] #{e.message}\n"
117
- if options[:debug]
118
- $stderr.print e.backtrace.join("\n") + "\n"
119
- end
120
115
  end
data/lib/s3cp/s3rm.rb CHANGED
@@ -102,7 +102,7 @@ end
102
102
  include_regex = options[:include_regex] ? Regexp.new(options[:include_regex]) : nil
103
103
  exclude_regex = options[:exclude_regex] ? Regexp.new(options[:exclude_regex]) : nil
104
104
 
105
- begin
105
+ S3CP.standard_exception_handling(options) do
106
106
  S3CP.load_config()
107
107
 
108
108
  @s3 = S3CP.connect()
@@ -147,10 +147,5 @@ begin
147
147
  raise e unless e.is_a? AWS::S3::Errors::NoSuchKey
148
148
  end
149
149
  end
150
- rescue => e
151
- $stderr.print "s3rm: [#{e.class}] #{e.message}\n"
152
- if options[:debug]
153
- $stderr.print e.backtrace.join("\n") + "\n"
154
- end
155
150
  end
156
151
 
data/lib/s3cp/s3stat.rb CHANGED
@@ -45,19 +45,21 @@ permission = ARGV.last
45
45
  @bucket, @key = S3CP.bucket_and_key(source)
46
46
  fail "Your URL looks funny, doesn't it?" unless @bucket
47
47
 
48
- S3CP.load_config()
48
+ S3CP.standard_exception_handling(options) do
49
+ S3CP.load_config()
49
50
 
50
- @s3 = S3CP.connect().buckets[@bucket]
51
+ @s3 = S3CP.connect().buckets[@bucket]
51
52
 
52
- obj = @s3.objects[@key]
53
+ obj = @s3.objects[@key]
53
54
 
54
- metadata = obj.head
55
- metadata.to_h.keys.sort { |k1, k2| k1.to_s <=> k2.to_s}.each do |k|
56
- puts "#{"%30s" % k} #{metadata[k].is_a?(Hash) ? metadata[k].inspect : metadata[k].to_s}"
57
- end
55
+ metadata = obj.head
56
+ metadata.to_h.keys.sort { |k1, k2| k1.to_s <=> k2.to_s}.each do |k|
57
+ puts "#{"%30s" % k} #{metadata[k].is_a?(Hash) ? metadata[k].inspect : metadata[k].to_s}"
58
+ end
58
59
 
59
- if @options[:acl]
60
- puts
61
- xml = Nokogiri::XML(obj.acl.to_s)
62
- puts xml.to_s
60
+ if @options[:acl]
61
+ puts
62
+ xml = Nokogiri::XML(obj.acl.to_s)
63
+ puts xml.to_s
64
+ end
63
65
  end
data/lib/s3cp/s3tree.rb CHANGED
@@ -68,104 +68,101 @@ url = ARGV[0]
68
68
  @bucket, @key = S3CP.bucket_and_key(url)
69
69
  fail "Your URL looks funny, doesn't it?" unless @bucket
70
70
 
71
- S3CP.load_config()
72
-
73
- @s3 = S3CP.connect().buckets[@bucket]
74
71
 
75
72
  keys = 0
76
73
  rows = 0
77
74
 
78
- begin
79
- # find last index of character `ch` in `str`.
80
- last_index_of = lambda do |str, ch|
81
- case
82
- when str[ch] then str.length-(str.reverse.index(ch)+1)
83
- else -1
84
- end
85
- end
75
+ S3CP.standard_exception_handling(options) do
76
+ S3CP.load_config()
77
+ @s3 = S3CP.connect().buckets[@bucket]
86
78
 
87
- # displays the next line, returns true if user interrupts or max keys shown
88
- display_line = lambda do |line|
89
- puts line
90
- keys += 1
91
- if options[:max_keys] && keys > options[:max_keys]
92
- return true
93
- end
94
- rows += 1
95
- response = ''
96
- if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
97
- begin
98
- print "Continue? (Y/n) "
99
- response = STDIN.gets.chomp.downcase
100
- end until response == 'n' || response == 'y' || response == ''
79
+ begin
80
+ # find last index of character `ch` in `str`.
81
+ last_index_of = lambda do |str, ch|
82
+ case
83
+ when str[ch] then str.length-(str.reverse.index(ch)+1)
84
+ else -1
85
+ end
101
86
  end
102
- (response == 'n')
103
- end
104
87
 
105
- # returns relative path against @key
106
- #
107
- # e.g. relative.call("foo/bar") => "bar" (assuming @key = "foo/")
108
- #
109
- relative = lambda do |key|
110
- last_delimiter = last_index_of.call(@key, options[:delimiter])
111
- (last_delimiter != -1) ? key[last_delimiter..-1] : key
112
- end
88
+ # displays the next line, returns true if user interrupts or max keys shown
89
+ display_line = lambda do |line|
90
+ puts line
91
+ keys += 1
92
+ if options[:max_keys] && keys > options[:max_keys]
93
+ return true
94
+ end
95
+ rows += 1
96
+ response = ''
97
+ if options[:rows_per_page] && (rows % options[:rows_per_page] == 0)
98
+ begin
99
+ print "Continue? (Y/n) "
100
+ response = STDIN.gets.chomp.downcase
101
+ end until response == 'n' || response == 'y' || response == ''
102
+ end
103
+ (response == 'n')
104
+ end
113
105
 
114
- # trim up to the last delimiter
115
- #
116
- # e.g. trim.call("foo/bar") => "foo/"
117
- #
118
- trim = lambda do |key|
119
- last_delimiter = last_index_of.call(key, options[:delimiter])
120
- (last_delimiter != -1) ? key[0..last_delimiter] : ""
121
- end
106
+ # returns relative path against @key
107
+ #
108
+ # e.g. relative.call("foo/bar") => "bar" (assuming @key = "foo/")
109
+ #
110
+ relative = lambda do |key|
111
+ last_delimiter = last_index_of.call(@key, options[:delimiter])
112
+ (last_delimiter != -1) ? key[last_delimiter..-1] : key
113
+ end
122
114
 
123
- # recursively display tree elements
124
- #
125
- # +prefix+: line prefix
126
- # +children+: children of the current directory
127
- # +depth+: current directory depth
128
- display_tree = lambda do |prefix, children, depth|
129
- stop = false
130
- children = children.to_a # aws-sdk returns a sucky ChildCollection object
131
- children.each_with_index do |node, index|
132
- node = node
133
- if options[:directories_only] && node.leaf?
134
- next
135
- end
115
+ # trim up to the last delimiter
116
+ #
117
+ # e.g. trim.call("foo/bar") => "foo/"
118
+ #
119
+ trim = lambda do |key|
120
+ last_delimiter = last_index_of.call(key, options[:delimiter])
121
+ (last_delimiter != -1) ? key[0..last_delimiter] : ""
122
+ end
136
123
 
137
- last = (index == children.size - 1)
138
- has_siblings = (children.size > 1)
139
- key = node.branch? ? node.prefix : node.key
140
- parts = relative.call(key).split(options[:delimiter])
141
- postfix = last ? '└── ' : '├── '
124
+ # recursively display tree elements
125
+ #
126
+ # +prefix+: line prefix
127
+ # +children+: children of the current directory
128
+ # +depth+: current directory depth
129
+ display_tree = lambda do |prefix, children, depth|
130
+ stop = false
131
+ children = children.to_a # aws-sdk returns a sucky ChildCollection object
132
+ children.each_with_index do |node, index|
133
+ node = node
134
+ if options[:directories_only] && node.leaf?
135
+ next
136
+ end
137
+
138
+ last = (index == children.size - 1)
139
+ has_siblings = (children.size > 1)
140
+ key = node.branch? ? node.prefix : node.key
141
+ parts = relative.call(key).split(options[:delimiter])
142
+ postfix = last ? '└── ' : '├── '
143
+
144
+ stop = display_line.call(prefix + postfix + parts.last)
145
+ break if stop
142
146
 
143
- stop = display_line.call(prefix + postfix + parts.last)
144
- break if stop
147
+ if node.branch? && depth < options[:max_depth]
148
+ new_prefix = prefix + (has_siblings ? "│ " : " ")
149
+ stop = display_tree.call(new_prefix, node.children, depth + 1)
150
+ break if stop
151
+ end
145
152
 
146
- if node.branch? && depth < options[:max_depth]
147
- new_prefix = prefix + (has_siblings ? "│ " : " ")
148
- stop = display_tree.call(new_prefix, node.children, depth + 1)
149
153
  break if stop
150
154
  end
151
-
152
- break if stop
155
+ stop
153
156
  end
154
- stop
155
- end
156
157
 
157
- display_line.call("s3://#{@bucket}/#{trim.call(@key)}")
158
-
159
- prefix = ""
160
- root = @s3.objects.with_prefix(@key).as_tree( :delimier => options[:delimiter], :append => false)
161
- depth = 1
162
- display_tree.call(prefix, root.children, depth)
163
- rescue Errno::EPIPE
164
- # ignore
165
- rescue => e
166
- $stderr.print "s3tree: [#{e.class}] #{e.message}\n"
167
- if options[:debug]
168
- $stderr.print e.backtrace.join("\n") + "\n"
158
+ display_line.call("s3://#{@bucket}/#{trim.call(@key)}")
159
+
160
+ prefix = ""
161
+ root = @s3.objects.with_prefix(@key).as_tree( :delimier => options[:delimiter], :append => false)
162
+ depth = 1
163
+ display_tree.call(prefix, root.children, depth)
164
+ rescue Errno::EPIPE
165
+ # ignore
169
166
  end
170
167
  end
171
168
 
data/lib/s3cp/s3up.rb CHANGED
@@ -69,9 +69,8 @@ url = ARGV[0]
69
69
  bucket, key = S3CP.bucket_and_key(url)
70
70
  fail "Your URL looks funny, doesn't it?" unless bucket
71
71
 
72
- begin
72
+ S3CP.standard_exception_handling(options) do
73
73
  S3CP.load_config()
74
-
75
74
  @s3 = S3CP.connect()
76
75
 
77
76
  # copy all of STDIN to a temp file
@@ -93,17 +92,12 @@ begin
93
92
  S3CP.set_header_options(s3_options, @headers)
94
93
  s3_options[:acl] = options[:acl]
95
94
  @s3.buckets[bucket].objects[key].write(temp, s3_options)
96
- STDERR.puts "s3://#{bucket}/#{key} => #{S3CP.format_filesize(temp.size)} "
95
+ $stderr.puts "s3://#{bucket}/#{key} => #{S3CP.format_filesize(temp.size)} "
97
96
  ensure
98
97
  # cleanup
99
98
  temp.close
100
99
  temp.delete
101
100
  end
102
- rescue => e
103
- $stderr.print "s3up: [#{e.class}] #{e.message}\n"
104
- if options[:debug]
105
- $stderr.print e.backtrace.join("\n") + "\n"
106
- end
107
101
  end
108
102
 
109
103
 
data/lib/s3cp/utils.rb CHANGED
@@ -250,6 +250,20 @@ module S3CP
250
250
  yield bucket.objects[key]
251
251
  end
252
252
  end
253
+
254
+ def standard_exception_handling(options)
255
+ begin
256
+ yield
257
+ rescue Exception => ex
258
+ cmd_name ||= File.basename(caller[1].split(/:/)[0], '.*')
259
+ $stderr.print "#{cmd_name} [#{ex.class}] #{ex.message}\n"
260
+ if options[:debug]
261
+ $stderr.print ex.backtrace.join("\n") + "\n"
262
+ end
263
+ exit 1
264
+ end
265
+ end
266
+
253
267
  end
254
268
 
255
269
  # Monkey-patch S3 object for download streaming
data/lib/s3cp/version.rb CHANGED
@@ -16,5 +16,5 @@
16
16
  # the License.
17
17
 
18
18
  module S3CP
19
- VERSION = "1.1.29"
19
+ VERSION = "1.1.30"
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: 41
4
+ hash: 47
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 29
10
- version: 1.1.29
9
+ - 30
10
+ version: 1.1.30
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Boisvert