s3 0.3.2 → 0.3.4

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/Gemfile.lock CHANGED
@@ -1,19 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- s3 (0.3.2)
4
+ s3 (0.3.3)
5
5
  proxies
6
- trollop
7
6
 
8
7
  GEM
9
8
  remote: http://rubygems.org/
10
9
  specs:
11
10
  mocha (0.9.8)
12
11
  rake
13
- proxies (0.1.1)
12
+ proxies (0.2.1)
14
13
  rake (0.8.7)
15
14
  test-unit (2.1.1)
16
- trollop (1.16.2)
17
15
 
18
16
  PLATFORMS
19
17
  ruby
@@ -24,4 +22,3 @@ DEPENDENCIES
24
22
  proxies
25
23
  s3!
26
24
  test-unit (>= 2.0)
27
- trollop
data/lib/s3/bucket.rb CHANGED
@@ -85,7 +85,7 @@ module S3
85
85
  # Returns the objects in the bucket and caches the result (see
86
86
  # #reload method).
87
87
  def objects
88
- MethodProxy.new(self, :list_bucket, :extend => ObjectsExtension)
88
+ Proxy.new(lambda { list_bucket }, :owner => self, :extend => ObjectsExtension)
89
89
  end
90
90
 
91
91
  def inspect #:nodoc:
data/lib/s3/service.rb CHANGED
@@ -28,7 +28,7 @@ module S3
28
28
  @use_ssl = options.fetch(:use_ssl, false)
29
29
  @timeout = options.fetch(:timeout, 60)
30
30
  @debug = options.fetch(:debug, false)
31
-
31
+
32
32
  raise ArgumentError, "Missing proxy settings. Must specify at least :host." if options[:proxy] && !options[:proxy][:host]
33
33
  @proxy = options.fetch(:proxy, nil)
34
34
  end
@@ -36,7 +36,7 @@ module S3
36
36
  # Returns all buckets in the service and caches the result (see
37
37
  # +reload+)
38
38
  def buckets
39
- MethodProxy.new(self, :list_all_my_buckets, :extend => BucketsExtension)
39
+ Proxy.new(lambda { list_all_my_buckets}, :owner => self, :extend => BucketsExtension)
40
40
  end
41
41
 
42
42
  # Returns "http://" or "https://", depends on <tt>:use_ssl</tt>
data/lib/s3/signature.rb CHANGED
@@ -23,64 +23,108 @@ module S3
23
23
  # Generated signature string for given hostname and request
24
24
  def self.generate(options)
25
25
  request = options[:request]
26
- host = options[:host]
27
26
  access_key_id = options[:access_key_id]
28
- secret_access_key = options[:secret_access_key]
29
-
30
- http_verb = request.method
31
- content_md5 = request["content-md5"] || ""
32
- content_type = request["content-type"] || ""
33
- date = request["x-amz-date"].nil? ? request["date"] : ""
34
- canonicalized_resource = canonicalized_resource(host, request)
35
- canonicalized_amz_headers = canonicalized_amz_headers(request)
36
27
 
37
- string_to_sign = ""
38
- string_to_sign << http_verb
39
- string_to_sign << "\n"
40
- string_to_sign << content_md5
41
- string_to_sign << "\n"
42
- string_to_sign << content_type
43
- string_to_sign << "\n"
44
- string_to_sign << date
45
- string_to_sign << "\n"
46
- string_to_sign << canonicalized_amz_headers
47
- string_to_sign << canonicalized_resource
28
+ options.merge!(:headers => request,
29
+ :method => request.method,
30
+ :resource => request.path)
48
31
 
49
- digest = OpenSSL::Digest::Digest.new('sha1')
50
- hmac = OpenSSL::HMAC.digest(digest, secret_access_key, string_to_sign)
51
- base64 = Base64.encode64(hmac)
52
- signature = base64.chomp
32
+ signature = canonicalized_signature(options)
53
33
 
54
34
  "AWS #{access_key_id}:#{signature}"
55
35
  end
56
36
 
57
- # Generates temporary URL for given resource
37
+ # Generates temporary URL signature for given resource
58
38
  #
59
39
  # ==== Options
60
40
  # * <tt>:bucket</tt> - Bucket in which the resource resides
61
41
  # * <tt>:resource</tt> - Path to the resouce you want to create
62
- # a teporary link to
42
+ # a temporary link to
63
43
  # * <tt>:secret_access_key</tt> - Secret access key
64
- # * <tt>:expires_on</tt> - Unix time stamp of when the resouce
44
+ # * <tt>:expires_at</tt> - Unix time stamp of when the resouce
65
45
  # link will expire
46
+ # * <tt>:method</tt> - HTTP request method you want to use on
47
+ # the resource, defaults to GET
48
+ # * <tt>:headers</tt> - Any additional HTTP headers you intend
49
+ # to use when requesting the resource
66
50
  def self.generate_temporary_url_signature(options)
67
51
  bucket = options[:bucket]
68
52
  resource = options[:resource]
69
53
  secret_access_key = options[:secret_access_key]
70
54
  expires = options[:expires_at]
71
55
 
72
- string_to_sign = "GET\n\n\n#{expires.to_i.to_s}\n/#{bucket}/#{resource}";
56
+ headers = options[:headers] || {}
57
+ headers.merge!('date' => expires.to_i.to_s)
73
58
 
74
- digest = OpenSSL::Digest::Digest.new("sha1")
75
- hmac = OpenSSL::HMAC.digest(digest, secret_access_key, string_to_sign)
76
- base64 = Base64.encode64(hmac)
77
- signature = base64.chomp
59
+ options.merge!(:resource => "/#{bucket}/#{resource}",
60
+ :method => options[:method] || :get,
61
+ :headers => headers)
62
+ signature = canonicalized_signature(options)
78
63
 
79
64
  CGI.escape(signature)
80
65
  end
81
66
 
67
+ # Generates temporary URL for given resource
68
+ #
69
+ # ==== Options
70
+ # * <tt>:bucket</tt> - Bucket in which the resource resides
71
+ # * <tt>:resource</tt> - Path to the resouce you want to create
72
+ # a temporary link to
73
+ # * <tt>:access_key</tt> - Access key
74
+ # * <tt>:secret_access_key</tt> - Secret access key
75
+ # * <tt>:expires_at</tt> - Unix time stamp of when the resouce
76
+ # link will expire
77
+ # * <tt>:method</tt> - HTTP request method you want to use on
78
+ # the resource, defaults to GET
79
+ # * <tt>:headers</tt> - Any additional HTTP headers you intend
80
+ # to use when requesting the resource
81
+ def self.generate_temporary_url(options)
82
+ bucket = options[:bucket]
83
+ resource = options[:resource]
84
+ access_key = options[:access_key]
85
+ expires = options[:expires_at].to_i
86
+ signature = generate_temporary_url_signature(options)
87
+
88
+ url = "http://#{S3::HOST}/#{bucket}/#{resource}"
89
+ url << "?AWSAccessKeyId=#{access_key}"
90
+ url << "&Expires=#{expires}"
91
+ url << "&Signature=#{signature}"
92
+ end
93
+
82
94
  private
83
95
 
96
+ def self.canonicalized_signature(options)
97
+ headers = options[:headers] || {}
98
+ host = options[:host] || ""
99
+ resource = options[:resource]
100
+ access_key_id = options[:access_key_id]
101
+ secret_access_key = options[:secret_access_key]
102
+
103
+ http_verb = options[:method].to_s.upcase
104
+ content_md5 = headers["content-md5"] || ""
105
+ content_type = headers["content-type"] || ""
106
+ date = headers["x-amz-date"].nil? ? headers["date"] : ""
107
+ canonicalized_resource = canonicalized_resource(host, resource)
108
+ canonicalized_amz_headers = canonicalized_amz_headers(headers)
109
+
110
+ string_to_sign = ""
111
+ string_to_sign << http_verb
112
+ string_to_sign << "\n"
113
+ string_to_sign << content_md5
114
+ string_to_sign << "\n"
115
+ string_to_sign << content_type
116
+ string_to_sign << "\n"
117
+ string_to_sign << date
118
+ string_to_sign << "\n"
119
+ string_to_sign << canonicalized_amz_headers
120
+ string_to_sign << canonicalized_resource
121
+
122
+ digest = OpenSSL::Digest::Digest.new('sha1')
123
+ hmac = OpenSSL::HMAC.digest(digest, secret_access_key, string_to_sign)
124
+ base64 = Base64.encode64(hmac)
125
+ base64.chomp
126
+ end
127
+
84
128
  # Helper method for extracting header fields from Net::HTTPRequest
85
129
  # and preparing them for singing in #generate method
86
130
  #
@@ -157,7 +201,7 @@ module S3
157
201
  #
158
202
  # ==== Returns
159
203
  # String containing extracted canonicalized resource
160
- def self.canonicalized_resource(host, request)
204
+ def self.canonicalized_resource(host, resource)
161
205
  # 1. Start with the empty string ("").
162
206
  string = ""
163
207
 
@@ -172,7 +216,7 @@ module S3
172
216
 
173
217
  # 3. Append the path part of the un-decoded HTTP Request-URI,
174
218
  # up-to but not including the query string.
175
- uri = URI.parse(request.path)
219
+ uri = URI.parse(resource)
176
220
  string << uri.path
177
221
 
178
222
  # 4. If the request addresses a sub-resource, like ?location,
data/lib/s3/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module S3
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.4"
3
3
  end
data/s3.gemspec CHANGED
@@ -9,13 +9,12 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Jakub Kuźma"]
10
10
  s.email = ["qoobaa@gmail.com"]
11
11
  s.homepage = "http://jah.pl/projects/s3.html"
12
- s.summary = "Library for accessing S3 objects and buckets, with command line tool"
12
+ s.summary = "Library for accessing S3 objects and buckets"
13
13
  s.description = "S3 library provides access to Amazon's Simple Storage Service. It supports both: European and US buckets through REST API."
14
14
 
15
15
  s.required_rubygems_version = ">= 1.3.6"
16
16
  s.rubyforge_project = "s3"
17
17
 
18
- s.add_dependency "trollop"
19
18
  s.add_dependency "proxies"
20
19
  s.add_development_dependency "test-unit", ">= 2.0"
21
20
  s.add_development_dependency "mocha"
@@ -140,4 +140,66 @@ class SignatureTest < Test::Unit::TestCase
140
140
  expected = "AWS 0PN5J17HBGZHT7JJ3X82:dxhSBHoI6eVSPcXJqEghlUzZMnY="
141
141
  assert_equal expected, actual
142
142
  end
143
+
144
+ test "temporary signature for object get" do
145
+ actual = S3::Signature.generate_temporary_url_signature(
146
+ :bucket => "johnsmith",
147
+ :resource => "photos/puppy.jpg",
148
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o",
149
+ :expires_at => 1175046589
150
+ )
151
+ expected = "gs6xNznrLJ4Bd%2B1y9pcy2HOSVeg%3D"
152
+ assert_equal expected, actual
153
+ end
154
+
155
+ test "temporary signature for object post" do
156
+ actual = S3::Signature.generate_temporary_url_signature(
157
+ :bucket => "johnsmith",
158
+ :resource => "photos/puppy.jpg",
159
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o",
160
+ :expires_at => 1175046589,
161
+ :method => :post
162
+ )
163
+ expected = "duIzwO2KTEMIlbSYbFFS86Wj0LI%3D"
164
+ assert_equal expected, actual
165
+ end
166
+
167
+ test "temporary signature for object put with headers" do
168
+ actual = S3::Signature.generate_temporary_url_signature(
169
+ :bucket => "johnsmith",
170
+ :resource => "photos/puppy.jpg",
171
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o",
172
+ :expires_at => 1175046589,
173
+ :method => :put,
174
+ :headers => {'x-amz-acl' => 'public-read'}
175
+ )
176
+ expected = "SDMxjIkOKIVR47nWfJ57UNPXxFM%3D"
177
+ assert_equal expected, actual
178
+ end
179
+
180
+ test "temporary signature for object delete" do
181
+ actual = S3::Signature.generate_temporary_url_signature(
182
+ :bucket => "johnsmith",
183
+ :resource => "photos/puppy.jpg",
184
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o",
185
+ :expires_at => 1175046589,
186
+ :method => :delete
187
+ )
188
+ expected = "5Vg7A4HxgS6tVCYzBx%2BkMR8sztY%3D"
189
+ assert_equal expected, actual
190
+ end
191
+
192
+ test "temporary url for object put with headers" do
193
+ actual = S3::Signature.generate_temporary_url(
194
+ :bucket => "johnsmith",
195
+ :resource => "photos/puppy.jpg",
196
+ :access_key => '0PN5J17HBGZHT7JJ3X82',
197
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o",
198
+ :expires_at => 1175046589,
199
+ :method => :put,
200
+ :headers => {'x-amz-acl' => 'public-read'}
201
+ )
202
+ expected = "http://s3.amazonaws.com/johnsmith/photos/puppy.jpg?AWSAccessKeyId=0PN5J17HBGZHT7JJ3X82&Expires=1175046589&Signature=SDMxjIkOKIVR47nWfJ57UNPXxFM%3D"
203
+ assert_equal expected, actual
204
+ end
143
205
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 2
9
- version: 0.3.2
8
+ - 4
9
+ version: 0.3.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Jakub Ku\xC5\xBAma"
@@ -14,11 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-09-06 00:00:00 +02:00
17
+ date: 2010-09-25 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: trollop
21
+ name: proxies
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
@@ -30,23 +30,10 @@ dependencies:
30
30
  version: "0"
31
31
  type: :runtime
32
32
  version_requirements: *id001
33
- - !ruby/object:Gem::Dependency
34
- name: proxies
35
- prerelease: false
36
- requirement: &id002 !ruby/object:Gem::Requirement
37
- none: false
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
- version: "0"
44
- type: :runtime
45
- version_requirements: *id002
46
33
  - !ruby/object:Gem::Dependency
47
34
  name: test-unit
48
35
  prerelease: false
49
- requirement: &id003 !ruby/object:Gem::Requirement
36
+ requirement: &id002 !ruby/object:Gem::Requirement
50
37
  none: false
51
38
  requirements:
52
39
  - - ">="
@@ -56,11 +43,11 @@ dependencies:
56
43
  - 0
57
44
  version: "2.0"
58
45
  type: :development
59
- version_requirements: *id003
46
+ version_requirements: *id002
60
47
  - !ruby/object:Gem::Dependency
61
48
  name: mocha
62
49
  prerelease: false
63
- requirement: &id004 !ruby/object:Gem::Requirement
50
+ requirement: &id003 !ruby/object:Gem::Requirement
64
51
  none: false
65
52
  requirements:
66
53
  - - ">="
@@ -69,11 +56,11 @@ dependencies:
69
56
  - 0
70
57
  version: "0"
71
58
  type: :development
72
- version_requirements: *id004
59
+ version_requirements: *id003
73
60
  - !ruby/object:Gem::Dependency
74
61
  name: bundler
75
62
  prerelease: false
76
- requirement: &id005 !ruby/object:Gem::Requirement
63
+ requirement: &id004 !ruby/object:Gem::Requirement
77
64
  none: false
78
65
  requirements:
79
66
  - - ">="
@@ -84,12 +71,12 @@ dependencies:
84
71
  - 0
85
72
  version: 1.0.0
86
73
  type: :development
87
- version_requirements: *id005
74
+ version_requirements: *id004
88
75
  description: "S3 library provides access to Amazon's Simple Storage Service. It supports both: European and US buckets through REST API."
89
76
  email:
90
77
  - qoobaa@gmail.com
91
- executables:
92
- - s3
78
+ executables: []
79
+
93
80
  extensions: []
94
81
 
95
82
  extra_rdoc_files: []
@@ -101,7 +88,6 @@ files:
101
88
  - LICENSE
102
89
  - README.rdoc
103
90
  - Rakefile
104
- - bin/s3
105
91
  - extra/s3_attachment_fu.rb
106
92
  - extra/s3_paperclip.rb
107
93
  - lib/s3.rb
@@ -155,6 +141,6 @@ rubyforge_project: s3
155
141
  rubygems_version: 1.3.7
156
142
  signing_key:
157
143
  specification_version: 3
158
- summary: Library for accessing S3 objects and buckets, with command line tool
144
+ summary: Library for accessing S3 objects and buckets
159
145
  test_files: []
160
146
 
data/bin/s3 DELETED
@@ -1,187 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
4
-
5
- require "trollop"
6
- require "s3"
7
-
8
- # HELPER METHODS
9
-
10
- include S3
11
-
12
- def list_buckets(service)
13
- service.buckets.each do |bucket|
14
- puts bucket.name
15
- end
16
- end
17
-
18
- def create_bucket(service, name, location)
19
- service.buckets.build(name).save(location)
20
- end
21
-
22
- def destroy_bucket(service, name)
23
- service.buckets.find(name).destroy
24
- end
25
-
26
- def show_bucket(service, name, options = {})
27
- service.buckets.find(name).objects.find_all.each do |object|
28
- puts "#{name}/#{object.key}"
29
- end
30
- end
31
-
32
- def list_objects(service)
33
- service.buckets.each do |bucket|
34
- bucket.objects.each do |object|
35
- puts "#{bucket.name}/#{object.key}"
36
- end
37
- end
38
- end
39
-
40
- def create_object(service, name, file_name, options = {})
41
- bucket_name, object_name = name.split("/", 2)
42
- object = service.buckets.find(bucket_name).objects.build(object_name)
43
- object.content_type = options[:type]
44
- object.content_encoding = options[:encoding]
45
- object.content_disposition = options[:disposition]
46
- object.acl = options[:acl]
47
- object.content = File.new(file_name)
48
- object.save
49
- end
50
-
51
- def destroy_object(service, name)
52
- bucket_name, object_name = name.split("/", 2)
53
- object = service.buckets.find(bucket_name).objects.find(object_name)
54
- object.destroy
55
- end
56
-
57
- def show_object(service, name, file_name = nil)
58
- bucket_name, object_name = name.split("/", 2)
59
- object = service.buckets.find(bucket_name).objects.find_first(object_name)
60
- puts " object: #{object.name}/#{object.key}"
61
- puts " content type: #{object.content_type}"
62
- puts " size: #{object.size}"
63
- puts " etag: #{object.etag}"
64
- puts " last modified: #{object.last_modified}"
65
- if file_name
66
- if file_name == "-"
67
- puts object.content
68
- else
69
- File.open(file_name, "wb") do |file|
70
- file.write(object.content)
71
- end
72
- end
73
- end
74
- end
75
-
76
- # COMMAND LINE PARSER
77
-
78
- ACCESS_KEY_ID = ENV["ACCESS_KEY_ID"]
79
- SECRET_ACCESS_KEY = ENV["SECRET_ACCESS_KEY"]
80
- COMMANDS = %w(bucket object)
81
- BUCKET_SUBCOMMANDS = %w(add remove show)
82
- OBJECT_SUBCOMMANDS = %w(add remove show)
83
-
84
- global_options = Trollop::options do
85
- banner "s3 command line tool"
86
- opt :access_key_id, "Your access key id to AWS", :type => :string, :default => ACCESS_KEY_ID
87
- opt :secret_access_key, "Your secret access key to AWS", :type => :string, :default => SECRET_ACCESS_KEY
88
- opt :debug, "Debug mode", :type => :flag, :default => false
89
- stop_on COMMANDS
90
- end
91
-
92
- Trollop::die "No access key id given" unless global_options[:access_key_id]
93
- Trollop::die "No secret access key given" unless global_options[:secret_access_key]
94
-
95
- service = Service.new(:access_key_id => global_options[:access_key_id],
96
- :secret_access_key => global_options[:secret_access_key],
97
- :debug => global_options[:debug])
98
-
99
- command = ARGV.shift
100
-
101
- begin
102
- case command
103
- when "bucket"
104
- command_options = Trollop::options do
105
- banner "manage buckets"
106
- stop_on BUCKET_SUBCOMMANDS
107
- end
108
- subcommand = ARGV.shift
109
- case subcommand
110
- when "add"
111
- subcommand_options = Trollop::options do
112
- banner "add bucket"
113
- opt :location, "Location of the bucket - EU or US", :default => "US", :type => :string
114
- end
115
- name = ARGV.shift
116
- Trollop::die "Bucket has not been added because of unknown error" unless create_bucket(service, name, subcommand_options[:location])
117
- when "remove"
118
- subcommand_options = Trollop::options do
119
- banner "remove bucket"
120
- end
121
- name = ARGV.shift
122
- Trollop::die "Bucket name must be given" if name.nil? or name.empty?
123
- Trollop::die "Bucket has not been removed because of unknown error" unless destroy_bucket(service, name)
124
- when "show"
125
- subcommand_options = Trollop::options do
126
- banner "show bucket"
127
- opt :prefix, "Limits the response to keys which begin with the indicated prefix", :type => :string
128
- opt :marker, "Indicates where in the bucket to begin listing", :type => :string
129
- opt :max_keys, "The maximum number of keys you'd like to see", :type => :integer
130
- opt :delimiter, "Causes keys that contain the same string between the prefix and the first occurrence of the delimiter to be rolled up into a single result element", :type => :string
131
- end
132
- name = ARGV.shift
133
- Trollop::die "Bucket name must be given" if name.nil? or name.empty?
134
- show_bucket(service, name, subcommand_options)
135
- when nil
136
- list_buckets(service)
137
- else
138
- Trollop::die "Unknown subcommand: #{subcommand.inspect}"
139
- end
140
- when "object"
141
- command_options = Trollop::options do
142
- banner "manage objects"
143
- stop_on OBJECT_SUBCOMMANDS
144
- end
145
- subcommand = ARGV.shift
146
- case subcommand
147
- when "add"
148
- subcommand_options = Trollop::options do
149
- banner "object add s3_object_name local_file_name"
150
- opt :type, "A standard MIME type describing the format of the contents", :default => "binary/octet-stream"
151
- opt :disposition, "Specifies presentational information for the object", :type => :string
152
- opt :encoding, "Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied in order to obtain the media-type referenced by the Content-Type header field", :type => :string
153
- opt :acl, "The canned ACL to apply to the object. Options include private, public-read, public-read-write, and authenticated-read", :type => :string
154
- end
155
- name = ARGV.shift
156
- Trollop::die "No object name given" if name.nil? or name.empty?
157
- file_name = ARGV.shift
158
- Trollop::die "No file name given" if file_name.nil? or file_name.empty?
159
- Trollop::die "Object has not been added because of unknown error" unless create_object(service, name, file_name, subcommand_options)
160
- when "remove"
161
- subcommand_options = Trollop::options do
162
- banner "object remove s3_object_name"
163
- end
164
- name = ARGV.shift
165
- Trollop::die "No object name given" if name.nil? or name.empty?
166
- Trollop::die "Object has not been removed because of unknown error" unless destroy_object(service, name)
167
- when "show"
168
- subcommand_options = Trollop::options do
169
- banner "object show s3_object_name optional_file_name"
170
- end
171
- name = ARGV.shift
172
- Trollop::die "No object name given" if name.nil? or name.empty?
173
- file_name = ARGV.shift
174
- show_object(service, name, file_name)
175
- when nil
176
- list_objects(service)
177
- else
178
- Trollop::die "Unknown subcommand: #{subcommand.inspect}"
179
- end
180
- when nil
181
- Trollop::die "No command given"
182
- else
183
- Trollop::die "Unknown command #{command.inspect}"
184
- end
185
- rescue Error::ResponseError => e
186
- Trollop::die e.message.sub(/\.+\Z/, "")
187
- end