strongspace 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/bin/strongspace ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'strongspace'
7
+ require 'strongspace/command'
8
+
9
+ args = ARGV.dup
10
+ ARGV.clear
11
+ command = args.shift.strip rescue 'help'
12
+
13
+ Strongspace::Command.run(command, args)
14
+
@@ -0,0 +1,136 @@
1
+ require 'rest_client'
2
+ require 'uri'
3
+ require 'strongspace/version'
4
+ require 'json/pure' unless {}.respond_to?(:to_json)
5
+
6
+ # A Ruby class to call the Strongspace REST API. You might use this if you want to
7
+ # manage your Strongspace apps from within a Ruby program, such as Capistrano.
8
+ #
9
+ # Example:
10
+ #
11
+ # require 'strongspace'
12
+ # strongspace = Strongspace::Client.new('me@example.com', 'mypass')
13
+ #
14
+ class Strongspace::Client
15
+ def self.version
16
+ Strongspace::VERSION
17
+ end
18
+
19
+ def self.gem_version_string
20
+ "strongspace-gem/#{version}"
21
+ end
22
+
23
+ attr_accessor :host, :user, :password
24
+
25
+ def self.auth(user, password, host='https://www.strongspace.com')
26
+ client = new(user, password, host)
27
+ JSON.parse client.get('/api/v1/api_token', :username => user, :password => password).to_s
28
+ end
29
+
30
+ def username
31
+ self.user.split("/")[0]
32
+ end
33
+
34
+ def initialize(user, password, host='https://www.strongspace.com')
35
+ @user = user
36
+ @password = password
37
+ @host = host
38
+ end
39
+
40
+ def spaces
41
+ doc = JSON.parse get('/api/v1/spaces')
42
+ end
43
+
44
+ def destroy_space(space_name)
45
+ doc = JSON.parse delete("/api/v1/spaces/#{escape(space_name)}").to_s
46
+ end
47
+
48
+ def create_space(name, type='normal')
49
+ doc = JSON.parse post("/api/v1/spaces", :name => name, :type => type)
50
+ end
51
+
52
+ def get_space(space_name)
53
+ doc = JSON.parse get("/api/v1/spaces/#{escape(space_name)}")
54
+ end
55
+
56
+ def snapshots(space_name)
57
+ doc = JSON.parse get("/api/v1/spaces/#{escape(space_name)}/snapshots").to_s
58
+ end
59
+
60
+ def destroy_snapshot(space_name, snapshot_name)
61
+ doc = JSON.parse delete("/api/v1/spaces/#{escape(space_name)}/snapshots/#{escape(snapshot_name)}").to_s
62
+ end
63
+
64
+ def create_snapshot(space_name, snapshot_name)
65
+ doc = JSON.parse post("/api/v1/spaces/#{escape(space_name)}/snapshots", :name => snapshot_name)
66
+ end
67
+
68
+
69
+ # Get the list of ssh public keys for the current user.
70
+ def keys
71
+ doc = JSON.parse get('/api/v1/ssh_keys')
72
+ end
73
+
74
+ # Add an ssh public key to the current user.
75
+ def add_key(key)
76
+ post("/api/v1/ssh_keys", :key => key).to_s
77
+ end
78
+
79
+ # Remove an existing ssh public key from the current user.
80
+ def remove_key(key_id)
81
+ delete("/api/v1/ssh_keys/#{key_id}").to_s
82
+ end
83
+
84
+ # Clear all keys on the current user.
85
+ def remove_all_keys
86
+ delete("/api/v1/ssh_keys").to_s
87
+ end
88
+
89
+ ##################
90
+
91
+ def resource(uri)
92
+ RestClient.proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
93
+ if uri =~ /^https?/
94
+ RestClient::Resource.new(uri, user, password)
95
+ elsif host =~ /^https?/
96
+ RestClient::Resource.new(host, user, password)[uri]
97
+ end
98
+ end
99
+
100
+ def get(uri, extra_headers={}) # :nodoc:
101
+ process(:get, uri, extra_headers)
102
+ end
103
+
104
+ def post(uri, payload="", extra_headers={}) # :nodoc:
105
+ process(:post, uri, extra_headers, payload)
106
+ end
107
+
108
+ def put(uri, payload, extra_headers={}) # :nodoc:
109
+ process(:put, uri, extra_headers, payload)
110
+ end
111
+
112
+ def delete(uri, extra_headers={}) # :nodoc:
113
+ process(:delete, uri, extra_headers)
114
+ end
115
+
116
+ def process(method, uri, extra_headers={}, payload=nil)
117
+ headers = strongspace_headers.merge(extra_headers)
118
+ args = [method, payload, headers].compact
119
+ response = resource(uri).send(*args)
120
+ end
121
+
122
+ def escape(value) # :nodoc:
123
+ escaped = URI.escape(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
124
+ escaped.gsub('.', '%2E') # not covered by the previous URI.escape
125
+ end
126
+
127
+ def strongspace_headers # :nodoc:
128
+ {
129
+ 'X-Strongspace-API-Version' => '1',
130
+ 'User-Agent' => self.class.gem_version_string,
131
+ 'X-Ruby-Version' => RUBY_VERSION,
132
+ 'X-Ruby-Platform' => RUBY_PLATFORM
133
+ }
134
+ end
135
+
136
+ end
@@ -0,0 +1,85 @@
1
+ require 'strongspace/helpers'
2
+ require 'strongspace/commands/base'
3
+
4
+ Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
5
+
6
+ module Strongspace
7
+ module Command
8
+ class InvalidCommand < RuntimeError; end
9
+ class CommandFailed < RuntimeError; end
10
+
11
+ extend Strongspace::Helpers
12
+
13
+ class << self
14
+
15
+ def run(command, args, retries=0)
16
+ begin
17
+ run_internal 'auth:reauthorize', args.dup if retries > 0
18
+ run_internal(command, args.dup)
19
+ rescue InvalidCommand
20
+ error "Unknown command. Run 'strongspace help' for usage information."
21
+ rescue RestClient::Unauthorized
22
+ if retries < 3
23
+ STDERR.puts "Authentication failure"
24
+ run(command, args, retries+1)
25
+ else
26
+ error "Authentication failure"
27
+ end
28
+ rescue RestClient::ResourceNotFound => e
29
+ error extract_not_found(e.http_body)
30
+ rescue RestClient::RequestFailed => e
31
+ error extract_error(e.http_body) unless e.http_code == 402
32
+ rescue RestClient::RequestTimeout
33
+ error "API request timed out. Please try again, or contact support@strongspace.com if this issue persists."
34
+ rescue CommandFailed => e
35
+ error e.message
36
+ rescue Interrupt => e
37
+ error "\n[canceled]"
38
+ end
39
+ end
40
+
41
+ def run_internal(command, args, strongspace=nil)
42
+ klass, method = parse(command)
43
+ runner = klass.new(args, strongspace)
44
+ raise InvalidCommand unless runner.respond_to?(method)
45
+ runner.send(method)
46
+ end
47
+
48
+ def parse(command)
49
+ parts = command.split(':')
50
+ case parts.size
51
+ when 1
52
+ begin
53
+ return eval("Strongspace::Command::#{command.capitalize}"), :index
54
+ rescue NameError, NoMethodError
55
+ return Strongspace::Command::App, command.to_sym
56
+ end
57
+ else
58
+ begin
59
+ const = Strongspace::Command
60
+ command = parts.pop
61
+ parts.each { |part| const = const.const_get(part.capitalize) }
62
+ return const, command.to_sym
63
+ rescue NameError
64
+ raise InvalidCommand
65
+ end
66
+ end
67
+ end
68
+
69
+ def extract_not_found(body)
70
+ body =~ /^[\w\s]+ not found$/ ? body : "Resource not found"
71
+ end
72
+
73
+ def extract_error(body)
74
+ msg = parse_error_json(body) || 'Internal server error'
75
+ msg.split("\n").map { |line| ' ! ' + line }.join("\n")
76
+ end
77
+
78
+ def parse_error_json(body)
79
+ json = JSON.parse(body.to_s)
80
+ json['status']
81
+ rescue JSON::ParserError
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,143 @@
1
+ module Strongspace::Command
2
+ class Auth < Base
3
+ attr_accessor :credentials
4
+
5
+ def client
6
+ @client ||= init_strongspace
7
+ end
8
+
9
+ def init_strongspace
10
+ client = Strongspace::Client.new(user, password, host)
11
+ client
12
+ end
13
+
14
+ # just a stub; will raise if not authenticated
15
+ def check
16
+ client.spaces
17
+ end
18
+
19
+ def host
20
+ ENV['STRONGSPACE_HOST'] || 'https://www.strongspace.com'
21
+ end
22
+
23
+ def reauthorize
24
+ @credentials = ask_for_credentials
25
+ write_credentials
26
+ end
27
+
28
+ def user # :nodoc:
29
+ get_credentials
30
+ @credentials[0]
31
+ end
32
+
33
+ def password # :nodoc:
34
+ get_credentials
35
+ @credentials[1]
36
+ end
37
+
38
+ def credentials_file
39
+ "#{home_directory}/.strongspace/credentials"
40
+ end
41
+
42
+ def get_credentials # :nodoc:
43
+ return if @credentials
44
+ unless @credentials = read_credentials
45
+ @credentials = ask_for_credentials
46
+ save_credentials
47
+ end
48
+ @credentials
49
+ end
50
+
51
+ def read_credentials
52
+ File.exists?(credentials_file) and File.read(credentials_file).split("\n")
53
+ end
54
+
55
+ def echo_off
56
+ system "stty -echo"
57
+ end
58
+
59
+ def echo_on
60
+ system "stty echo"
61
+ end
62
+
63
+ def ask_for_credentials
64
+ puts "Enter your Strongspace credentials."
65
+
66
+ print "Username or Email: "
67
+ user = ask
68
+
69
+ print "Password: "
70
+ password = running_on_windows? ? ask_for_password_on_windows : ask_for_password
71
+
72
+ ["#{user}/token", Strongspace::Client.auth(user, password, host)['api_token']]
73
+ end
74
+
75
+ def ask_for_password_on_windows
76
+ require "Win32API"
77
+ char = nil
78
+ password = ''
79
+
80
+ while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do
81
+ break if char == 10 || char == 13 # received carriage return or newline
82
+ if char == 127 || char == 8 # backspace and delete
83
+ password.slice!(-1, 1)
84
+ else
85
+ # windows might throw a -1 at us so make sure to handle RangeError
86
+ (password << char.chr) rescue RangeError
87
+ end
88
+ end
89
+ puts
90
+ return password
91
+ end
92
+
93
+ def ask_for_password
94
+ echo_off
95
+ password = ask
96
+ puts
97
+ echo_on
98
+ return password
99
+ end
100
+
101
+ def save_credentials
102
+ begin
103
+ write_credentials
104
+ command = 'auth:check'
105
+ Strongspace::Command.run_internal(command, args)
106
+ rescue RestClient::Unauthorized => e
107
+ delete_credentials
108
+ raise e unless retry_login?
109
+
110
+ display "\nAuthentication failed"
111
+ @credentials = ask_for_credentials
112
+ @client = init_strongspace
113
+ retry
114
+ rescue Exception => e
115
+ delete_credentials
116
+ raise e
117
+ end
118
+ end
119
+
120
+ def retry_login?
121
+ @login_attempts ||= 0
122
+ @login_attempts += 1
123
+ @login_attempts < 3
124
+ end
125
+
126
+ def write_credentials
127
+ FileUtils.mkdir_p(File.dirname(credentials_file))
128
+ File.open(credentials_file, 'w') do |f|
129
+ f.puts self.credentials
130
+ end
131
+ set_credentials_permissions
132
+ end
133
+
134
+ def set_credentials_permissions
135
+ FileUtils.chmod 0700, File.dirname(credentials_file)
136
+ FileUtils.chmod 0600, credentials_file
137
+ end
138
+
139
+ def delete_credentials
140
+ FileUtils.rm_f(credentials_file)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,16 @@
1
+ module Strongspace::Command
2
+ class Base
3
+ include Strongspace::Helpers
4
+ attr_accessor :args
5
+ def initialize(args, strongspace=nil)
6
+ @args = args
7
+ @strongspace = strongspace
8
+ end
9
+
10
+ def strongspace
11
+ @strongspace ||= Strongspace::Command.run_internal('auth:client', args)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,84 @@
1
+ module Strongspace::Command
2
+ class Help < Base
3
+ class HelpGroup < Array
4
+ attr_reader :title
5
+
6
+ def initialize(title)
7
+ @title = title
8
+ end
9
+
10
+ def command(name, description)
11
+ self << [name, description]
12
+ end
13
+
14
+ def space
15
+ self << ['', '']
16
+ end
17
+ end
18
+
19
+ def self.groups
20
+ @groups ||= []
21
+ end
22
+
23
+ def self.group(title, &block)
24
+ groups << begin
25
+ group = HelpGroup.new(title)
26
+ yield group
27
+ group
28
+ end
29
+ end
30
+
31
+ def self.create_default_groups!
32
+ group 'General Commands' do |group|
33
+ group.command 'help', 'show this usage'
34
+ group.command 'version', 'show the gem version'
35
+ group.space
36
+ group.space
37
+ group.command 'keys', 'show your user\'s public keys'
38
+ group.command 'keys:add [<path to keyfile>]', 'add a public key'
39
+ group.command 'keys:remove <id> ', 'remove a key by id'
40
+ group.command 'keys:clear', 'remove all keys'
41
+ group.space
42
+ group.space
43
+ group.command 'spaces', 'show your user\'s spaces'
44
+ group.command 'spaces:create <space_name> [type]', 'add a new space. type => (normal,public,backup)'
45
+ group.command 'spaces:destroy <space_name> [type]', 'remove a space by and destroy its data'
46
+ group.command 'spaces:snapshots <space_name>', 'show a space\'s snapshots'
47
+ group.command 'spaces:create_snapshot <space_name@snapshot_name>', 'take a space of a space.'
48
+ group.command 'spaces:destroy_snapshot <space_name@snapshot_name>', 'remove a snapshot from a space'
49
+ end
50
+ end
51
+
52
+ def index
53
+ display usage
54
+ end
55
+
56
+ def version
57
+ display Strongspace::Client.version
58
+ end
59
+
60
+ def usage
61
+ longest_command_length = self.class.groups.map do |group|
62
+ group.map { |g| g.first.length }
63
+ end.flatten.max
64
+
65
+ self.class.groups.inject(StringIO.new) do |output, group|
66
+ output.puts "=== %s" % group.title
67
+ output.puts
68
+
69
+ group.each do |command, description|
70
+ if command.empty?
71
+ output.puts
72
+ else
73
+ output.puts "%-*s # %s" % [longest_command_length, command, description]
74
+ end
75
+ end
76
+
77
+ output.puts
78
+ output
79
+ end.string
80
+ end
81
+ end
82
+ end
83
+
84
+ Strongspace::Command::Help.create_default_groups!
@@ -0,0 +1,50 @@
1
+ module Strongspace::Command
2
+ class Keys < Base
3
+ def list
4
+ long = args.any? { |a| a == '--long' }
5
+ keys = strongspace.keys["ssh_keys"]
6
+ if keys.empty?
7
+ display "No keys for #{strongspace.username}"
8
+ else
9
+ display "=== #{keys.size} key#{'s' if keys.size > 1} for #{strongspace.username}"
10
+ keys.each do |key|
11
+ display long ? key["key"].strip : format_key_for_display(key["key"]) + " key-id: #{key["id"]}"
12
+ end
13
+ end
14
+ end
15
+ alias :index :list
16
+
17
+ def add
18
+ keyfile = args.first || find_key
19
+ key = File.read(keyfile)
20
+
21
+ display "Uploading ssh public key #{keyfile}"
22
+
23
+ strongspace.add_key(key)
24
+ end
25
+
26
+ def remove
27
+ strongspace.remove_key(args.first)
28
+ display "Key #{args.first} removed."
29
+ end
30
+
31
+ def clear
32
+ strongspace.remove_all_keys
33
+ display "All keys removed."
34
+ end
35
+
36
+ protected
37
+ def find_key
38
+ %w(rsa dsa).each do |key_type|
39
+ keyfile = "#{home_directory}/.ssh/id_#{key_type}.pub"
40
+ return keyfile if File.exists? keyfile
41
+ end
42
+ raise CommandFailed, "No ssh public key found in #{home_directory}/.ssh/id_[rd]sa.pub. You may want to specify the full path to the keyfile."
43
+ end
44
+
45
+ def format_key_for_display(key)
46
+ type, hex, local = key.strip.split(/\s/)
47
+ [type, hex[0,10] + '...' + hex[-10,10], local].join(' ')
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ module Strongspace::Command
2
+ class Spaces < Base
3
+ def list
4
+ long = args.any? { |a| a == '--long' }
5
+ spaces = strongspace.spaces["spaces"]
6
+
7
+ if spaces.empty?
8
+ display "#{strongspace.username} has no spaces"
9
+ else
10
+ display "=== #{strongspace.username} has #{spaces.size} space#{'s' if spaces.size > 1}"
11
+ spaces.each do |space|
12
+ space = space["space"]
13
+ display "#{space['name']} [type: #{space['type']}, snapshots: #{space['snapshots']}]"
14
+ end
15
+ end
16
+ end
17
+ alias :index :list
18
+
19
+ def create
20
+ name = args[0]
21
+ type = args[1]
22
+
23
+ strongspace.create_space(name, type)
24
+ display "Create space #{name}"
25
+ end
26
+
27
+ def destroy
28
+ strongspace.destroy_space(args.first)
29
+ display "Space #{args.first} removed."
30
+ end
31
+
32
+ def snapshots
33
+ if args.length == 0
34
+ display "No space specified."
35
+ return
36
+ end
37
+ snapshots = strongspace.snapshots(args.first)["snapshots"]
38
+
39
+ if snapshots.empty?
40
+ display "Space #{args.first} has no snapshots"
41
+ else
42
+ display "=== Space #{args.first} has #{snapshots.size} snapshot#{'s' if snapshots.size > 1}"
43
+ snapshots.each do |snapshot|
44
+ snapshot = snapshot["snapshot"]
45
+ display "#{args.first}@#{snapshot['name']} [created: #{snapshot['created_at']}]"
46
+ end
47
+ end
48
+ end
49
+
50
+ def create_snapshot
51
+ space_name, snapshot_name = args[0].split("@")
52
+
53
+ strongspace.create_snapshot(space_name, snapshot_name)
54
+ display "Created snapshot '#{args[0]}'"
55
+ end
56
+
57
+ def destroy_snapshot
58
+ space_name, snapshot_name = args[0].split("@")
59
+
60
+ strongspace.destroy_snapshot(space_name, snapshot_name)
61
+ display "Destroyed snapshot '#{args.first}'"
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module Strongspace::Command
2
+ class Version < Base
3
+ def index
4
+ display Strongspace::Client.gem_version_string
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,86 @@
1
+ module Strongspace
2
+ module Helpers
3
+ def home_directory
4
+ running_on_windows? ? ENV['USERPROFILE'] : ENV['HOME']
5
+ end
6
+
7
+ def running_on_windows?
8
+ RUBY_PLATFORM =~ /mswin32|mingw32/
9
+ end
10
+
11
+ def running_on_a_mac?
12
+ RUBY_PLATFORM =~ /-darwin\d/
13
+ end
14
+
15
+ def display(msg, newline=true)
16
+ if newline
17
+ puts(msg)
18
+ else
19
+ print(msg)
20
+ STDOUT.flush
21
+ end
22
+ end
23
+
24
+ def redisplay(line, line_break = false)
25
+ display("\r\e[0K#{line}", line_break)
26
+ end
27
+
28
+ def error(msg)
29
+ STDERR.puts(msg)
30
+ exit 1
31
+ end
32
+
33
+ def confirm(message="Are you sure you wish to continue? (y/n)?")
34
+ display("#{message} ", false)
35
+ ask.downcase == 'y'
36
+ end
37
+
38
+ def confirm_command(app = app)
39
+ if extract_option('--force')
40
+ display("Warning: The --force switch is deprecated, and will be removed in a future release. Use --confirm #{app} instead.")
41
+ return true
42
+ end
43
+
44
+ raise(Strongspace::Command::CommandFailed, "No app specified.\nRun this command from app folder or set it adding --app <app name>") unless app
45
+
46
+ confirmed_app = extract_option('--confirm', false)
47
+ if confirmed_app
48
+ unless confirmed_app == app
49
+ raise(Strongspace::Command::CommandFailed, "Confirmed app #{confirmed_app} did not match the selected app #{app}.")
50
+ end
51
+ return true
52
+ else
53
+ display "\n ! Potentially Destructive Action"
54
+ display " ! To proceed, type \"#{app}\" or re-run this command with --confirm #{@app}"
55
+ display "> ", false
56
+ if ask.downcase != app
57
+ display " ! Input did not match #{app}. Aborted."
58
+ false
59
+ else
60
+ true
61
+ end
62
+ end
63
+ end
64
+
65
+ def format_date(date)
66
+ date = Time.parse(date) if date.is_a?(String)
67
+ date.strftime("%Y-%m-%d %H:%M %Z")
68
+ end
69
+
70
+ def ask
71
+ gets.strip
72
+ end
73
+
74
+ def shell(cmd)
75
+ FileUtils.cd(Dir.pwd) {|d| return `#{cmd}`}
76
+ end
77
+ end
78
+ end
79
+
80
+ unless String.method_defined?(:shellescape)
81
+ class String
82
+ def shellescape
83
+ empty? ? "''" : gsub(/([^A-Za-z0-9_\-.,:\/@\n])/n, '\\\\\\1').gsub(/\n/, "'\n'")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ module Strongspace
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,3 @@
1
+ module Strongspace; end
2
+
3
+ require 'strongspace/client'
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: strongspace
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Strongspace
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-06 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rake
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 27
44
+ segments:
45
+ - 1
46
+ - 3
47
+ - 0
48
+ version: 1.3.0
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: taps
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 5
60
+ segments:
61
+ - 0
62
+ - 3
63
+ - 11
64
+ version: 0.3.11
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: webmock
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 1
78
+ - 5
79
+ - 0
80
+ version: 1.5.0
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: rest-client
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - <
90
+ - !ruby/object:Gem::Version
91
+ hash: 11
92
+ segments:
93
+ - 1
94
+ - 7
95
+ - 0
96
+ version: 1.7.0
97
+ type: :runtime
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: json_pure
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - <
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 1
110
+ - 5
111
+ - 0
112
+ version: 1.5.0
113
+ type: :runtime
114
+ version_requirements: *id006
115
+ description: Client library and command line tool for Strongspace.
116
+ email: support@strongspace.com
117
+ executables:
118
+ - strongspace
119
+ extensions: []
120
+
121
+ extra_rdoc_files: []
122
+
123
+ files:
124
+ - bin/strongspace
125
+ - lib/strongspace/client.rb
126
+ - lib/strongspace/command.rb
127
+ - lib/strongspace/commands/auth.rb
128
+ - lib/strongspace/commands/base.rb
129
+ - lib/strongspace/commands/help.rb
130
+ - lib/strongspace/commands/keys.rb
131
+ - lib/strongspace/commands/spaces.rb
132
+ - lib/strongspace/commands/version.rb
133
+ - lib/strongspace/helpers.rb
134
+ - lib/strongspace/version.rb
135
+ - lib/strongspace.rb
136
+ has_rdoc: true
137
+ homepage: http://github.com/expandrive/strongspace
138
+ licenses: []
139
+
140
+ post_install_message:
141
+ rdoc_options: []
142
+
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ hash: 3
151
+ segments:
152
+ - 0
153
+ version: "0"
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ hash: 3
160
+ segments:
161
+ - 0
162
+ version: "0"
163
+ requirements: []
164
+
165
+ rubyforge_project:
166
+ rubygems_version: 1.3.7
167
+ signing_key:
168
+ specification_version: 3
169
+ summary: Client library and CLI for Strongspace.
170
+ test_files: []
171
+