runssh 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.autotest ADDED
@@ -0,0 +1,12 @@
1
+ require 'autotest/fsevent'
2
+ require 'autotest/growl'
3
+
4
+ Autotest.add_hook(:initialize) {|at|
5
+ at.add_exception %r{^\.git} # ignore Version Control System
6
+ at.add_exception %r{^./tmp} # ignore temp files, lest autotest will run again, and again...
7
+ # at.clear_mappings # take out the default (test/test*rb)
8
+ at.add_mapping(%r{^lib/.*\.rb$}) {|f, _|
9
+ Dir['spec/**/*.rb']
10
+ }
11
+ nil
12
+ }
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ html/
2
+ *.tmproj
3
+ .DS_Store
4
+ .rvmrc
5
+ coverage/
6
+ .rake_tasks*
7
+ *.gem
8
+ pkg/
9
+ .rubyamp-config.yml
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in testme.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ runssh (0.2.0.rc.1)
5
+ highline (~> 1.6.1)
6
+ trollop (~> 1.16.2)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ ZenTest (4.4.2)
12
+ autotest (4.4.6)
13
+ ZenTest (>= 4.4.1)
14
+ autotest-fsevent (0.2.4)
15
+ sys-uname
16
+ autotest-growl (0.2.9)
17
+ diff-lcs (1.1.2)
18
+ highline (1.6.1)
19
+ rcov (0.9.9)
20
+ rspec (2.1.0)
21
+ rspec-core (~> 2.1.0)
22
+ rspec-expectations (~> 2.1.0)
23
+ rspec-mocks (~> 2.1.0)
24
+ rspec-core (2.1.0)
25
+ rspec-expectations (2.1.0)
26
+ diff-lcs (~> 1.1.2)
27
+ rspec-mocks (2.1.0)
28
+ sys-uname (0.8.5)
29
+ trollop (1.16.2)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ autotest (~> 4.4.4)
36
+ autotest-fsevent (~> 0.2.3)
37
+ autotest-growl (~> 0.2.6)
38
+ highline (~> 1.6.1)
39
+ rcov (~> 0.9.9)
40
+ rspec (~> 2.1.0)
41
+ runssh!
42
+ trollop (~> 1.16.2)
data/README.rdoc CHANGED
@@ -53,18 +53,16 @@ of bookmarks:
53
53
 
54
54
  You can decide to arrange your bookmarks by customers and/or location
55
55
  and/or internal/external addresses etc. To access a host definition you
56
- specify the full path to that host. In the above example to access _host2_
56
+ specify the full path to that host. In the above example to access <i>host2</i>
57
57
  (e.g, print it's definition) run:
58
58
  runssh print customer1 location1 host2
59
59
 
60
60
  == requirements:
61
- (versions are specified in the gem definition in the Rakefile)
62
-
63
- Runtime:
64
- * Trollop
65
- Development:
66
- * rspec
67
- * rcov
61
+ Dependencies (runtime and development) are specified in <i>runssh.gemspec</i>.
62
+ When installing through gem, dependencies will be installed by default. For
63
+ development, you need to install _bundler_ 1.0.x and run (inside the
64
+ project directory):
65
+ bundle install
68
66
 
69
67
  == License
70
68
  This program is distributed under the GPL v2 license.
@@ -76,12 +74,33 @@ This program is distributed under the GPL v2 license.
76
74
  [0.1.1] Improved docs.
77
75
 
78
76
  == TODO
77
+ * Convert to use thor as parent for RunSSHLib::CLI
79
78
  * Create a _proper_ zsh completion script.
80
79
  * Add scp capabilities
81
80
  * Add tunneling support:
82
81
  1. Configured tunneling
83
82
  2. tunneling defined on the command line.
84
83
  * Remote commands (e.g, with no login).
84
+ * Shell via gateway (connect to a firewall and from there open shell to the host).
85
85
  * Rename (or move) host definition
86
86
  * Maybe replace invoking ssh from the command line with some library.
87
- * Automatic deletion of empty groups.
87
+ * Automatic deletion of empty groups.
88
+
89
+ === Tasks for 0.2
90
+ * Add support for autotest ✓
91
+ * Use Highline for questions ✓
92
+ * Migrate to new ConfigFile:
93
+ 1. Create a new _SshHostDef_ class ✓
94
+ 2. Add version to the config file (use "VERSION" key as string and not as
95
+ symbol (so it won't interfere with the paths) ✓
96
+ 3. Create discovery of config version on initialization:
97
+ * If config file is un-versioned abort the application and suggest
98
+ running with <tt>--update-config</tt> argument. ✓
99
+ 4. Create a update-config method for upgrading the configurations file:
100
+ * Inform the user of backup name. ✓
101
+ * Copy the original to backup. ✓
102
+ * Convert all _HostDef_ instances to _SshHostDef_. ✓
103
+ * Save configuration and inform the user. ✓
104
+ 4. Make sure _VERSION_ is excluded form the listing of groups. ✓
105
+ 5. Convert existing functionality with the new configuration. ✓
106
+ * Add support for remote command. ✓
data/Rakefile CHANGED
@@ -16,49 +16,21 @@
16
16
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
  #
18
18
 
19
- require 'lib/runsshlib'
20
- require 'rubygems'
21
- require 'rake'
19
+ require 'bundler'
22
20
  require 'rake/rdoctask'
23
- require 'rake/gempackagetask'
24
21
  require 'rspec/core/rake_task'
25
22
 
26
- spec = Gem::Specification.new do |s|
27
- s.platform = Gem::Platform::RUBY
28
- s.summary = "CLI utility to bookmark multiple ssh connections with hierarchy."
29
- s.name = 'runssh'
30
- s.version = RunSSHLib::Version::STRING
31
- s.homepage = 'http://github.com/babysnakes/runssh'
32
- s.required_ruby_version = '~> 1.8.7'
33
- s.has_rdoc = true
34
- s.extra_rdoc_files = ['README.rdoc']
35
- s.rdoc_options << '--main' << 'README.rdoc'
36
- s.author = 'Haim Ashkenazi'
37
- s.email = 'haim@babysnakes.org'
38
- s.add_dependency('trollop', '~> 1.16.2')
39
- s.add_development_dependency('rspec', "~> 2.0.1")
40
- s.add_development_dependency('rcov', '~> 0.9.9')
41
- s.require_path = 'lib'
42
- s.executables << 'runssh'
43
- s.files = %w(README.rdoc gpl-2.0.txt Rakefile) + Dir.glob("{lib,bin,spec}/**/*")
44
- s.description = <<EOF
45
- Runssh is a command line utility to help bookmark many
46
- ssh connections in heirarchial groups.
47
- EOF
48
- end
49
-
50
- Rake::GemPackageTask.new(spec) do |pkg|
51
- pkg.need_zip = true
52
- pkg.need_tar = true
53
- end
23
+ Bundler::GemHelper.install_tasks
54
24
 
55
25
  RSpec::Core::RakeTask.new do |t|
56
- t.rcov = true
26
+ t.rcov = ENV['rcov'] == "true" ? true : false
57
27
  t.rcov_opts = %w(--exclude gems\/,spec\/)
28
+ t.name = :specs
58
29
  # t.warning = true # rspec produces too many warnings so it's commented.
59
30
  end
60
31
 
61
32
  Rake::RDocTask.new do |rd|
62
33
  rd.main = "README.rdoc"
63
34
  rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
35
+ rd.options << "-c" << 'UTF-8'
64
36
  end
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/bin/runssh CHANGED
@@ -19,10 +19,12 @@
19
19
  #
20
20
 
21
21
  require 'rubygems'
22
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
22
23
  require 'runsshlib'
23
24
 
24
25
  # verify required versions
25
26
  gem 'trollop', "1.16.2"
27
+ gem 'highline', '1.6.1'
26
28
 
27
29
  # let's clone and reset ARGV for future use
28
30
  args = ARGV.clone
data/lib/runsshlib/cli.rb CHANGED
@@ -28,12 +28,12 @@ module RunSSHLib
28
28
  args.unshift '-h' if args.empty?
29
29
  args.unshift '-h' if args == ['help']
30
30
  @global_options = parse_args(args)
31
+ return if @global_options[:update_config]
31
32
 
32
33
  # workaround to enable 'help COMMAND' functionality.
33
34
  if args.first == 'help'; args.shift; args << '-h'; end
34
35
  # indicate path completion request
35
36
  @completion_requested = args.delete('?')
36
-
37
37
  @cmd = extract_subcommand(args)
38
38
  @options = parse_subcommand(@cmd, args)
39
39
  @c = init_config
@@ -41,12 +41,23 @@ module RunSSHLib
41
41
  @path = args.map { |e| e.to_sym }
42
42
  rescue ConfigError, InvalidSubCommandError, Errno::ENOENT => e
43
43
  Trollop.die e.message
44
+ rescue OlderConfigVersionError => e
45
+ message = <<-EOM
46
+ You seem to use older configuration version. Did you upgrade runssh?
47
+ If so, please run <%= color('runssh [ -f config ] --update-config', :blue) %> in order to
48
+ update your configuration to the current version.
49
+
50
+ Your old configuration will be saved with the suffix <%= color(".#{e.message}", :underline) %>
51
+ EOM
52
+ HighLine.new.say(message)
53
+ abort ''
44
54
  end
45
55
 
46
56
  # run
47
57
  def run
48
- # did the user request completions? if not run the approproate command.
49
- if @completion_requested
58
+ if @global_options[:update_config]
59
+ run_update_config
60
+ elsif @completion_requested
50
61
  puts @c.list_groups(@path)
51
62
  else
52
63
  command_name = 'run_' + @cmd
@@ -92,6 +103,9 @@ Global options:
92
103
  EOS
93
104
  opt :config_file, "alternate config file",
94
105
  :type => :string, :short => :f
106
+ opt :update_config, "update configuration from previous version." +
107
+ " this option should run without COMMAND",
108
+ :short => :U
95
109
  version "RunSSH version #{Version::STRING}"
96
110
  stop_on_unknown
97
111
  end
@@ -119,19 +133,32 @@ EOS
119
133
  def parse_subcommand(cmd, args)
120
134
  case cmd
121
135
  when 'shell'
122
- Trollop::options(args) do
136
+ options = Trollop::options(args) do
123
137
  banner <<-EOS
124
- Usage: runssh [global_options] shell [options] <path>
138
+ Usage: runssh [global_options] shell [options] <path> [-- <remote command>]
125
139
 
126
140
  Connect to the specified host using ssh.
127
141
 
128
142
  <path> : See main help for description of path.
129
143
 
144
+ If you only want to run remote command instead of full shell, you can
145
+ append "-- <remote command>" to the regular command. To list /tmp on a host
146
+ bookmarked as "some host" run:
147
+ runssh shell some host -- ls -l /tmp
148
+
130
149
  Options:
131
150
  EOS
132
151
  opt :login, "override the login in the configuration",
133
152
  :type => :string
153
+ stop_on "--"
134
154
  end
155
+ # handle the case of remote command (indicated by --)
156
+ if ind = args.index("--")
157
+ rmt = args.slice!(ind, args.size - ind)
158
+ rmt.delete_at(0) # remove --
159
+ options[:remote_cmd] = rmt.join(" ")
160
+ end
161
+ options
135
162
  when 'add'
136
163
  Trollop::options(args) do
137
164
  banner <<-EOS
@@ -147,8 +174,8 @@ Options:
147
174
  EOS
148
175
  opt :host_name, 'The name or address of the host (e.g, host.example.com)',
149
176
  :short => :n, :type => :string, :required => true
150
- opt :user, 'The user to connect as (optional)',
151
- :short => :u, :type => :string
177
+ opt :login, 'The user to connect as (optional)',
178
+ :type => :string
152
179
  end
153
180
  when 'update'
154
181
  Trollop::options(args) do
@@ -165,8 +192,8 @@ Options:
165
192
  EOS
166
193
  opt :host_name, 'The name or address of the host (e.g, host.example.com)',
167
194
  :short => :n, :type => :string, :required => true
168
- opt :user, 'The user to connect as (optional)',
169
- :short => :u, :type => :string
195
+ opt :login, 'The user to connect as (optional)',
196
+ :type => :string
170
197
  end
171
198
  when 'del'
172
199
  Trollop::options(args) do
@@ -224,32 +251,37 @@ EOS
224
251
  end
225
252
 
226
253
  def init_config
227
- config = @global_options[:config_file] ?
228
- @global_options[:config_file] : DEFAULT_CONFIG
254
+ config = @global_options[:config_file] || DEFAULT_CONFIG
229
255
  ConfigFile.new(config)
230
256
  end
231
257
 
232
258
  def run_shell(path)
233
259
  host = @c.get_host(path)
234
- s = SshBackend.new(host, @options)
235
- s.shell
260
+ # only override if value exist
261
+ # TODO: this works only for some types (e.g, not boolean) but
262
+ # currently this is all we need. We may need to make it better
263
+ # later.
264
+ definition = host.definition.merge(@options) do |key, this, other|
265
+ other ? other : this
266
+ end
267
+ SshBackend.shell(definition)
236
268
  end
237
269
 
238
270
  def run_add(path)
239
271
  # extract the host definition name
240
272
  host = path.pop
241
- @c.add_host_def(path, host,
242
- HostDef.new(@options[:host_name], @options[:user]))
273
+ options = extract_definition @options
274
+ @c.add_host_def(path, host, SshHostDef.new(options))
243
275
  end
244
276
 
245
277
  def run_update(path)
246
- @c.update_host_def(path,
247
- HostDef.new(@options[:host_name], @options[:user]))
278
+ @c.update_host_def(path, SshHostDef.new(extract_definition @options))
248
279
  end
249
280
 
250
281
  def run_del(path)
251
- question = "Are you sure you want to delete \"" + path.join(':') + "\""
252
- if verify_yn(question)
282
+ question = "Are you sure you want to delete \"" + path.join(':') + "\"" +
283
+ "? [yes/no] "
284
+ if HighLine.new.agree(question)
253
285
  @c.delete_path(path)
254
286
  else
255
287
  puts 'canceled'
@@ -258,17 +290,15 @@ EOS
258
290
 
259
291
  def run_print(path)
260
292
  host = @c.get_host(path)
261
- output = "Host definition for: #{path.last}",
262
- " * host: #{host.name}",
263
- " * user: #{host.login ? host.login : 'current user'}"
264
- puts output
293
+ puts "Host definition for: #{path.last}"
294
+ puts host.to_print
265
295
  end
266
296
 
267
297
  # we don't use path here, it's just for easier invocation.
268
298
  def run_import(path)
269
299
  question = "Importing a file OVERWRITES existing configuration. " +
270
- "Are you sure"
271
- if verify_yn(question)
300
+ "Are you sure? [yes/no] "
301
+ if HighLine.new.agree(question)
272
302
  @c.import(@options[:input_file])
273
303
  else
274
304
  puts 'canceled'
@@ -280,13 +310,30 @@ EOS
280
310
  @c.export(@options[:output_file])
281
311
  end
282
312
 
283
- # Verifies a presented question. If response is 'y' it returns
284
- # true, else false.
285
- #
286
- # The supplied question should not include the (y/n)? postfix.
287
- def verify_yn question
288
- print question, " (y/n)? "
289
- gets.chomp == 'y'
313
+ # extract keys relevant for definition of SshHostDef
314
+ def extract_definition options
315
+ valid_definition = [:host_name, :login]
316
+ options.reject do |key, value|
317
+ ! valid_definition.include?(key)
318
+ end
319
+ end
320
+
321
+ # updating configurations
322
+ def run_update_config
323
+ config = @global_options[:config_file] || DEFAULT_CONFIG
324
+ c = ConfigFile.new(config, true)
325
+ result = c.update_config
326
+ if result
327
+ message = <<-EOM
328
+ Your config file is now updated to the approproate version.
329
+ Your old config file is copied to <%= color("#{result}", :blue) %>.
330
+ EOM
331
+ HighLine.new.say(message)
332
+ elsif
333
+ message = "Your configuration seems to be at the appropriate version!" +
334
+ " No update was performed."
335
+ HighLine.new.say(message)
336
+ end
290
337
  end
291
338
  end
292
339
  end
@@ -27,17 +27,27 @@ module RunSSHLib
27
27
  # configuration, but should also be able to import/export
28
28
  # to/from yaml file.
29
29
  class ConfigFile
30
+ Version = 1.0 # Config version
30
31
 
31
32
  # Initialize new ConfigFile. Uses supplied config_file or the default
32
33
  # '~/.runssh'. If file doesn't exist, it issues a warning and creates
33
34
  # a new empty one.
34
- def initialize(config_file)
35
+ def initialize(config_file, old_version=false)
35
36
  @config_file = config_file
36
37
  if File.exists? config_file
37
38
  File.open(config_file) { |io| @config = Marshal.load(io) }
39
+ if ! @config['VERSION']
40
+ raise OlderConfigVersionError, 'none' unless old_version
41
+ elsif @config['VERSION'] > Version
42
+ # This is for the future, to avoid reading more advanced
43
+ # configuration version in an old runssh version
44
+ error = "The configuration file is for a newer version of runssh!"
45
+ raise ConfigError, error
46
+ end
38
47
  else
39
48
  # warn "Config file not found. It must be the first time you run this app..."
40
49
  @config = Hash.new
50
+ @config['VERSION'] = Version
41
51
  save
42
52
  end
43
53
  end
@@ -47,14 +57,14 @@ module RunSSHLib
47
57
  # path:: An array of symbols that represent the path
48
58
  # for the host. e.g, [:client, :datacenter1].
49
59
  # name:: The name of the host definition as symbol.
50
- # host_def:: A HostDef instance.
60
+ # host_def:: A SshHostDef instance.
51
61
  def add_host_def(path, name, host_def)
52
62
  # sanity
53
- raise ConfigError.new('Invalid host definition') unless host_def.instance_of? HostDef
63
+ raise ConfigError.new('Invalid host definition') unless host_def.instance_of? SshHostDef
54
64
 
55
65
  k = path.inject(@config) do |hsh, key|
56
66
  if hsh.include? key
57
- if hsh[key].instance_of? HostDef
67
+ if hsh[key].instance_of? SshHostDef
58
68
  raise ConfigError.new('Cannot override host definition with path!')
59
69
  end
60
70
  hsh[key]
@@ -74,7 +84,7 @@ module RunSSHLib
74
84
  def update_host_def(path, host_def)
75
85
  # sanity
76
86
  raise ConfigError.new('Invalid host definition!') if not
77
- host_def.instance_of? HostDef
87
+ host_def.instance_of? SshHostDef
78
88
 
79
89
  # we need to separate the host name from the path
80
90
  # in order to get the key of the host definition.
@@ -83,7 +93,7 @@ module RunSSHLib
83
93
  raise ConfigError, 'Invalid path!' unless groups
84
94
  if groups.include? host
85
95
  raise ConfigError.new("Cannot overwrite group with host definition") unless
86
- groups[host].instance_of? HostDef
96
+ groups[host].instance_of? SshHostDef
87
97
  groups[host] = host_def
88
98
  else
89
99
  raise ConfigError.new("Host definition doesn't exist!")
@@ -110,7 +120,7 @@ module RunSSHLib
110
120
  def list_groups(path)
111
121
  value = retrieve_path(path, 'Invalid path!')
112
122
  if value.instance_of? Hash
113
- value.keys
123
+ value.keys.reject { |i| i == 'VERSION' }
114
124
  else
115
125
  []
116
126
  end
@@ -124,7 +134,7 @@ module RunSSHLib
124
134
  value = retrieve_path(path, 'Invalid path!')
125
135
  raise ConfigError.new('Invalid path!') unless value
126
136
 
127
- if value[mykey].instance_of? HostDef or value[mykey] == {}
137
+ if value[mykey].instance_of? SshHostDef or value[mykey] == {}
128
138
  value.delete(mykey)
129
139
  elsif not value[mykey]
130
140
  raise ConfigError.new('Invalid path!')
@@ -135,25 +145,46 @@ module RunSSHLib
135
145
  save
136
146
  end
137
147
 
138
- # Export config as YAML to the supplied file.
148
+ # Import config from YAML from the specified file.
139
149
  def import(file)
140
150
  require 'yaml'
141
- @config = YAML.load_file(file)
151
+ config = YAML.load_file(file)
152
+ raise ConfigError, "The imported file is from a different version of " +
153
+ "runssh (config: #{config['VERSION']})! aborting." unless
154
+ config['VERSION'] == Version
155
+ @config = config
142
156
  save
143
157
  end
144
158
 
145
- # Import config from YAML from the specified file.
159
+ # Export config as YAML to the supplied file.
146
160
  def export(file)
147
161
  require 'yaml'
148
162
  File.open(file, 'w') { |out| YAML.dump(@config, out) }
149
163
  end
150
164
 
165
+ # Spacial case - perform update to the configuration. This should
166
+ # later include handling of +all+ versions of the config!
167
+ #
168
+ # Returns the name of the backup file or nil if there was no need
169
+ # for backup.
170
+ def update_config
171
+ return if @config['VERSION'] == Version
172
+ backup_file = @config_file + '.none'
173
+ require 'fileutils'
174
+ new_config = config_none_to_10(@config)
175
+ FileUtils.move(@config_file, backup_file)
176
+ @config = new_config
177
+ @config['VERSION'] = Version
178
+ save
179
+ backup_file
180
+ end
181
+
151
182
  private
152
183
 
153
184
  def save
154
- require 'ftools'
185
+ require 'fileutils'
155
186
  # create backup (File.copy always seems to overwrite existing file)
156
- File.copy(@config_file, @config_file + '.bak') if File.exists? @config_file
187
+ FileUtils.copy(@config_file, @config_file + '.bak') if File.exists? @config_file
157
188
  File.open(@config_file, 'w') { |out| Marshal.dump(@config, out) }
158
189
  end
159
190
 
@@ -163,5 +194,22 @@ module RunSSHLib
163
194
  hsh[ky]
164
195
  end
165
196
  end
197
+
198
+ # convert the config hash from version none (runssh 0.1) to version 1.0
199
+ # group is the hash that holds all the groups/hostdefs (@config).
200
+ def config_none_to_10 group
201
+ group.each do |key, value|
202
+ case
203
+ when value.instance_of?(RunSSHLib::HostDef)
204
+ hsh = Hash.new
205
+ hsh[:host_name] = value.name
206
+ hsh[:login] = value.login if value.login
207
+ group[key] = RunSSHLib::SshHostDef.new(hsh)
208
+ when value.instance_of?(Hash)
209
+ config_none_to_10(value)
210
+ end
211
+ end
212
+ group
213
+ end
166
214
  end
167
215
  end
@@ -18,19 +18,24 @@
18
18
 
19
19
  module RunSSHLib
20
20
 
21
- # A class to handle ssh operations.
22
- class SshBackend
23
- # New backend with host/login details.
24
- def initialize(host_def, overrides)
25
- @host = host_def.name
26
- @user = overrides[:login] ? overrides[:login] : host_def.login
27
- end
21
+ # A collection of ssh procedures.
22
+ module SshBackend
23
+ module_function
28
24
 
29
25
  # run shell on remote host.
30
- def shell
31
- command = "ssh #{@user ? %Q(-l #{@user}) : ''} #{@host}"
26
+ # definition:: A Hash containing required data for
27
+ # making shell connection (e.g., :host_name, :login).
28
+ #
29
+ # For running remote commands add to the _definition_ hash
30
+ # the entire remote command as a string with a +:remote_cmd+ key.
31
+ def shell(definition)
32
+ raise "no hostname" unless definition[:host_name] # should never happen
33
+ command = "ssh "
34
+ command << "-l #{definition[:login]} " if definition[:login]
35
+ command << "#{definition[:host_name]}"
36
+ command << %( -- "#{definition[:remote_cmd]}") if
37
+ (definition[:remote_cmd] && (!definition[:remote_cmd].empty?))
32
38
  exec command
33
39
  end
34
-
35
40
  end
36
41
  end
@@ -0,0 +1,49 @@
1
+ #
2
+ # Copyright (C) 2010 Haim Ashkenazi
3
+ #
4
+ # This program is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU General Public License
6
+ # as published by the Free Software Foundation; either version 2
7
+ # of the License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
+ #
18
+ module RunSSHLib
19
+ class SshHostDef
20
+ attr_reader :definition
21
+
22
+ # Initialize ssh host def with definition.
23
+ #
24
+ # [definition] A hash containing ssh options. <i>:host_name</i> is required.
25
+ # Could also be a hostname (string) for quick defining SshHostDef
26
+ # with only hostname.
27
+ def initialize(definition)
28
+ if definition.instance_of? String
29
+ definition = { :host_name => definition }
30
+ end
31
+ raise ArgumentError, "Missing hostname" unless definition[:host_name]
32
+ @definition = definition
33
+ end
34
+
35
+ # should be equal if @definition is equal
36
+ def ==(other)
37
+ return false if other.nil?
38
+ return false unless other.instance_of? SshHostDef
39
+ definition == other.definition
40
+ end
41
+ alias_method :eql?, :==
42
+
43
+ def to_print
44
+ out = " * host: #{definition[:host_name]}"
45
+ out << "\n * login: #{definition[:login] || 'current user'}"
46
+ out
47
+ end
48
+ end
49
+ end