webbynode 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of webbynode might be problematic. Click here for more details.

Files changed (98) hide show
  1. data/Manifest +88 -4
  2. data/PostInstall.txt +42 -9
  3. data/README.rdoc +6 -0
  4. data/Rakefile +16 -19
  5. data/assets/webbynode.png +0 -0
  6. data/bin/webbynode +3 -3
  7. data/bin/wn +7 -0
  8. data/cucumber.yml +1 -0
  9. data/devver.rake +174 -0
  10. data/features/bootstrap.feature +17 -0
  11. data/features/step_definitions/command_steps.rb +14 -0
  12. data/features/support/env.rb +22 -0
  13. data/features/support/hooks.rb +8 -0
  14. data/{test/test_webbynode.rb → features/support/io_features.rb} +0 -0
  15. data/features/support/mocha.rb +15 -0
  16. data/lib/templates/api_token +14 -0
  17. data/lib/templates/backup +15 -0
  18. data/lib/templates/gitignore +4 -0
  19. data/lib/templates/help +53 -0
  20. data/lib/webbynode/api_client.rb +121 -0
  21. data/lib/webbynode/application.rb +21 -0
  22. data/lib/webbynode/command.rb +332 -0
  23. data/lib/webbynode/commands/add_backup.rb +33 -0
  24. data/lib/webbynode/commands/add_key.rb +24 -0
  25. data/lib/webbynode/commands/alias.rb +153 -0
  26. data/lib/webbynode/commands/change_dns.rb +29 -0
  27. data/lib/webbynode/commands/config.rb +15 -0
  28. data/lib/webbynode/commands/delete.rb +25 -0
  29. data/lib/webbynode/commands/help.rb +25 -0
  30. data/lib/webbynode/commands/init.rb +77 -0
  31. data/lib/webbynode/commands/push.rb +70 -0
  32. data/lib/webbynode/commands/remote.rb +28 -0
  33. data/lib/webbynode/commands/restart.rb +25 -0
  34. data/lib/webbynode/commands/start.rb +23 -0
  35. data/lib/webbynode/commands/stop.rb +23 -0
  36. data/lib/webbynode/commands/tasks.rb +149 -0
  37. data/lib/webbynode/commands/version.rb +8 -0
  38. data/lib/webbynode/commands/webbies.rb +30 -0
  39. data/lib/webbynode/git.rb +112 -0
  40. data/lib/webbynode/io.rb +175 -0
  41. data/lib/webbynode/notify.rb +19 -0
  42. data/lib/webbynode/option.rb +84 -0
  43. data/lib/webbynode/parameter.rb +27 -0
  44. data/lib/webbynode/properties.rb +43 -0
  45. data/lib/webbynode/push_and.rb +16 -0
  46. data/lib/webbynode/remote_executor.rb +21 -0
  47. data/lib/webbynode/server.rb +39 -0
  48. data/lib/webbynode/ssh.rb +65 -0
  49. data/lib/webbynode/ssh_keys.rb +36 -0
  50. data/lib/webbynode.rb +56 -0
  51. data/spec/fixtures/aliases +0 -0
  52. data/spec/fixtures/api/credentials +3 -0
  53. data/spec/fixtures/api/dns +30 -0
  54. data/spec/fixtures/api/dns_a_record +20 -0
  55. data/spec/fixtures/api/dns_a_record_already_exists +15 -0
  56. data/spec/fixtures/api/dns_a_record_error +13 -0
  57. data/spec/fixtures/api/dns_new_zone +17 -0
  58. data/spec/fixtures/api/webbies +26 -0
  59. data/spec/fixtures/api/webbies_unauthorized +12 -0
  60. data/spec/fixtures/api/webby +6 -0
  61. data/spec/fixtures/commands/tasks/after_push +3 -0
  62. data/spec/fixtures/fixture_helpers +2 -0
  63. data/spec/fixtures/git/config/210.11.13.12 +9 -0
  64. data/spec/fixtures/git/config/67.23.79.31 +9 -0
  65. data/spec/fixtures/git/config/67.23.79.32 +9 -0
  66. data/spec/fixtures/git/config/config +9 -0
  67. data/spec/fixtures/git/status/clean +2 -0
  68. data/spec/fixtures/git/status/dirty +9 -0
  69. data/spec/fixtures/pushand +2 -0
  70. data/spec/spec_helper.rb +58 -0
  71. data/spec/webbynode/api_client_spec.rb +227 -0
  72. data/spec/webbynode/application_spec.rb +50 -0
  73. data/spec/webbynode/command_spec.rb +285 -0
  74. data/spec/webbynode/commands/add_backup_spec.rb +66 -0
  75. data/spec/webbynode/commands/add_key_spec.rb +58 -0
  76. data/spec/webbynode/commands/alias_spec.rb +213 -0
  77. data/spec/webbynode/commands/change_dns_spec.rb +51 -0
  78. data/spec/webbynode/commands/config_spec.rb +22 -0
  79. data/spec/webbynode/commands/delete_spec.rb +78 -0
  80. data/spec/webbynode/commands/help_spec.rb +43 -0
  81. data/spec/webbynode/commands/init_spec.rb +326 -0
  82. data/spec/webbynode/commands/push_spec.rb +175 -0
  83. data/spec/webbynode/commands/remote_spec.rb +76 -0
  84. data/spec/webbynode/commands/tasks_spec.rb +288 -0
  85. data/spec/webbynode/commands/version_spec.rb +18 -0
  86. data/spec/webbynode/commands/webbies_spec.rb +27 -0
  87. data/spec/webbynode/git_spec.rb +310 -0
  88. data/spec/webbynode/io_spec.rb +198 -0
  89. data/spec/webbynode/option_spec.rb +48 -0
  90. data/spec/webbynode/parameter_spec.rb +70 -0
  91. data/spec/webbynode/push_and_spec.rb +28 -0
  92. data/spec/webbynode/remote_executor_spec.rb +25 -0
  93. data/spec/webbynode/server_spec.rb +101 -0
  94. data/webbynode.gemspec +25 -16
  95. metadata +182 -14
  96. data/lib/wn.rb +0 -106
  97. data/test/test_helper.rb +0 -9
  98. data/test/test_wn.rb +0 -220
@@ -0,0 +1,121 @@
1
+ require 'httparty'
2
+
3
+ module Webbynode
4
+ class ApiClient
5
+ include HTTParty
6
+ base_uri "https://manager.webbynode.com/api/yaml"
7
+
8
+ CREDENTIALS_FILE = "#{ENV['HOME']}/.webbynode"
9
+
10
+ Unauthorized = Class.new(StandardError)
11
+ InactiveZone = Class.new(StandardError)
12
+ ApiError = Class.new(StandardError)
13
+
14
+ def io
15
+ @io ||= Io.new
16
+ end
17
+
18
+ def zones
19
+ response = post("/dns")
20
+ if zones = response["zones"]
21
+ zones.inject({}) { |h, zone| h[zone[:domain]] = zone; h }
22
+ end
23
+ end
24
+
25
+ def create_record(record, ip)
26
+ original_record = record
27
+
28
+ url = Domainatrix.parse("http://#{record}")
29
+ record = url.subdomain
30
+ domain = "#{url.domain}.#{url.public_suffix}."
31
+
32
+ zone = zones[domain]
33
+ if zone
34
+ raise InactiveZone, domain unless zone[:status] == 'Active'
35
+ else
36
+ zone = create_zone(domain)
37
+ end
38
+
39
+ create_a_record(zone[:id], record, ip, original_record)
40
+ end
41
+
42
+ def create_zone(zone)
43
+ response = post("/dns/new", :query => {"zone[domain]" => zone, "zone[ttl]" => "86400"})
44
+ handle_error(response)
45
+ response
46
+ end
47
+
48
+ def create_a_record(id, record, ip, original_record)
49
+ response = post("/dns/#{id}/records/new", :query => {"record[name]" => record, "record[type]" => "A", "record[data]" => ip})
50
+ if response["errors"] and response["errors"] =~ /Data has already been taken/
51
+ io.log "'#{original_record}' is already setup on Webbynode DNS, make sure it's pointing to #{ip}", :warning
52
+ return
53
+ end
54
+
55
+ handle_error(response)
56
+ response["record"]
57
+ end
58
+
59
+ def handle_error(response)
60
+ raise ApiError, response["error"] if response["error"]
61
+ raise ApiError, "invalid response from the API (code #{response.code})" unless response.code == 200
62
+ end
63
+
64
+ def ip_for(hostname)
65
+ (webbies[hostname] || {})[:ip]
66
+ end
67
+
68
+ def webbies
69
+ unless @webbies
70
+ response = post("/webbies") || {}
71
+
72
+ @webbies = response
73
+ end
74
+
75
+ @webbies['webbies'].inject({}) { |h, webby| h[webby[:name]] = webby; h }
76
+ end
77
+
78
+ def credentials
79
+ @credentials ||= init_credentials
80
+ end
81
+
82
+ def init_credentials(overwrite=false)
83
+ creds = if io.file_exists?(CREDENTIALS_FILE) and !overwrite
84
+ properties
85
+ else
86
+ email = overwrite[:email] if overwrite.is_a?(Hash) and overwrite[:email]
87
+ token = overwrite[:token] if overwrite.is_a?(Hash) and overwrite[:token]
88
+
89
+ puts io.read_from_template("api_token") unless email and token
90
+
91
+ email ||= ask("Login email: ")
92
+ token ||= ask("API token: ")
93
+
94
+ response = self.class.post("/webbies", :body => { :email => email, :token => token })
95
+ if response.code == 401 or response.code == 411
96
+ raise Unauthorized, "You have provided the wrong credentials"
97
+ end
98
+
99
+ properties['email'] = email
100
+ properties['token'] = token
101
+ properties.save
102
+
103
+ puts
104
+
105
+ { :email => email, :token => token }
106
+ end
107
+ end
108
+
109
+ def properties
110
+ @properties ||= Webbynode::Properties.new(CREDENTIALS_FILE)
111
+ end
112
+
113
+ def post(uri, options={})
114
+ response = self.class.post(uri, { :body => credentials }.merge(options))
115
+ if response.code == 401 or response.code == 411
116
+ raise Unauthorized, "You have provided the wrong credentials"
117
+ end
118
+ response
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,21 @@
1
+ module Webbynode
2
+ class AppError < StandardError; end
3
+
4
+ class Application
5
+ attr_reader :command, :params, :aliases
6
+
7
+ def initialize(*args)
8
+ args = ["help", "commands"] unless args.any?
9
+
10
+ @command = args.shift
11
+ @params = args
12
+ end
13
+
14
+ def execute
15
+ if command_class = Webbynode::Command.for(command)
16
+ cmd = command_class.new(*params)
17
+ cmd.run
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,332 @@
1
+ require 'jcode'
2
+
3
+ module Webbynode
4
+ class Command
5
+ Aliases = {}
6
+ Settings = {}
7
+
8
+ InvalidOption = Class.new(StandardError)
9
+ InvalidCommand = Class.new(StandardError)
10
+ CommandError = Class.new(StandardError)
11
+
12
+ def Command.inherited(child)
13
+ Settings[child] ||= {
14
+ :parameters_hash => {},
15
+ :options_hash => {},
16
+ :parameters => [],
17
+ :options => []
18
+ }
19
+ end
20
+
21
+ class << self
22
+ # classes that requires checking
23
+ # for webbynode init must call
24
+ # this method
25
+ def requires_initialization!
26
+ Settings[self][:requires_initialization!] = true
27
+ end
28
+
29
+ def requires_options!
30
+ Settings[self][:requires_options!] = true
31
+ end
32
+
33
+ def requires_pushed_application!
34
+ Settings[self][:requires_pushed_application!] = true
35
+ end
36
+
37
+ def description(s)
38
+ Settings[self][:description] = s
39
+ end
40
+
41
+ def summary(s)
42
+ Settings[self][:summary] = s
43
+ end
44
+
45
+ def setting(s)
46
+ Settings[self][s]
47
+ end
48
+
49
+ def parameter(*args)
50
+ param = Parameter.new(*args)
51
+ Settings[self][:parameters] << param
52
+ Settings[self][:parameters_hash][param.name] = param
53
+ end
54
+
55
+ def option(*args)
56
+ option = Option.new(*args)
57
+ Settings[self][:options] << option
58
+ Settings[self][:options_hash][option.name] = option
59
+ end
60
+
61
+ def class_for(command)
62
+ Webbynode::Commands.const_get command_class_name(command)
63
+ end
64
+
65
+ def for(command)
66
+ begin
67
+ class_for(command)
68
+ rescue NameError
69
+
70
+ # Assumes Command Not Found
71
+ # Will attempt to find/read possible aliases that might
72
+ # have been set up by the user
73
+ if File.directory?('.webbynode')
74
+ a = Webbynode::Commands::Alias.new
75
+ a.read_aliases_file
76
+ if a.exists?(command)
77
+ remote_command = a.extract_command(command)
78
+ r = Webbynode::Commands::Remote.new(remote_command)
79
+ r.execute
80
+ return
81
+ end
82
+ end
83
+
84
+ # If no aliases:
85
+ puts "Command \"#{command}\" doesn't exist"
86
+ end
87
+ end
88
+
89
+ def add_alias(alias_name)
90
+ Aliases[alias_name] = self.name.split("::").last
91
+ end
92
+
93
+ def command_class_name(command)
94
+ return Aliases[command] if Aliases[command]
95
+ class_name = command.split("_").inject([]) { |arr, item| arr << item.capitalize }.join("")
96
+ end
97
+ end
98
+
99
+ def initialize(*args)
100
+ parse_args(args)
101
+ rescue InvalidCommand, CommandError
102
+ @parse_error = $!.message
103
+ end
104
+
105
+ def self.command
106
+ str = ""
107
+ self.name.split("::").last.each_char do |ch|
108
+ str << "_" if ch.match(/[A-Z]/) and !str.empty?
109
+ str << ch.downcase
110
+ end
111
+ str
112
+ end
113
+
114
+ def param(p)
115
+ params_hash[p].value if params_hash[p]
116
+ end
117
+
118
+ def option(p)
119
+ raise CommandError, "Unknown option: #{p}." unless options[p]
120
+ options[p].value if options[p]
121
+ end
122
+
123
+ def params_hash
124
+ settings[:parameters_hash]
125
+ end
126
+
127
+ def options
128
+ settings[:options_hash]
129
+ end
130
+
131
+ def params
132
+ settings[:parameters]
133
+ end
134
+
135
+ def param_values
136
+ settings[:parameters].map { |p| p.value }
137
+ end
138
+
139
+ def self.summary_help
140
+ Settings[self][:summary]
141
+ end
142
+
143
+ def self.usage
144
+ help = "Usage: webbynode #{command}"
145
+ if (params = Settings[self][:parameters])
146
+ params.each do |p|
147
+ help << " #{p.to_s}"
148
+ end
149
+ end
150
+
151
+ help << " [options]" if (Settings[self][:options] || []).any?
152
+ help
153
+ end
154
+
155
+ def self.params_help
156
+ help = []
157
+ if (params = Settings[self][:parameters])
158
+ help << "Parameters:"
159
+ params.each do |p|
160
+ help << " #{p.name.to_s.ljust(20)}#{p.desc}#{p.required? ? "" : ", optional"}"
161
+ end
162
+ end
163
+ help.join("\n")
164
+ end
165
+
166
+ def self.options_help
167
+ help = []
168
+ if (options = Settings[self][:options] || []).any?
169
+ help << "Options:"
170
+ options.each do |p|
171
+ help << " #{p.to_s.ljust(20)}#{p.desc}#{p.required? ? "" : ", optional"}"
172
+ end
173
+ end
174
+ help.join("\n")
175
+ end
176
+
177
+ def self.help
178
+ help = []
179
+ help << summary_help if summary_help
180
+ help << usage
181
+ help << params_help if Settings[self][:parameters].any?
182
+ help << options_help if (Settings[self][:options] || []).any?
183
+
184
+ help.join("\n")
185
+ end
186
+
187
+ def io
188
+ @@io ||= Webbynode::Io.new
189
+ end
190
+
191
+ def git
192
+ @@git ||= Webbynode::Git.new
193
+ end
194
+
195
+ def server
196
+ @server ||= Webbynode::Server.new(git.parse_remote_ip)
197
+ end
198
+
199
+ def remote_executor
200
+ @remote_executor ||= Webbynode::RemoteExecutor.new(git.parse_remote_ip)
201
+ end
202
+
203
+ def pushand
204
+ @pushand ||= PushAnd.new
205
+ end
206
+
207
+ def api
208
+ @@api ||= Webbynode::ApiClient.new
209
+ end
210
+
211
+ def notify(msg)
212
+ Webbynode::Notify.message(msg)
213
+ end
214
+
215
+ def yes?(question)
216
+ answer = ask(question).downcase
217
+ return true if %w[y yes].include?(answer)
218
+ return false if %w[n no].include?(answer)
219
+ exit
220
+ end
221
+
222
+ def no?(question)
223
+ answer = ask(question).downcase
224
+ return true if %w[n no].include?(answer)
225
+ return false if %w[y yes].include?(answer)
226
+ exit
227
+ end
228
+
229
+ def validate_initialization
230
+ raise CommandError,
231
+ "Ahn!? Hello, McFly, anybody home?" unless git.present?
232
+ raise CommandError,
233
+ "Webbynode has not been initialized for this git repository." unless git.remote_webbynode?
234
+ raise CommandError,
235
+ "Could not find .webbynode folder, has Webbynode been initialized for this repository?" unless io.directory?('.webbynode')
236
+ raise CommandError,
237
+ "Could not find .pushand file, has Webbynode been initialized for this repository?" unless pushand.present?
238
+ end
239
+
240
+ def validate_options
241
+ raise Webbynode::Commands::NoOptionsProvided,
242
+ "No remote options were provided." if params.empty?
243
+ end
244
+
245
+ def settings
246
+ Settings[self.class] || {}
247
+ end
248
+
249
+ def run
250
+ if @parse_error
251
+ puts "#{@parse_error} Use \"webbynode help #{self.class.command}\" for more information."
252
+ puts self.class.usage
253
+ return
254
+ end
255
+
256
+ if @help
257
+ puts self.class.help
258
+ return
259
+ end
260
+
261
+ begin
262
+ validate_initialization if settings[:requires_initialization!]
263
+ validate_options if settings[:requires_options!]
264
+ execute
265
+ rescue Webbynode::ApiClient::Unauthorized
266
+ puts "Your credentials didn't match any Webbynode account."
267
+ rescue CommandError
268
+ # io.log $!
269
+ puts $!
270
+ end
271
+ end
272
+
273
+ private
274
+
275
+ def parse_args(args)
276
+ settings[:options].each { |o| o.reset! }
277
+ settings[:parameters].each { |p| p.reset! }
278
+
279
+ i = 0
280
+ while (opt = args.shift)
281
+ if opt == "--help"
282
+ @help = true
283
+ return
284
+ elsif (name = Option.name_for(opt))
285
+ option = settings[:options_hash][name.to_sym]
286
+ raise Webbynode::Command::CommandError, "Unknown option: #{name.to_sym}." unless option
287
+ option.parse(opt)
288
+ else
289
+ raise InvalidCommand, "command '#{self.class.command}' takes no parameters" if settings[:parameters].empty?
290
+
291
+ if settings[:parameters][i].array?
292
+ settings[:parameters][i].value << opt
293
+ else
294
+ settings[:parameters][i].value = opt
295
+ i += 1
296
+ end
297
+ end
298
+ end
299
+
300
+ # If help is invoked without any arguments, the first argument will
301
+ # be set to "commands" so it will always display a list of available commands.
302
+ if self.class.command.eql?("help") and param(:command).blank?
303
+ settings[:parameters][0].value = "commands"
304
+ end
305
+
306
+ settings[:parameters].each { |p| p.validate! }
307
+ end
308
+
309
+ def handle_dns(dns)
310
+ url = Domainatrix.parse("http://#{dns}")
311
+ ip = git.parse_remote_ip
312
+
313
+ if url.subdomain.empty?
314
+ dns = "#{url.domain}.#{url.public_suffix}"
315
+ io.log "Creating DNS entries for www.#{dns} and #{dns}..."
316
+ io.add_setting "dns_alias", "'www.#{dns}'"
317
+ api.create_record "#{dns}", ip
318
+ api.create_record "www.#{dns}", ip
319
+ else
320
+ io.log "Creating DNS entry for #{dns}..."
321
+ io.remove_setting "dns_alias"
322
+ api.create_record dns, ip
323
+ end
324
+ rescue Webbynode::ApiClient::ApiError
325
+ if $!.message =~ /Data has already been taken/
326
+ io.log "The DNS entry for '#{dns}' already existed, ignoring."
327
+ else
328
+ io.log "Couldn't create your DNS entry: #{$!.message}"
329
+ end
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,33 @@
1
+ module Webbynode::Commands
2
+ class AddBackup < Webbynode::Command
3
+ summary "Configures automatic nightly backups for the current application"
4
+ option :retain, "Number of backups to retain on S3 (one backup per day), default is 30", :take => :days
5
+
6
+ def execute
7
+ key = io.general_settings['aws_key']
8
+ secret = io.general_settings['aws_secret']
9
+
10
+ unless key and secret
11
+ puts io.read_from_template("backup")
12
+
13
+ key = ask("AWS key: ")
14
+ secret = ask("AWS secret: ") unless key.blank?
15
+
16
+ if key.blank? or secret.blank?
17
+ puts
18
+ puts "Aborted."
19
+ return
20
+ end
21
+
22
+ io.add_general_setting("aws_key", key)
23
+ io.add_general_setting("aws_secret", secret)
24
+ end
25
+
26
+ app_name = io.app_name
27
+ io.log "Configuring backup for #{app_name}...", :start
28
+
29
+ retain = option(:retain)
30
+ remote_executor.exec %Q(config_app_backup #{app_name} "#{key}" "#{secret}"#{retain.blank? ? "" : " #{retain}"}), true
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ module Webbynode::Commands
2
+ class AddKey < Webbynode::Command
3
+ requires_initialization!
4
+
5
+ summary "Adds your ssh public key to your Webby, making deployments easy"
6
+ option :passphrase, "If present, passphrase will be used when creating a new SSH key", :take => :words
7
+
8
+ LocalSshKey = "#{ENV['HOME']}/.ssh/id_rsa.pub"
9
+
10
+ add_alias "addkey"
11
+
12
+ def execute
13
+ server.add_ssh_key LocalSshKey, options[:passphrase].value
14
+ io.log "Your local SSH Key has been added to your webby!", :notify
15
+
16
+ rescue Webbynode::InvalidAuthentication
17
+ io.log "Could not connect to webby: invalid authentication.", true
18
+
19
+ rescue Webbynode::PermissionError
20
+ io.log "Could not create an SSH key: permission error.", true
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,153 @@
1
+ module Webbynode::Commands
2
+ class Alias < Webbynode::Command
3
+
4
+ attr_accessor :action, :alias, :command, :session_aliases
5
+
6
+ add_alias "aliases"
7
+
8
+ requires_initialization!
9
+
10
+ summary "Manages a list of alias for your common used remote commands"
11
+ parameter :action, String, "add, remove or show",
12
+ :required => true,
13
+ :validate => { :in => ['add', 'remove', 'show' ]}
14
+ parameter :alias, String, "name of the alias", :required => false
15
+ parameter :command, Array, "command to be executed", :required => false
16
+
17
+ FilePath = ".webbynode/aliases"
18
+
19
+ def initialize(*args)
20
+ super
21
+ @session_aliases = Array.new
22
+
23
+ # Ensures that the aliases file exists inside the .webbynode/ folder
24
+ ensure_aliases_file_exists
25
+ end
26
+
27
+ def execute
28
+
29
+ # Reads out the aliases from the aliases file and stores them in session_aliases
30
+ read_aliases_file
31
+
32
+ # Parses the parameters that were provided by the user
33
+ parse_parameters
34
+
35
+ # Initializes the specified action
36
+ send(action)
37
+
38
+ end
39
+
40
+ # Reads out the aliases file and stores all the aliases inside the session_aliases array
41
+ def read_aliases_file
42
+ @session_aliases = Array.new
43
+ io.read_file(FilePath).each_line do |line|
44
+ if line =~ /\[(.+)\] (.+)/
45
+ @session_aliases << "[#{$1}] #{$2}"
46
+ end
47
+ end
48
+ end
49
+
50
+ # Determines whether an alias already exists inside the session_aliases array
51
+ def exists?(a)
52
+ session_aliases.each do |session_alias|
53
+ if session_alias =~ /\[(.+)\]/
54
+ return true if $1.eql?(a)
55
+ end
56
+ end
57
+ false
58
+ end
59
+
60
+ # Ensures that the aliases file exists
61
+ # If the file does not exist, it will be created
62
+ def ensure_aliases_file_exists
63
+ unless io.file_exists?(FilePath)
64
+ io.exec("touch #{FilePath}")
65
+ end
66
+ end
67
+
68
+ def extract_command(a)
69
+ session_aliases.each do |session_alias|
70
+ if session_alias =~ /\[(.+)\] (.+)/
71
+ return $2 if a.eql?($1)
72
+ end
73
+ end
74
+ false
75
+ end
76
+
77
+ private
78
+
79
+ # Parses the paramters provided by the user
80
+ def parse_parameters
81
+ @action = param(:action)
82
+ @alias = param(:alias)
83
+ @command = param(:command).join(" ")
84
+ end
85
+
86
+ # Adds/Writes a new alias to the aliases file
87
+ def add
88
+ append_alias
89
+ write_aliases
90
+ show_aliases
91
+ end
92
+
93
+ # Removes an alias from the aliases file
94
+ def remove
95
+ remove_alias
96
+ write_aliases
97
+ show_aliases
98
+ end
99
+
100
+ # Displays the list of currently inserted aliases
101
+ def show
102
+ show_aliases
103
+ end
104
+
105
+ # Writes all aliases from the session_aliases array to the file
106
+ # It will completely overwrite the existing file
107
+ def write_aliases
108
+ io.open_file(FilePath, "w") do |file|
109
+ session_aliases.each do |a|
110
+ file << a + "\n"
111
+ end
112
+ end
113
+ end
114
+
115
+ # Appends an alias to the session_aliases unless..
116
+ # - There is no command provided for the alias
117
+ # - There is already an alias that exists with the same name
118
+ def append_alias
119
+ if !command.blank? and !exists?(@alias)
120
+ notify("Alias added:\n[#{@alias}] #{command}")
121
+ @session_aliases << "[#{@alias}] #{command}"
122
+ else
123
+ io.log("You must provide a remote command for the alias.", true) if command.blank?
124
+ io.log("You already have an alias named [#{@alias}].", true) if exists?(@alias)
125
+ end
126
+ end
127
+
128
+ # Removes the specified alias from the session_aliases if it exists
129
+ def remove_alias
130
+ tmp_aliases = @session_aliases
131
+ @session_aliases = Array.new
132
+ tmp_aliases.each do |a|
133
+ if a =~ /\[(.+)\] .+/
134
+ @session_aliases << a unless $1.eql?(@alias)
135
+ notify("Alias removed: [#{@alias}]") if $1.eql?(@alias)
136
+ end
137
+ end
138
+ end
139
+
140
+ # Outputs every alias from the session_aliases to the user
141
+ def show_aliases
142
+ if session_aliases.any?
143
+ io.log "These are your current aliases.."
144
+ session_aliases.each do |a|
145
+ io.log a
146
+ end
147
+ else
148
+ io.log "You have not yet set up any aliases.", true
149
+ end
150
+ end
151
+
152
+ end
153
+ end