openstack-swift 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "http://gems.locaweb.com.br"
2
2
 
3
3
  # Specify your gem's dependencies in openstack-swift.gemspec
4
4
  gemspec
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ openstack-swift (0.1.0)
5
+
6
+ GEM
7
+ remote: http://gems.locaweb.com.br/
8
+ specs:
9
+ archive-tar-minitar (0.5.2)
10
+ columnize (0.3.4)
11
+ crack (0.1.8)
12
+ diff-lcs (1.1.2)
13
+ httparty (0.7.8)
14
+ crack (= 0.1.8)
15
+ linecache19 (0.5.12)
16
+ ruby_core_source (>= 0.1.4)
17
+ rspec (2.6.0)
18
+ rspec-core (~> 2.6.0)
19
+ rspec-expectations (~> 2.6.0)
20
+ rspec-mocks (~> 2.6.0)
21
+ rspec-core (2.6.4)
22
+ rspec-expectations (2.6.0)
23
+ diff-lcs (~> 1.1.2)
24
+ rspec-mocks (2.6.0)
25
+ ruby-debug-base19 (0.11.25)
26
+ columnize (>= 0.3.1)
27
+ linecache19 (>= 0.5.11)
28
+ ruby_core_source (>= 0.1.4)
29
+ ruby-debug19 (0.11.6)
30
+ columnize (>= 0.3.1)
31
+ linecache19 (>= 0.5.11)
32
+ ruby-debug-base19 (>= 0.11.19)
33
+ ruby_core_source (0.1.5)
34
+ archive-tar-minitar (>= 0.5.2)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ httparty
41
+ openstack-swift!
42
+ rspec (~> 2.6)
43
+ ruby-debug19
@@ -0,0 +1,4 @@
1
+ :swift:
2
+ :url: "https://sw:8080/auth/v1.0"
3
+ :user: "system:root"
4
+ :pass: "testpass"
@@ -1,5 +1,41 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require "httparty"
3
+ require "net/http"
4
+ require "net/https"
5
+ require "fileutils"
6
+ require "openstack-swift/api"
7
+ require "openstack-swift/errors"
8
+ require "openstack-swift/client"
9
+ require "openstack-swift/swift_config"
10
+
1
11
  module Openstack
2
12
  module Swift
3
- # Your code goes here...
13
+ end
14
+ end
15
+
16
+ module Net
17
+ class HTTPGenericRequest
18
+ private
19
+ def send_request_with_body_stream(sock, ver, path, f)
20
+ unless content_length() or chunked?
21
+ raise ArgumentError,
22
+ "Content-Length not given and Transfer-Encoding is not `chunked'"
23
+ end
24
+ supply_default_content_type
25
+ write_header sock, ver, path
26
+ if chunked?
27
+ while s = f.read(1024)
28
+ sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
29
+ end
30
+ sock.write "0\r\n\r\n"
31
+ else
32
+ bytes_written = 0
33
+ buffer=1024
34
+ while (s = f.read(buffer)) && bytes_written < content_length()
35
+ sock.write s
36
+ bytes_written += buffer
37
+ end
38
+ end
39
+ end
4
40
  end
5
41
  end
@@ -0,0 +1,147 @@
1
+ # -*- coding: UTF-8 -*-
2
+ module Openstack
3
+ module Swift
4
+ module Api
5
+ extend self
6
+
7
+ # Authentication method to get the url and token to conect to swift
8
+ # Returns:
9
+ # x-storage-url
10
+ # x-storage-token
11
+ # x-auth-token
12
+ def auth(proxy, user, password)
13
+ res = HTTParty.get(proxy, :headers => {"X-Auth-User" => user, "X-Auth-Key" => password})
14
+ raise AuthenticationError unless res.code == 200
15
+
16
+ [res.headers["x-storage-url"],res.headers["x-storage-token"],res.headers["x-auth-token"]]
17
+ end
18
+
19
+ # Get informations about the currect account used to connect to swift
20
+ # Returns:
21
+ # x-account-bytes-used
22
+ # x-account-object-count
23
+ # x-account-container-count
24
+ def account(url, token)
25
+ query = {:format => "json"}
26
+ HTTParty.head(url, :headers => {"X-Auth-Token"=> token}, :query => query).headers
27
+ end
28
+
29
+ # List containers
30
+ # Note that swift only returns 1000 items, so to list more than this
31
+ # you should use the marker option as the name of the last returned item (1000th item)
32
+ # to return the next sequency (1001 - 2000)
33
+ # query options: marker, prefix, limit
34
+ def containers(url, token, query = {})
35
+ query = query.merge(:format => "json")
36
+ res = HTTParty.get(url, :headers => {"X-Auth-Token"=> token}, :query => query)
37
+ res.to_a
38
+ end
39
+
40
+ # Get all objects for a given container
41
+ # Query options:
42
+ # marker
43
+ # prefix
44
+ # limit
45
+ # delimiter
46
+ def objects(url, token, container, query = {})
47
+ query = query.merge(:format => "json")
48
+ res = HTTParty.get("#{url}/#{container}", :headers => {"X-Auth-Token"=> token}, :query => query)
49
+ res.to_a
50
+ end
51
+
52
+ # Delete a container for a given name from swift
53
+ def delete_container(url, token, container)
54
+ res = HTTParty.delete("#{url}/#{container}", :headers => {"X-Auth-Token"=> token})
55
+ raise "Could not delete container '#{container}'" if res.code < 200 or res.code >= 300
56
+ true
57
+ end
58
+
59
+ # Create a container on swift from a given name
60
+ def create_container(url, token, container)
61
+ res = HTTParty.put("#{url}/#{container}", :headers => {"X-Auth-Token"=> token})
62
+ raise "Could not create container '#{container}'" if res.code < 200 or res.code >= 300
63
+ true
64
+ end
65
+
66
+ # Get the object stat given the object name and the container this object is in
67
+ def object_stat(url, token, container, object)
68
+ url = "#{url}/#{container}/#{object}"
69
+ query = {:format => "json"}
70
+ HTTParty.head(url, :headers => {"X-Auth-Token"=> token}, :query => query).headers
71
+ end
72
+
73
+ # Creates the manifest file for a splitted upload
74
+ # Given the container and file path a manifest is created to guide the downloads of this
75
+ # splitted file
76
+ def create_manifest(url, token, container, file_path)
77
+ file_name = file_path.match(/.+\/(.+?)$/)[1]
78
+ file_size = File.size(file_path)
79
+ file_mtime = File.mtime(file_path).to_f.round(2)
80
+ manifest_path = "#{container}_segments/#{file_name}/#{file_mtime}/#{file_size}/"
81
+
82
+ res = HTTParty.put("#{url}/#{container}/#{file_name}", :headers => {
83
+ "X-Auth-Token" => token,
84
+ "x-object-manifest" => manifest_path,
85
+ "Content-Type" => "application/octet-stream",
86
+ "Content-Length" => "0"
87
+ })
88
+
89
+ raise "Could not create manifest for '#{file_path}'" if res.code < 200 or res.code >= 300
90
+ true
91
+ end
92
+
93
+ # Downloads an object (file) to disk and returns the saved file path
94
+ def download_object(url, token, container, object, file_name=nil)
95
+ file_name ||= "/tmp/swift/#{container}/#{object}"
96
+
97
+ # creating directory if it doesn't exist
98
+ FileUtils.mkdir_p(file_name.match(/(.+)\/.+?$/)[1])
99
+ file = File.open(file_name, "wb")
100
+ uri = URI.parse("#{url}/#{container}/#{object}")
101
+
102
+ req = Net::HTTP::Get.new(uri.path)
103
+ req.add_field("X-Auth-Token", token)
104
+
105
+ http = Net::HTTP.new(uri.host, uri.port)
106
+ http.use_ssl = true
107
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
108
+ md5 = Digest::MD5.new
109
+
110
+ http.request(req) do |res|
111
+ res.read_body do |chunk|
112
+ file.write chunk
113
+ md5.update(chunk)
114
+ end
115
+
116
+ raise "MD5 checksum failed for #{container}/#{object}" if res["x-object-manifest"].nil? && res["etag"] != md5.hexdigest
117
+ end
118
+
119
+ file_name
120
+ ensure
121
+ file.close rescue nil
122
+ end
123
+
124
+ # Uploads a given object to a given container
125
+ def upload_object(url, token, container, file_path, options={})
126
+ options[:object_name] ||= file_path.match(/.+\/(.+?)$/)[1]
127
+ file = File.open(file_path, "rb")
128
+
129
+ file.seek(options[:position]) if options[:position]
130
+ uri = URI.parse("#{url}/#{container}/#{options[:object_name]}")
131
+
132
+ req = Net::HTTP::Put.new(uri.path)
133
+ req.add_field("X-Auth-Token", token)
134
+ req.body_stream = file
135
+ req.content_length = options[:size] || File.size(file_path)
136
+ req.content_type = "application/octet-stream"
137
+
138
+ http = Net::HTTP.new(uri.host, uri.port)
139
+ http.use_ssl = true
140
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
141
+ http.request(req)
142
+ ensure
143
+ file.close rescue nil
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,121 @@
1
+ # -*- coding: UTF-8 -*-
2
+ module Openstack
3
+ module Swift
4
+ class Client
5
+ SWIFT_API = Openstack::Swift::Api
6
+ MAX_SIZE = 4 * 1024 ** 3
7
+
8
+ # Initialize method
9
+ # It uses the authenticate method to store the tokens for future requests
10
+ def initialize(proxy, user, password)
11
+ @proxy, @user, @password = proxy, user, password
12
+ authenticate!
13
+ end
14
+
15
+ # Authentication method
16
+ # It stores the authentication url and token for future commands
17
+ # avoiding to request a new token for each request
18
+ # It should be used to force a new token
19
+ def authenticate!
20
+ @url, _, @token = SWIFT_API.auth(@proxy, @user, @password)
21
+
22
+ if @url.blank? or @token.blank?
23
+ raise AuthenticationError
24
+ else
25
+ true
26
+ end
27
+ end
28
+
29
+ # Returns the following informations about the object:
30
+ # bytes_used: Number of bytes used by this account
31
+ # object_count: Number of objects that this account have allocated
32
+ # container_count: Number of container
33
+ def account_info
34
+ headers = SWIFT_API.account(@url, @token)
35
+ {
36
+ "bytes_used" => headers["x-account-bytes-used"],
37
+ "object_count" => headers["x-account-object-count"],
38
+ "container_count" => headers["x-account-container-count"]
39
+ }
40
+ end
41
+
42
+ # Returns the following informations about the account:
43
+ # last_modified
44
+ # md5
45
+ # content_type
46
+ # manifest
47
+ # content_length
48
+ def object_info(container, object)
49
+ headers = SWIFT_API.object_stat(@url, @token, container, object)
50
+ {
51
+ "last_modified" => headers["last-modified"],
52
+ "md5" => headers["etag"],
53
+ "content_type" => headers["content-type"],
54
+ "manifest" => headers["x-object-manifest"],
55
+ "content_length" => headers["content-length"]
56
+ }
57
+ end
58
+
59
+ # This method uploads a file from a given to a given container
60
+ def upload(container, file_path, options={})
61
+ options[:segments_size] ||= MAX_SIZE
62
+
63
+ SWIFT_API.create_container(@url, @token, container) rescue nil
64
+
65
+ file_name, file_mtime, file_size = file_info(file_path)
66
+
67
+ if file_size > options[:segments_size]
68
+ SWIFT_API.create_container(@url, @token, "#{container}_segments") rescue nil
69
+
70
+ segments_minus_one = file_size / options[:segments_size]
71
+ last_piece = file_size - segments_minus_one * options[:segments_size]
72
+ segments_minus_one.times do |segment|
73
+ upload_path_for(file_path, segment)
74
+ SWIFT_API.upload_object(
75
+ @url, @token, "#{container}_segments", file_path,
76
+ :size => options[:segments_size],
77
+ :position => options[:segments_size] * segment,
78
+ :object_name => segment_path
79
+ )
80
+ end
81
+
82
+ SWIFT_API.upload_object(
83
+ @url, @token, "#{container}_segments", file_path,
84
+ :size => last_piece,
85
+ :position => options[:segments_size] * segments_minus_one,
86
+ :object_name => upload_path_for(file_path, segments_minus_one)
87
+ )
88
+
89
+ SWIFT_API.create_manifest(@url, @token, container, file_path)
90
+ else
91
+ SWIFT_API.upload_object(@url, @token, container, file_path)
92
+ end
93
+ end
94
+
95
+ # This method downloads a object from a given container
96
+ def download(container, object)
97
+ SWIFT_API.download_object(@url, @token, container, object)
98
+ end
99
+
100
+ private
101
+
102
+ # Returns the standard swift path for a given file path and segment
103
+ def upload_path_for(file_path, segment)
104
+ "%s/%s/s/%08d" % (file_info(file_path) << segment)
105
+ end
106
+
107
+ # Get relevant informations about a file
108
+ # Returns an array with:
109
+ # file_name
110
+ # file_mtime
111
+ # file_size
112
+ def file_info(file_path)
113
+ [
114
+ file_path.match(/.+\/(.+?)$/)[1],
115
+ File.mtime(file_path).to_f.round(2),
116
+ File.size(file_path)
117
+ ]
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: UTF-8 -*-
2
+ module Openstack::Swift
3
+ class AuthenticationError < Exception; end
4
+ end
@@ -0,0 +1,19 @@
1
+ # -*- coding: UTF-8 -*-
2
+ module Openstack
3
+ module SwiftConfig
4
+ extend self
5
+
6
+ def [](name)
7
+ configs[name]
8
+ end
9
+
10
+ module_function
11
+ def configs
12
+ @config_file ||= load_file
13
+ end
14
+
15
+ def load_file
16
+ YAML.load_file(File.expand_path(File.dirname(__FILE__)) + "/../../config/swift.yml")[:swift]
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,6 @@
1
+ # -*- coding: UTF-8 -*-
1
2
  module Openstack
2
3
  module Swift
3
- VERSION = "0.0.1"
4
+ VERSION = "0.1.0"
4
5
  end
5
6
  end
@@ -8,14 +8,16 @@ Gem::Specification.new do |s|
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["morellon", "pothix"]
10
10
  s.email = ["morellon@gmail.com", "pothix@pothix.com"]
11
- s.homepage = ""
12
- s.summary = %q{Openstack's swift client}
11
+ s.homepage = "http://github.com/morellon/openstack-swift"
13
12
  s.description = %q{Openstack's swift client}
13
+ s.summary = s.description
14
14
 
15
15
  s.rubyforge_project = "openstack-swift"
16
16
 
17
- s.files = `git ls-files`.split("\n")
18
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.files = Dir["./**/*"].reject {|file| file =~ /\.git|pkg/}
20
18
  s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "rspec", "~> 2.6"
21
+ s.add_development_dependency "httparty"
22
+ s.add_development_dependency "ruby-debug19"
21
23
  end
@@ -0,0 +1,47 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require "spec_helper"
3
+
4
+ describe "Openstack::Swift::Client" do
5
+ let!(:swift_dummy_file) do
6
+ file_path = "/tmp/swift-dummy"
7
+ File.open(file_path, "w") {|f| f.puts("testfile "*1000)}
8
+ file_path
9
+ end
10
+
11
+ context "when authenticating" do
12
+ it "should return authentication error if one of the parameters is incorrect" do
13
+ expect {
14
+ Openstack::Swift::Client.new("http://incorrect.com/swift", Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass])
15
+ }.to raise_error(Openstack::Swift::AuthenticationError)
16
+ end
17
+
18
+ it "shoud not need to authenticate again" do
19
+ client = Openstack::Swift::Client.new(Openstack::SwiftConfig[:url], Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass])
20
+ Openstack::Swift::Api.should_not_receive(:auth)
21
+ client.account_info
22
+ end
23
+ end
24
+
25
+ context "when authenticated" do
26
+ subject { Openstack::Swift::Client.new(Openstack::SwiftConfig[:url], Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass]) }
27
+
28
+ it "should upload a splitted file and create its manifest" do
29
+ pending "WTF...Not working for a unknown reason"
30
+ subject.upload("pothix", swift_dummy_file, {:segments_size => 1024*2})
31
+ subject.object_info("pothix", "swifty-dummy")["manifest"].should_not be_nil
32
+ end
33
+
34
+ it "should download an splitted file" do
35
+ content_length = subject.object_info("morellon", "splitted_file")["content_length"].to_i
36
+ file_path = subject.download("morellon", "splitted_file")
37
+ File.size(file_path).should == content_length
38
+ end
39
+
40
+ it "should return account's details" do
41
+ account_info = subject.account_info
42
+ account_info.should have_key("bytes_used")
43
+ account_info.should have_key("object_count")
44
+ account_info.should have_key("container_count")
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,99 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require "spec_helper"
3
+
4
+ describe Openstack::Swift::Api do
5
+ context "when authenticating" do
6
+ it "should authenticate on swift" do
7
+ expect {
8
+ subject.auth(Openstack::SwiftConfig[:url], Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass])
9
+ }.to_not raise_error Openstack::Swift::AuthenticationError
10
+ end
11
+
12
+ it "should raise error for a invalid url" do
13
+ expect {
14
+ subject.auth("http://pothix.com/swift", Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass])
15
+ }.to raise_error Openstack::Swift::AuthenticationError
16
+ end
17
+
18
+ it "should raise error for a invalid pass" do
19
+ expect {
20
+ subject.auth(Openstack::SwiftConfig[:url], Openstack::SwiftConfig[:user], "invalidpassword")
21
+ }.to raise_error Openstack::Swift::AuthenticationError
22
+ end
23
+
24
+ it "should raise error for a invalid user" do
25
+ expect {
26
+ subject.auth(Openstack::SwiftConfig[:url], "system:weirduser", Openstack::SwiftConfig[:pass])
27
+ }.to raise_error Openstack::Swift::AuthenticationError
28
+ end
29
+
30
+ it "should return storage-url, storage-token and auth-token" do
31
+ subject.auth(Openstack::SwiftConfig[:url], Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass]).should have(3).items
32
+ end
33
+ end
34
+
35
+ context "when authenticated" do
36
+ let!(:swift_dummy_file){ File.open("/tmp/swift-dummy", "w") {|f| f.puts("test file"*1000)} }
37
+
38
+ before do
39
+ @url, _, @token = subject.auth(
40
+ Openstack::SwiftConfig[:url],
41
+ Openstack::SwiftConfig[:user],
42
+ Openstack::SwiftConfig[:pass]
43
+ )
44
+ end
45
+
46
+ it "should return account's headers" do
47
+ account = subject.account(@url, @token)
48
+ account.should have_key("x-account-bytes-used")
49
+ account.should have_key("x-account-object-count")
50
+ account.should have_key("x-account-container-count")
51
+ end
52
+
53
+ it "should return a list of containers" do
54
+ subject.containers(@url, @token).should be_a(Array)
55
+ end
56
+
57
+ it "should return a list of objects" do
58
+ subject.objects(@url, @token, "morellon", :delimiter => "/").should be_a(Array)
59
+ end
60
+
61
+ it "should download an object" do
62
+ subject.download_object(@url, @token, "morellon", "Gemfile").should == "/tmp/swift/morellon/Gemfile"
63
+ end
64
+
65
+ it "should upload an object" do
66
+ subject.upload_object(@url, @token, "morellon", "/tmp/swift-dummy").code.should == "201"
67
+ end
68
+
69
+ it "should create a new container" do
70
+ subject.create_container(@url, @token, "pothix_container").should be_true
71
+ end
72
+
73
+ context "when excluding a container" do
74
+ before { @container = "pothix_container" }
75
+
76
+ it "should delete a existent container" do
77
+ subject.create_container(@url, @token, @container).should be_true
78
+ subject.delete_container(@url, @token, @container).should be_true
79
+ end
80
+
81
+ it "should raise an error when the container doesn't exist" do
82
+ expect {
83
+ subject.delete_container(@url, @token, @container).should be_true
84
+ subject.delete_container(@url, @token, @container).should be_true
85
+ }.to raise_error("Could not delete container '#{@container}'")
86
+ end
87
+ end
88
+
89
+ it "should get the file stat" do
90
+ subject.upload_object(@url, @token, "morellon", "/tmp/swift-dummy")
91
+ headers = subject.object_stat(@url, @token, "morellon", "swift-dummy")
92
+
93
+ headers["last-modified"].should_not be_blank
94
+ headers["etag"].should_not be_blank
95
+ headers["content-type"].should_not be_blank
96
+ headers["date"].should_not be_blank
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: UTF-8 -*-
2
+ require "rubygems"
3
+ require "bundler/setup"
4
+
5
+ require "openstack-swift"
6
+
7
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|file| require file}
8
+
9
+ # Using a diferent YAML engine on test environment
10
+ YAML::ENGINE::yamler = "syck"
11
+
12
+ RSpec.configure do |config|
13
+ end
metadata CHANGED
@@ -1,64 +1,96 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: openstack-swift
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
4
5
  prerelease:
5
- version: 0.0.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - morellon
9
9
  - pothix
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
-
14
- date: 2011-08-10 00:00:00 -03:00
13
+ date: 2011-08-22 00:00:00.000000000 -03:00
15
14
  default_executable:
16
- dependencies: []
17
-
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ requirement: &10022160 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: '2.6'
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: *10022160
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: &10021760 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *10021760
38
+ - !ruby/object:Gem::Dependency
39
+ name: ruby-debug19
40
+ requirement: &10021280 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *10021280
18
49
  description: Openstack's swift client
19
- email:
50
+ email:
20
51
  - morellon@gmail.com
21
52
  - pothix@pothix.com
22
53
  executables: []
23
-
24
54
  extensions: []
25
-
26
55
  extra_rdoc_files: []
27
-
28
- files:
29
- - .gitignore
30
- - Gemfile
31
- - Rakefile
32
- - lib/openstack-swift.rb
33
- - lib/openstack-swift/version.rb
34
- - openstack-swift.gemspec
56
+ files:
57
+ - ./Gemfile.lock
58
+ - ./config/swift.yml
59
+ - ./Rakefile
60
+ - ./lib/openstack-swift.rb
61
+ - ./lib/openstack-swift/swift_config.rb
62
+ - ./lib/openstack-swift/errors.rb
63
+ - ./lib/openstack-swift/api.rb
64
+ - ./lib/openstack-swift/client.rb
65
+ - ./lib/openstack-swift/version.rb
66
+ - ./Gemfile
67
+ - ./openstack-swift.gemspec
68
+ - ./spec/openstack-swift/client_spec.rb
69
+ - ./spec/openstack-swift/web_api_spec.rb
70
+ - ./spec/spec_helper.rb
35
71
  has_rdoc: true
36
- homepage: ""
72
+ homepage: http://github.com/morellon/openstack-swift
37
73
  licenses: []
38
-
39
74
  post_install_message:
40
75
  rdoc_options: []
41
-
42
- require_paths:
76
+ require_paths:
43
77
  - lib
44
- required_ruby_version: !ruby/object:Gem::Requirement
78
+ required_ruby_version: !ruby/object:Gem::Requirement
45
79
  none: false
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: "0"
50
- required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
85
  none: false
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: "0"
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
56
90
  requirements: []
57
-
58
91
  rubyforge_project: openstack-swift
59
92
  rubygems_version: 1.6.2
60
93
  signing_key:
61
94
  specification_version: 3
62
95
  summary: Openstack's swift client
63
96
  test_files: []
64
-
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*