strongspace 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ #!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'strongspace' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ version = ">= 0"
12
+
13
+ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
14
+ version = $1
15
+ ARGV.shift
16
+ end
17
+
18
+ gem 'strongspace', version
19
+ load 'strongspace'
@@ -0,0 +1,20 @@
1
+ #!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'strongspace' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ version = ">= 0"
12
+
13
+ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
14
+ version = $1
15
+ ARGV.shift
16
+ end
17
+
18
+ gem 'strongspace', version
19
+ load 'strongspace'
20
+
data/lib/strongspace.rb CHANGED
@@ -1,3 +1,24 @@
1
1
  module Strongspace; end
2
2
 
3
- require 'strongspace/client'
3
+ require 'rest_client'
4
+ require 'uri'
5
+ require 'json/pure' unless {}.respond_to?(:to_json)
6
+ require 'fileutils'
7
+
8
+ STRONGSPACE_LIB_PATH = File.dirname(__FILE__) + "/strongspace/"
9
+
10
+ [
11
+ "version",
12
+ "exceptions",
13
+ "client",
14
+ "helpers",
15
+ "plugin_interface",
16
+ "plugin",
17
+ "command",
18
+ "commands/base"
19
+ ].each do |library|
20
+ require STRONGSPACE_LIB_PATH + library
21
+ end
22
+
23
+
24
+ Dir["#{STRONGSPACE_LIB_PATH}/commands/*.rb"].each { |c| require c }
@@ -1,8 +1,3 @@
1
- require 'rest_client'
2
- require 'uri'
3
- require 'strongspace/version'
4
- require 'json/pure' unless {}.respond_to?(:to_json)
5
-
6
1
  # A Ruby class to call the Strongspace REST API. You might use this if you want to
7
2
  # manage your Strongspace apps from within a Ruby program, such as Capistrano.
8
3
  #
@@ -23,14 +18,26 @@ class Strongspace::Client
23
18
  attr_accessor :host, :user, :password
24
19
 
25
20
  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
21
+ begin
22
+ client = new(user, password, host)
23
+ return JSON.parse client.get('/api/v1/api_token', :username => user, :password => password).to_s
24
+ rescue RestClient::Request::Unauthorized => e
25
+ raise Strongspace::Exceptions::InvalidCredentials
26
+ rescue SocketError => e
27
+ raise Strongspace::Exceptions::NoConnection
28
+ end
28
29
  end
29
30
 
30
31
  def username
32
+ return nil if !user
33
+
31
34
  self.user.split("/")[0]
32
35
  end
33
36
 
37
+ def login_token
38
+ doc = JSON.parse get('/api/v1/login_token')
39
+ end
40
+
34
41
  def initialize(user, password, host='https://www.strongspace.com')
35
42
  @user = user
36
43
  @password = password
@@ -73,6 +80,7 @@ class Strongspace::Client
73
80
 
74
81
  def snapshots(space_name)
75
82
  doc = JSON.parse get("/api/v1/spaces/#{escape(space_name)}/snapshots").to_s
83
+ doc["snapshots"]
76
84
  end
77
85
 
78
86
  def delete_snapshot(space_name, snapshot_name)
@@ -87,6 +95,7 @@ class Strongspace::Client
87
95
  # Get the list of ssh public keys for the current user.
88
96
  def keys
89
97
  doc = JSON.parse get('/api/v1/ssh_keys')
98
+ doc["ssh_keys"]
90
99
  end
91
100
 
92
101
  # Add an ssh public key to the current user.
@@ -1,9 +1,3 @@
1
- require 'strongspace/helpers'
2
- require 'strongspace/plugin'
3
- require 'strongspace/commands/base'
4
-
5
- Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
6
-
7
1
  module Strongspace
8
2
  module Command
9
3
  class InvalidCommand < RuntimeError; end
@@ -21,7 +15,7 @@ module Strongspace
21
15
  raise InvalidCommand
22
16
  end
23
17
 
24
- run_internal 'auth:reauthorize', args.dup if retries > 0
18
+ run_internal 'auth:reauthorize_interactve', args.dup if retries > 0
25
19
  run_internal(command, args.dup)
26
20
  rescue InvalidCommand
27
21
  error "Unknown command. Run 'strongspace help' for usage information."
@@ -30,7 +24,7 @@ module Strongspace
30
24
  STDERR.puts "Authentication failure"
31
25
  run(command, args, retries+1)
32
26
  else
33
- error "Authentication failure"
27
+ error "! Authentication failure"
34
28
  end
35
29
  rescue RestClient::ResourceNotFound => e
36
30
  error extract_not_found(e.http_body)
@@ -46,6 +40,9 @@ module Strongspace
46
40
  end
47
41
 
48
42
  def run_internal(command, args, strongspace=nil)
43
+ if command == "web:start"
44
+ require 'strongspace-web'
45
+ end
49
46
  klass, method = parse(command)
50
47
  runner = klass.new(args, strongspace)
51
48
  raise InvalidCommand unless runner.respond_to?(method)
@@ -90,3 +87,4 @@ module Strongspace
90
87
  end
91
88
  end
92
89
  end
90
+
@@ -20,11 +20,34 @@ module Strongspace::Command
20
20
  ENV['STRONGSPACE_HOST'] || 'https://www.strongspace.com'
21
21
  end
22
22
 
23
- def reauthorize
23
+ def reauthorize_interactve
24
24
  @credentials = ask_for_credentials
25
25
  write_credentials
26
26
  end
27
27
 
28
+ def authorize!
29
+ @credentials = [args.first, args[1]]
30
+ r = Strongspace::Client.auth(@credentials[0], @credentials[1])
31
+ if r
32
+ @credentials[0] = "#{@credentials[0]}/token"
33
+ @credentials[1] = r['api_token']
34
+ write_credentials
35
+ return true
36
+ end
37
+
38
+ return false
39
+ end
40
+
41
+ def authenticated_login
42
+ if args.blank?
43
+ url = "#{host}/login/#{client.login_token['login_token']}"
44
+ else
45
+ to = URI.escape(args[0][0..1]) + URI.escape(URI.escape(args[0][2..-1])).gsub('&', '%26')
46
+ url = "#{host}/login/#{client.login_token['login_token']}?to=#{to}"
47
+ end
48
+ `open "#{url}"`
49
+ end
50
+
28
51
  def user # :nodoc:
29
52
  get_credentials
30
53
  @credentials[0]
@@ -36,7 +59,7 @@ module Strongspace::Command
36
59
  end
37
60
 
38
61
  def credentials_file
39
- "#{home_directory}/.strongspace/credentials"
62
+ "#{credentials_folder}/credentials"
40
63
  end
41
64
 
42
65
  def get_credentials # :nodoc:
@@ -72,6 +95,15 @@ module Strongspace::Command
72
95
  ["#{user}/token", Strongspace::Client.auth(user, password, host)['api_token']]
73
96
  end
74
97
 
98
+ def valid_saved_credentials?
99
+ if File.exists?(credentials_file)
100
+ credentials = read_credentials
101
+ r = Strongspace::Client.auth(credentials[0], credentials[1])
102
+ return !r.blank?
103
+ end
104
+ return false
105
+ end
106
+
75
107
  def ask_for_password_on_windows
76
108
  require "Win32API"
77
109
  char = nil
@@ -124,7 +156,12 @@ module Strongspace::Command
124
156
  end
125
157
 
126
158
  def write_credentials
127
- FileUtils.mkdir_p(File.dirname(credentials_file))
159
+ begin
160
+ FileUtils.mkdir_p(credentials_folder)
161
+ rescue Errno::EEXIST => e
162
+
163
+ end
164
+
128
165
  File.open(credentials_file, 'w') do |f|
129
166
  f.puts self.credentials
130
167
  end
@@ -1,7 +1,3 @@
1
- require 'fileutils'
2
- require 'strongspace/plugin_interface'
3
-
4
-
5
1
  module Strongspace::Command
6
2
  class Base
7
3
  include Strongspace::Helpers
@@ -58,8 +58,8 @@ module Strongspace::Command
58
58
  group.command 'spaces:create <name> [type]', 'add a new space. type => (normal,public,backup)'
59
59
  group.command 'spaces:delete <name> [type]', 'remove a space by and destroy its data'
60
60
  group.command 'spaces:snapshots <name>', 'show a space\'s snapshots'
61
- group.command 'spaces:create_snapshot <name@snapshot_name>', 'take a space of a space.'
62
- group.command 'spaces:delete_snapshot <name@snapshot_name>', 'remove a snapshot from a space'
61
+ group.command 'spaces:create_snapshot <name> [snapshot_name]', 'take a space of a space - snapshot_name defaults to current date/time.'
62
+ group.command 'spaces:delete_snapshot <name> <snapshot_name>', 'remove a snapshot from a space'
63
63
  end
64
64
 
65
65
  group 'Plugins' do |group|
@@ -2,7 +2,7 @@ module Strongspace::Command
2
2
  class Keys < Base
3
3
  def list
4
4
  long = args.any? { |a| a == '--long' }
5
- keys = strongspace.keys["ssh_keys"]
5
+ keys = strongspace.keys
6
6
  if keys.empty?
7
7
  display "No keys for #{strongspace.username}"
8
8
  else
@@ -11,6 +11,7 @@ module Strongspace::Command
11
11
  display long ? key["key"].strip : format_key_for_display(key["key"]) + " key-id: #{key["id"]}"
12
12
  end
13
13
  end
14
+ keys
14
15
  end
15
16
  alias :index :list
16
17
 
@@ -19,6 +20,25 @@ module Strongspace::Command
19
20
  return ($? == 0)
20
21
  end
21
22
 
23
+ def generate_for_gui
24
+ return unless running_on_a_mac?
25
+ FileUtils.mkdir "#{credentials_folder}" unless File.exist? "#{credentials_folder}"
26
+
27
+
28
+ File.open("#{credentials_folder}/known_hosts", "w") do |f|
29
+ f.write "*.strongspace.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArXBYAoHZWVzLfHNMlgteAbq20AaCVcE1qALqVjYZerIpa3rBjNlv2i/2O8ul3OmSfcQwQGPTnABLqz9cozAbxF01eDfqUiSABUDT6m1/lY1a0V7RGS46Y/KJMVbOb4mVpxDZOVwBQh/DYTu7R55vFc93lXpE+tZboqnuq+LvJIZDqzoGTHIUprRs3sNY8Xegnz+m68P+tV6iLkXMRk8Gh8/IIavN4mXYhWPVbCv6Gqo2XhiYVMrCqLZFKLG0W6uwWY/xOhUjWxKDZMlqhyU/YUsMB5BZc9/x0t+Sc82OL+Eh3IB5EUmmCWnhm/LKxjMIn2UNe48BQqwaU/gozVtVPQ==\n"
30
+ end
31
+
32
+
33
+ if !File.exist? "#{credentials_folder}/#{hostname}.rsa"
34
+ `/usr/bin/ssh-keygen -f #{credentials_folder}/#{hostname}.rsa -b 2048 -C \" Strongspace App - #{hostname}\" -q -N ""` unless File.exist? "#{credentials_folder}/#{hostname}.rsa"
35
+ args[0] = "#{credentials_folder}/#{hostname}.rsa.pub"
36
+ begin
37
+ add
38
+ rescue RestClient::Conflict => e # Swallow errors if the key already exists on Strongspace
39
+ end
40
+ end
41
+ end
22
42
 
23
43
  def add
24
44
  keyfile = args.first || find_key
@@ -39,6 +59,19 @@ module Strongspace::Command
39
59
  display "All keys removed."
40
60
  end
41
61
 
62
+ def valid_key_gui?
63
+ return unless running_on_a_mac? and File.exist? "#{support_directory}/ssh"
64
+
65
+ ret = `ssh -o PreferredAuthentications=publickey -i "#{support_directory}/ssh/#{hostname}.rsa" #{strongspace.username}@#{strongspace.username}.strongspace.com 2>&1`
66
+
67
+ if ret.include? "Strongspace"
68
+ display "Valid key installed"
69
+ return true
70
+ end
71
+ display "No valid key installed"
72
+ return false
73
+ end
74
+
42
75
  protected
43
76
  def find_key
44
77
  %w(rsa dsa).each do |key_type|
@@ -2,14 +2,13 @@ module Strongspace::Command
2
2
  class Spaces < Base
3
3
  def list
4
4
  long = args.any? { |a| a == '--long' }
5
- spaces = strongspace.spaces["spaces"]
5
+ spaces = strongspace.spaces
6
6
 
7
7
  if spaces.empty?
8
8
  display "#{strongspace.username} has no spaces"
9
9
  else
10
10
  display "=== #{strongspace.username} has #{spaces.size} space#{'s' if spaces.size > 1}"
11
11
  spaces.each do |space|
12
- space = space["space"]
13
12
  display "#{space['name']} [type: #{space['type']}, snapshots: #{space['snapshots']}]"
14
13
  end
15
14
  end
@@ -34,31 +33,171 @@ module Strongspace::Command
34
33
  display "No space specified."
35
34
  return
36
35
  end
37
- snapshots = strongspace.snapshots(args.first)["snapshots"]
36
+ snapshots = strongspace.snapshots(args.first)
38
37
 
39
38
  if snapshots.empty?
40
39
  display "Space #{args.first} has no snapshots"
41
40
  else
42
41
  display "=== Space #{args.first} has #{snapshots.size} snapshot#{'s' if snapshots.size > 1}"
43
42
  snapshots.each do |snapshot|
44
- snapshot = snapshot["snapshot"]
45
43
  display "#{args.first}@#{snapshot['name']} [created: #{snapshot['created_at']}]"
46
44
  end
47
45
  end
48
46
  end
49
47
 
50
48
  def create_snapshot
51
- space_name, snapshot_name = args[0].split("@")
49
+ space_name, snapshot_name = args[0..1]
50
+
51
+ if snapshot_name.blank?
52
+ snapshot_name = Time.now.strftime("%Y-%m-%d-%H%M%S")
53
+ end
52
54
 
53
55
  strongspace.create_snapshot(space_name, snapshot_name)
54
- display "Created snapshot '#{args[0]}'"
56
+ display "Created snapshot '#{space_name}@#{snapshot_name}'"
57
+ end
58
+
59
+ def create_snapshot_and_thin
60
+
61
+ retries = 0
62
+ success = false
63
+ while (!success and (retries < 5)) do
64
+ begin
65
+ create_snapshot
66
+ thin_snapshots
67
+ rescue SocketError => e
68
+ sleep(10)
69
+ retries = retries + 1
70
+ next
71
+ end
72
+ success = true
73
+ end
74
+
55
75
  end
56
76
 
57
77
  def delete_snapshot
58
- space_name, snapshot_name = args[0].split("@")
78
+ space_name, snapshot_name = args[0..1]
59
79
 
60
80
  strongspace.delete_snapshot(space_name, snapshot_name)
61
- display "Destroyed snapshot '#{args.first}'"
81
+ display "Destroyed snapshot '#{space_name}@#{snapshot_name}'"
82
+ end
83
+
84
+ def thin_snapshots
85
+ snapshots = strongspace.snapshots(args.first)
86
+
87
+ keeplist = []
88
+
89
+ if snapshots.count < 24
90
+ return
91
+ end
92
+
93
+ snapshots.each do |s|
94
+
95
+ if Time.parse(s['created_at']) > (Time.now - 3600*24)
96
+ keeplist << s
97
+ next
98
+ end
99
+
100
+ end
101
+
102
+ (snapshots - keeplist).each do |k|
103
+ puts "Drop: " + k['name']
104
+ strongspace.delete_snapshot(args.first, k['name'])
105
+ end
106
+
107
+ end
108
+
109
+
110
+ def schedule_snapshots
111
+ space_name = args[0]
112
+
113
+ if running_on_a_mac?
114
+ plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
115
+ <!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
116
+ http://www.apple.com/DTDs/PropertyList-1.0.dtd >
117
+ <plist version=\"1.0\">
118
+ <dict>
119
+ <key>Label</key>
120
+ <string>com.strongspace.Snapshots.#{space_name}</string>
121
+ <key>Program</key>
122
+ <string>#{support_directory}/gems/bin/strongspace</string>
123
+ <key>ProgramArguments</key>
124
+ <array>
125
+ <string>strongspace</string>
126
+ <string>spaces:create_snapshot_and_thin</string>
127
+ <string>#{space_name}</string>
128
+ </array>
129
+ <key>KeepAlive</key>
130
+ <false/>
131
+ <key>StartCalendarInterval</key>
132
+ <dict>
133
+ <key>Minute</key>
134
+ <integer>0</integer>
135
+ </dict>
136
+ <key>RunAtLoad</key>
137
+ <true/>
138
+ <key>StandardOutPath</key>
139
+ <string>#{log_file}</string>
140
+ <key>StandardErrorPath</key>
141
+ <string>#{log_file}</string>
142
+ <key>EnvironmentVariables</key>
143
+ <dict>
144
+ <key>GEM_PATH</key>
145
+ <string>#{support_directory}/gems</string>
146
+ <key>GEM_HOME</key>
147
+ <string>#{support_directory}/gems</string>
148
+ <key>RACK_ENV</key>
149
+ <string>production</string>
150
+ </dict>
151
+
152
+ </dict>
153
+ </plist>"
154
+
155
+ file = File.new(launchd_plist_file(space_name), "w+")
156
+ file.puts plist
157
+ file.close
158
+
159
+ r = `launchctl load -S aqua '#{launchd_plist_file(space_name)}'`
160
+ if r.strip.ends_with?("Already loaded")
161
+ error "This task is aready scheduled, unload before scheduling again"
162
+ return
163
+ end
164
+ display "Scheduled Snapshots of #{space_name}"
165
+ end
166
+ end
167
+
168
+ def unschedule_snapshots
169
+ space_name = args[0]
170
+
171
+ if space_name.blank?
172
+ display "Please supply the name of a space"
173
+ return false
174
+ end
175
+
176
+ if running_on_windows?
177
+ error "Scheduling currently isn't supported on Windows"
178
+ return
179
+ end
180
+
181
+ if running_on_a_mac?
182
+ if File.exist? launchd_plist_file(space_name)
183
+ `launchctl unload '#{launchd_plist_file(space_name)}'`
184
+ FileUtils.rm(launchd_plist_file(space_name))
185
+ end
186
+ else # Assume we're running on linux/unix
187
+ CronEdit::Crontab.Remove "strongspace-snapshots-#{space_name}"
188
+ end
189
+
190
+ display "Unscheduled snapshotting of #{space_name}"
191
+ end
192
+
193
+
194
+ private
195
+ def launchd_plist_file(space_name)
196
+ "#{launchd_agents_folder}/com.strongspace.Snapshots.#{space_name}.plist"
197
+ end
198
+
199
+ def log_file
200
+ "#{logs_folder}/Strongspace.log"
62
201
  end
63
202
 
64
203
  end
@@ -0,0 +1,17 @@
1
+ module Strongspace
2
+ module Exceptions
3
+ class StrongspaceError < StandardError; end
4
+
5
+ class InvalidCredentials < StrongspaceError
6
+ def message
7
+ "Invalid Strongspace Credentials"
8
+ end
9
+ end
10
+
11
+ class NoConnection < StrongspaceError
12
+ def message
13
+ "Could not connect to Strongspace"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -5,32 +5,77 @@ module Strongspace
5
5
  self.class.name.split("::").last
6
6
  end
7
7
 
8
- def home_directory
8
+ def self.home_directory
9
9
  running_on_windows? ? ENV['USERPROFILE'] : ENV['HOME']
10
10
  end
11
11
 
12
+ def home_directory
13
+ return Strongspace::Helpers.home_directory
14
+ end
15
+
16
+ def self.support_directory
17
+ running_on_windows? ? "#{home_directory}/Strongspace" : "#{home_directory}/Library/Strongspace"
18
+ end
19
+
20
+ def support_directory
21
+ return Strongspace::Helpers.support_directory
22
+ end
23
+
24
+ def self.running_on_windows?
25
+ RUBY_PLATFORM =~ /mswin32|mingw32/
26
+ end
27
+
12
28
  def running_on_windows?
13
29
  RUBY_PLATFORM =~ /mswin32|mingw32/
14
30
  end
15
31
 
32
+ def self.running_on_a_mac?
33
+ RUBY_PLATFORM =~ /-darwin\d/
34
+ end
35
+
16
36
  def running_on_a_mac?
17
37
  RUBY_PLATFORM =~ /-darwin\d/
18
38
  end
19
39
 
40
+ def gui_ssh_key
41
+ "#{credentials_folder}/#{hostname}.rsa"
42
+ end
43
+
44
+ def hostname
45
+ @hostname ||= `hostname`.strip
46
+
47
+ if @hostname.include?(".local")
48
+ @hostname = @hostname.split(".")[0]
49
+ end
50
+ return @hostname
51
+ end
52
+
53
+ def credentials_folder
54
+ "#{support_directory}/credentials"
55
+ end
56
+
20
57
  def pids_folder
21
- "#{home_directory}/.strongspace/pids"
58
+ "#{support_directory}/pids"
22
59
  end
23
60
 
24
61
  def plugins_folder
25
62
  Strongspace::Plugin.directory
26
63
  end
27
64
 
65
+ def logs_folder
66
+ if running_on_a_mac?
67
+ "#{home_directory}/Library/Logs/Strongspace"
68
+ else
69
+ "#{support_directory}/logs"
70
+ end
71
+ end
72
+
28
73
  def bin_folder
29
- "#{home_directory}/.strongspace/bin"
74
+ "#{support_directory}/bin"
30
75
  end
31
76
 
32
77
  def launchd_agents_folder
33
- "#{home_directory}/Library/LaunchAgents"
78
+ "#{support_directory}/LaunchAgents"
34
79
  end
35
80
 
36
81
  def pid_file_path(name)
@@ -58,7 +103,8 @@ module Strongspace
58
103
  end
59
104
 
60
105
  begin
61
- # This process is running
106
+ # This process is running, Kill 0 is a no-op that only works
107
+ # if the process exists
62
108
  Process.kill(0, existing_pid)
63
109
  return true
64
110
  rescue Errno::EPERM
@@ -165,24 +211,17 @@ module Strongspace
165
211
  end
166
212
 
167
213
  def space_exist?(name)
168
- strongspace.spaces["spaces"].each do |space|
214
+ strongspace.spaces.each do |space|
169
215
  # TODO: clean up the json returned by the strongspace API requests to simplify this iteration
170
- space = space["space"]
171
216
  return true if space["name"] == name
172
217
  end
173
218
  return false
174
219
  end
175
220
 
176
- def valid_space_name?(name)
177
- # For now, just make sure the space name is all "word characters," i.e. [0-9A-Za-z_]
178
- return false if name =~ /\W/
179
- return true
180
- end
181
221
 
182
222
  def backup_space?(name)
183
223
  space = nil
184
- strongspace.spaces["spaces"].each do |s|
185
- s = s["space"]
224
+ strongspace.spaces.each do |s|
186
225
  if s["name"] == name then
187
226
  space = s
188
227
  break
@@ -1,5 +1,3 @@
1
- # based on the Rails Plugin
2
-
3
1
  module Strongspace
4
2
  class Plugin
5
3
  class << self
@@ -9,7 +7,7 @@ module Strongspace
9
7
  attr_reader :name, :uri
10
8
 
11
9
  def self.directory
12
- File.expand_path("#{home_directory}/.strongspace/plugins")
10
+ File.expand_path("#{support_directory}/plugins")
13
11
  end
14
12
 
15
13
  def self.list
@@ -19,6 +17,7 @@ module Strongspace
19
17
  end
20
18
 
21
19
  def self.load!
20
+ self.update_support_directory!
22
21
  list.each do |plugin|
23
22
  begin
24
23
  load_plugin(plugin)
@@ -26,6 +25,14 @@ module Strongspace
26
25
  display "Unable to load plugin: #{plugin}: #{e.message}"
27
26
  end
28
27
  end
28
+ self.load_default_gem_plugins
29
+ end
30
+
31
+ def self.load_default_gem_plugins
32
+ begin
33
+ require 'strongspace-rsync'
34
+ rescue Exception => e
35
+ end
29
36
  end
30
37
 
31
38
  def self.load_plugin(plugin)
@@ -38,6 +45,15 @@ module Strongspace
38
45
  FileUtils.rm_rf("#{self.directory}/#{plugin}")
39
46
  end
40
47
 
48
+ def self.update_support_directory!
49
+ if running_on_a_mac?
50
+ # if File.exist?("#{home_directory}/.strongspace") and !File.exist?("#{support_directory}")
51
+ # FileUtils.mv("#{home_directory}/.strongspace", "#{support_directory}")
52
+ # end
53
+
54
+ FileUtils.mkdir_p(launchd_agents_folder) unless File.exist? launchd_agents_folder
55
+ end
56
+ end
41
57
 
42
58
  def initialize(uri)
43
59
  @uri = uri
@@ -1,3 +1,3 @@
1
1
  module Strongspace
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/spec/auth_spec.rb ADDED
@@ -0,0 +1,19 @@
1
+ require File.expand_path("./base", File.dirname(__FILE__))
2
+
3
+ require "strongspace"
4
+
5
+ def prepare_command(klass)
6
+ command = klass.new(['--app', 'myapp'])
7
+ command.stub!(:args).and_return([])
8
+ command.stub!(:display)
9
+ command
10
+ end
11
+
12
+
13
+
14
+ describe Strongspace::Command::Auth do
15
+
16
+
17
+
18
+
19
+ end
data/spec/base.rb CHANGED
@@ -8,9 +8,7 @@ require 'fileutils'
8
8
  require 'tmpdir'
9
9
  require 'webmock/rspec'
10
10
 
11
- require 'strongspace/command'
12
- require 'strongspace/commands/base'
13
- Dir["#{File.dirname(__FILE__)}/../lib/strongspace/commands/*"].each { |c| require c }
11
+ require 'strongspace'
14
12
 
15
13
  include WebMock::API
16
14
 
data/spec/client_spec.rb CHANGED
@@ -1,23 +1,42 @@
1
1
  require File.expand_path("./base", File.dirname(__FILE__))
2
2
  require "cgi"
3
- require "strongspace/client"
3
+ require "strongspace"
4
4
 
5
5
  describe Strongspace::Client do
6
6
  before do
7
7
  @client = Strongspace::Client.new(nil, nil)
8
8
  end
9
9
 
10
- it "Client.auth -> get user details" do
10
+ it "should return the current version" do
11
+ Strongspace::Client.version.should == Strongspace::VERSION
12
+ end
13
+
14
+ it "should return a gem version string" do
15
+ Strongspace::Client.gem_version_string.should == "strongspace-gem/#{Strongspace::VERSION}"
16
+ end
17
+
18
+ it "should return an API key hash for auth" do
11
19
  api_token = { "api_key" => "abc" }
12
20
  stub_request(:get, "https://foo:bar@www.strongspace.com/api/v1/api_token").to_return(:body => api_token.to_json)
13
21
  Strongspace::Client.auth("foo", "bar").should == api_token
14
22
  end
15
23
 
16
- it "list -> get a list of this user's apps" do
24
+ it "should fail auth gracefully with a bad password" do
25
+ api_token = { "api_key" => "abc" }
26
+ stub_request(:get, "https://foo:bar@www.strongspace.com/api/v1/api_token").to_return(:body => api_token.to_json)
27
+ lambda {Strongspace::Client.auth("foo", "ba3r")}.should raise_error(WebMock::NetConnectNotAllowedError)
28
+ end
29
+
30
+ it "should return nil for username and password" do
31
+ @client.username.should == nil
32
+ @client.password.should == nil
33
+ end
34
+
35
+ it "should return an array of spaces" do
17
36
  stub_api_request(:get, "/spaces").to_return(:body => <<-EOJSON)
18
- {"spaces":[{"space":{"name":"a space", "snapshots":0, "type":"normal"}}, {"space":{"name":"diskimages", "snapshots":0, "type":"normal"}}]}
37
+ {"spaces" : [{"space":{"name":"a space", "snapshots":0, "type":"normal"}}, {"space":{"name":"diskimages", "snapshots":0, "type":"normal"}}]}
19
38
  EOJSON
20
- @client.spaces.should == {"spaces"=>[{"space"=>{"name"=>"a space", "snapshots"=>0, "type"=>"normal"}}, {"space"=>{"name"=>"diskimages", "snapshots"=>0, "type"=>"normal"}}]}
39
+ @client.spaces.should == [{"space"=>{"name"=>"a space", "snapshots"=>0, "type"=>"normal"}}, {"space"=>{"name"=>"diskimages", "snapshots"=>0, "type"=>"normal"}}]
21
40
  end
22
41
 
23
42
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strongspace
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Strongspace
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-11 00:00:00 -05:00
18
+ date: 2011-01-30 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -91,39 +91,37 @@ dependencies:
91
91
  type: :development
92
92
  version_requirements: *id005
93
93
  - !ruby/object:Gem::Dependency
94
- name: taps
94
+ name: webmock
95
95
  prerelease: false
96
96
  requirement: &id006 !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- hash: 5
101
+ hash: 3
102
102
  segments:
103
+ - 1
104
+ - 5
103
105
  - 0
104
- - 3
105
- - 11
106
- version: 0.3.11
106
+ version: 1.5.0
107
107
  type: :development
108
108
  version_requirements: *id006
109
109
  - !ruby/object:Gem::Dependency
110
- name: webmock
110
+ name: ruby-fsevent
111
111
  prerelease: false
112
112
  requirement: &id007 !ruby/object:Gem::Requirement
113
113
  none: false
114
114
  requirements:
115
- - - ~>
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  hash: 3
118
118
  segments:
119
- - 1
120
- - 5
121
119
  - 0
122
- version: 1.5.0
120
+ version: "0"
123
121
  type: :development
124
122
  version_requirements: *id007
125
123
  - !ruby/object:Gem::Dependency
126
- name: open4
124
+ name: sinatra
127
125
  prerelease: false
128
126
  requirement: &id008 !ruby/object:Gem::Requirement
129
127
  none: false
@@ -137,7 +135,7 @@ dependencies:
137
135
  type: :development
138
136
  version_requirements: *id008
139
137
  - !ruby/object:Gem::Dependency
140
- name: ruby-fsevent
138
+ name: sinatra-reloader
141
139
  prerelease: false
142
140
  requirement: &id009 !ruby/object:Gem::Requirement
143
141
  none: false
@@ -184,14 +182,14 @@ dependencies:
184
182
  requirement: &id012 !ruby/object:Gem::Requirement
185
183
  none: false
186
184
  requirements:
187
- - - <
185
+ - - "="
188
186
  - !ruby/object:Gem::Version
189
- hash: 11
187
+ hash: 13
190
188
  segments:
191
189
  - 1
192
- - 7
193
- - 0
194
- version: 1.7.0
190
+ - 6
191
+ - 1
192
+ version: 1.6.1
195
193
  type: :runtime
196
194
  version_requirements: *id012
197
195
  - !ruby/object:Gem::Dependency
@@ -220,6 +218,8 @@ extensions: []
220
218
  extra_rdoc_files: []
221
219
 
222
220
  files:
221
+ - bin/as_installed/ss
222
+ - bin/as_installed/strongspace
223
223
  - bin/ss
224
224
  - bin/strongspace
225
225
  - lib/strongspace/client.rb
@@ -232,12 +232,14 @@ files:
232
232
  - lib/strongspace/commands/plugins.rb
233
233
  - lib/strongspace/commands/spaces.rb
234
234
  - lib/strongspace/commands/version.rb
235
+ - lib/strongspace/exceptions.rb
235
236
  - lib/strongspace/helpers.rb
236
237
  - lib/strongspace/plugin.rb
237
238
  - lib/strongspace/plugin_interface.rb
238
239
  - lib/strongspace/version.rb
239
240
  - lib/strongspace.rb
240
241
  - README.markdown
242
+ - spec/auth_spec.rb
241
243
  - spec/base.rb
242
244
  - spec/client_spec.rb
243
245
  has_rdoc: true