do 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in do.gemspec
3
+ gem 'rspec'
4
+
4
5
  gemspec
data/README.md CHANGED
@@ -11,14 +11,31 @@ So why another one? Basically I need:
11
11
  * see perfectly what's happening on my remote servers
12
12
  * highly focus on smart actions, upload, download, sudo, replace.
13
13
  * manage easily more than one server at same time
14
- * use same syntax to manage local tasks
14
+ * a use same syntax to manage local tasks
15
+
16
+ What really is *DO* ?
17
+
18
+ * some like brew
19
+ * some like rake
20
+ * some like capistrano
21
+
22
+ All togheter mixed to make your life easier.
23
+
24
+ As mentioned before do is a fun mix of capistrano, rake, thor and brew.
25
+
26
+ With *DO* you are be able to do easily common task on your local or remote machine.
27
+ The aim of *DO* is to become the unique and universal tool language that permit you to make
28
+ your own _brew_, _apt-get_ or _yum_ package, same syntax for all your machine.
15
29
 
16
30
  ## DO - Installation and Setup
17
31
 
18
32
  ```sh
19
33
  $ sudo gem install do
20
- $ doit setup # setup DO directory
21
- $ doit -T # show DO tasks
34
+ $ doit download # download a new recipe with --url=
35
+ $ doit setup # setup a working home directory
36
+ $ doit version # show version number
37
+ $ doit list # show task list
38
+ $ doit help # show help message
22
39
  ```
23
40
 
24
41
  Now you can edit your `~/.do/dorc` adding your **servers** or **plugins**.
@@ -135,7 +152,7 @@ plugin :vim, 'https://raw.github.com/DAddYE/.do/master/vim.rake'
135
152
  However we have a `doit` command for that:
136
153
 
137
154
  ```sh
138
- $ doit download[https://raw.github.com/DAddYE/.do/master/l.rake]
155
+ $ doit download --url https://raw.github.com/DAddYE/.do/master/l.rake
139
156
  ```
140
157
 
141
158
  This command add for you a new line in your `~/.do/dorc` and perform:
@@ -150,11 +167,7 @@ file.
150
167
  Once this happen you are be able to see new tasks:
151
168
 
152
169
  ```sh
153
- $ doit -T
154
-
155
- ************************************************************
156
- * DO - IT! *
157
- ************************************************************
170
+ $ doit list
158
171
 
159
172
  doit plugin:vim # install vim plugin
160
173
  doit setup # setup a working home directory
@@ -184,7 +197,7 @@ I've also some recipes in my `~/.do` path:
184
197
  # ~/.do/configure.rake
185
198
  namespace :configure
186
199
  desc "upgrade rubygems and install useful gems"
187
- task :gems => :ree do
200
+ task :gems => :ree, :in => :web do
188
201
  run "gem update --system" if yes?("Do you want to update rubygems?")
189
202
  run "gem install rake"
190
203
  run "gem install highline"
@@ -193,18 +206,18 @@ namespace :configure
193
206
  end
194
207
 
195
208
  desc "create motd for each server"
196
- task :motd do
209
+ task :motd, :in => :remote do
197
210
  replace :all, "Hey boss! Welcome to the \e[1m#{name}\e[0m of LipsiaSOFT s.r.l.\n", "/etc/motd"
198
211
  end
199
212
 
200
213
  desc "redirect emails to a real account"
201
- task :root_emails do
214
+ task :root_emails, :in => :remote do
202
215
  append "\nroot: servers@lipsiasoft.com", "/etc/aliases"
203
216
  run "newaliases"
204
217
  end
205
218
 
206
219
  desc "mysql basic configuration"
207
- task :mysql => :yum do
220
+ task :mysql => :yum, :in => :remote do
208
221
  run "yum install mysql-server mysql mysql-devel -y"
209
222
  run "chkconfig --level 2345 mysqld on"
210
223
  run "service mysqld restart"
@@ -228,14 +241,14 @@ $ doit configure:mysql
228
241
  any task, ex:
229
242
 
230
243
  ```rb
231
- task :mysql => :yum do; ...; end
244
+ task :mysql => :yum, :in => :remote do; ...; end
232
245
  ```
233
246
 
234
247
  That's are some local tasks:
235
248
 
236
249
  ```rb
237
250
  namespace :l do
238
- local :setup do
251
+ task :setup do
239
252
  name = File.basename(File.expand_path('.'))
240
253
  exit unless yes?('Do you want to setup "%s"?' % name)
241
254
  srv = nil
@@ -246,18 +259,18 @@ namespace :l do
246
259
 
247
260
  if File.exist?('.git')
248
261
  exit unless yes?('Project "%s" has already a working repo, do you want remove it?' % name)
249
- sh 'rm -rf .git'
262
+ run 'rm -rf .git'
250
263
  end
251
264
 
252
- sh 'git init'
253
- sh 'git remote add origin git@lipsiasoft.biz:/%s.git' % name
254
- Rake::Task['l:commit'].invoke if yes?("Are you ready to commit it, database, config etc is correct?")
265
+ run 'git init'
266
+ run 'git remote add origin git@lipsiasoft.biz:/%s.git' % name
267
+ run_task('l:commit') if yes?("Are you ready to commit it, database, config etc is correct?")
255
268
  end
256
269
 
257
- local :commit do
258
- sh 'git add .'
259
- sh 'git commit -a'
260
- sh 'git push origin master'
270
+ task :commit do
271
+ run 'git add .'
272
+ run 'git commit -a'
273
+ run 'git push origin master'
261
274
  end
262
275
  end
263
276
  ```
@@ -277,8 +290,8 @@ standard rake tasks. *DO* extend `Rake`.
277
290
  Sometimes you want to perform a task only on some servers:
278
291
 
279
292
  ```sh
280
- $ doit configure:new --only-srv1 --only-srv2
281
- $ doit configure:new --except-srv1
293
+ $ doit configure:new --srv1 # apply recipes only on srv1
294
+ $ doit configure:new --no-srv1 # apply recipes to all except srv1
282
295
  ```
283
296
 
284
297
  ## DO - Output (Awesome...)
data/Rakefile CHANGED
@@ -1,8 +1,14 @@
1
1
  #!/usr/bin/env rake
2
- require 'bundler/setup'
2
+ require 'rubygems' unless defined?(Gem)
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
 
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.rspec_opts = %w(-fs --color --fail-fast)
8
+ end
9
+
10
+ task :default => :spec
11
+
6
12
  %w(install release).each do |task|
7
13
  Rake::Task[task].enhance do
8
14
  sh "rm -rf pkg"
@@ -20,12 +26,3 @@ task :bump do
20
26
  end
21
27
 
22
28
  task :release => :bump
23
-
24
- desc "Run complete application spec suite"
25
- RSpec::Core::RakeTask.new("spec") do |t|
26
- t.skip_bundler = true
27
- t.pattern = './spec/**/*_spec.rb'
28
- t.rspec_opts = %w(-fs --color --fail-fast)
29
- end
30
-
31
- task :default => :spec
data/bin/doit CHANGED
@@ -1,30 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  $:.push File.expand_path("../../lib", __FILE__)
3
3
  require 'rubygems' unless defined?(Gem)
4
- require 'rake/dsl_definition'
5
- require 'rake'
6
4
  require 'do'
7
5
 
8
- ARGV << "-T" if ARGV.empty?
9
-
10
- only = ARGV.map { |a| a =~ /--only-(.*)/ && $1.to_sym }.compact
11
- except = ARGV.map { |a| a =~ /--except-(.*)/ && $1.to_sym }.compact
12
-
13
- ARGV.delete_if { |a| a =~ /--(only|except)/ }
14
-
15
- puts "\e[32m"
16
- puts "*" * 60
17
- puts "*" + "DO - IT!".center(58) + "*"
18
- puts "*" * 60
19
- puts "\e[0m"
20
-
21
- Rake.application.init
22
- Rake.application.instance_variable_set(:@name, 'doit')
23
- load(File.expand_path('../../lib/do/commands.rb', __FILE__))
24
- DO.recipes.each { |recipe| Rake.application.add_import(recipe) }
25
- Rake.application.load_imports
26
-
27
- servers.delete_if { |server| !only.include?(server.name) } unless only.empty?
28
- servers.delete_if { |server| except.include?(server.name) }
29
-
30
- Rake.application.top_level
6
+ DO::CLI.start(*ARGV)
data/do.gemspec CHANGED
@@ -14,10 +14,8 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "do"
15
15
  gem.require_paths = ['lib']
16
16
  gem.version = DO::VERSION
17
- gem.add_dependency "rake", "~>0.9.2"
18
17
  gem.add_dependency "net-ssh", "~>2.1.4"
19
18
  gem.add_dependency "net-sftp", "~>2.0.5"
20
- gem.add_development_dependency "rspec"
21
19
 
22
20
  gem.post_install_message = "\e[32m" + ("*" * 60) + "\n"
23
21
  gem.post_install_message += "*" + "DO - IT! $ doit setup".center(58) + "*" + "\n"
data/lib/do/cli.rb ADDED
@@ -0,0 +1,14 @@
1
+ module DO
2
+ module CLI
3
+ extend self
4
+
5
+ def start(*args)
6
+ DO::Commands.load_recipes
7
+ args.empty? ? DO::Commands.run_task(:help) : DO::Commands.task_run(*args)
8
+ rescue DO::Tasks::NotFound
9
+ puts "\e[31mSorry, \e[1m'%s'\e[0m\e[31m was not found, see available tasks:\e[0m" % args.join(' ')
10
+ puts
11
+ DO::Commands.run_task(:list)
12
+ end
13
+ end # CLI
14
+ end # DO
data/lib/do/commands.rb CHANGED
@@ -1,11 +1,10 @@
1
- require 'rake/dsl_definition'
2
- require 'rake'
3
-
4
1
  module DO
5
2
  module Commands
6
- include Rake::DSL
3
+ include DO::Tasks
7
4
  include DO::Utils
8
5
 
6
+ extend self
7
+
9
8
  ##
10
9
  # Array of DO::Server defined in our tasks
11
10
  #
@@ -13,11 +12,8 @@ module DO
13
12
  @_servers ||= []
14
13
  end
15
14
 
16
- ##
17
- # An array of DO::Server selected by our remote task
18
- #
19
- def servers_selected
20
- @_servers_selected ||=[]
15
+ def remote
16
+ servers.map(&:name)
21
17
  end
22
18
 
23
19
  ##
@@ -27,6 +23,40 @@ module DO
27
23
  @_current_server
28
24
  end
29
25
 
26
+ ##
27
+ # Set an option to the given value
28
+ #
29
+ def set(option, value)
30
+ define_method(option) { value }
31
+ end
32
+
33
+ ##
34
+ # DO loads rakefiles in these locations:
35
+ #
36
+ # ~/do/dorc
37
+ # ~/do/*.rake
38
+ # ./Do
39
+ # ./Dofile
40
+ #
41
+ # DO_PATH, default is ~/do.
42
+ #
43
+ def recipes
44
+ @_recipes ||= (
45
+ %w[dorc **/*.rake].map { |f| Dir[File.join(DO_PATH, f)] }.flatten +
46
+ %w[./Do ./Dofile].map { |f| File.expand_path(f) } <<
47
+ File.expand_path('../common.rb', __FILE__)
48
+ ).reject { |f| !File.exist?(f) }
49
+ end
50
+
51
+ def load_recipes
52
+ recipes.each { |f| load_recipe(f) }
53
+ end
54
+
55
+ def load_recipe(path)
56
+ instance_eval(File.read(path), __FILE__, __LINE__)
57
+ end
58
+ alias :load :load_recipe
59
+
30
60
  ##
31
61
  # This method define our servers
32
62
  #
@@ -39,7 +69,20 @@ module DO
39
69
  #
40
70
  def server(name, host, user, options={})
41
71
  servers.push(DO::Server.new(name, host, user, options))
42
- local(name) { servers_selected.replace(servers.select { |s| s.name == name }) }
72
+ task name do |opts, b|
73
+ allowed = opts.map { |k,v| k if remote.include?(k) && v }.compact
74
+ denied = opts.map { |k,v| k if remote.include?(k) && v == false }.compact
75
+ if (allowed.empty? && denied.empty?) ||
76
+ (!allowed.empty? && allowed.include?(name)) ||
77
+ (!denied.empty? && !denied.include?(name))
78
+ @_current_server = servers.find { |s| s.name == name }
79
+ begin
80
+ b.arity == 1 ? b.call(opts) : b.call
81
+ ensure
82
+ @_current_server = nil
83
+ end
84
+ end
85
+ end
43
86
  end
44
87
 
45
88
  ##
@@ -52,95 +95,33 @@ module DO
52
95
  #
53
96
  def plugin(name, repo)
54
97
  desc "install #{name} plugin"
55
- local("plugin:#{name}" => :setup) do
56
- log "\e[36m## Installing plugin %s\e[0m" % name
57
- Dir.mkdir(DO_PATH) unless File.exist?(DO_PATH)
58
- sh "curl --location --progress-bar #{repo} > #{File.join(DO_PATH, '%s.rake' % name)}"
98
+ namespace :plugin do
99
+ task(name => :setup) do
100
+ log "\e[36m## Installing plugin %s\e[0m" % name
101
+ Dir.mkdir(DO_PATH) unless File.exist?(DO_PATH)
102
+ path = File.join(DO_PATH, '%s.rake' % name)
103
+ sh :curl, '--location', '--progress-bar', repo, '>', path
104
+ load_recipe(path)
105
+ end
59
106
  end
60
107
  end
61
108
 
62
109
  ##
63
- # Execute DO::Server operations on remote defined servers.
64
- #
65
- # ==== Examples:
66
- # # Define our ssh connections
67
- # keys = %w[key1.pem key2.pem key3.pem key4.pem]
68
- # server :srv1, 's1.domain.local', 'user', :keys => keys
69
- # server :srv2, 's2.domain.local', 'user', :keys => keys
70
- # server :srv3, 's3.domain.local', 'user', :keys => keys
71
- # server :srv4, 's4.domain.local', 'user', :keys => keys
72
- #
73
- # # => Executes commands only to :srv1, :srv2, :srv3
74
- # remote :name => [:srv1, :srv2, :srv3] do; ...; end
75
- #
76
- # # => Same as above
77
- # task :name => [:srv1, :srv2, :srv3] do; ...; end
78
- #
79
- # # => Executes commands on all defined servers
80
- # remote :name => :servers do; ...; end
81
- # # => Same as above
82
- # remote :name => do; ...; end
83
- # # => Same as above
84
- # task :name do; ...; end
85
- # # => Same as above
86
- # local :name => :servers do; ...; end
87
- #
88
- # # => Execute the task on your machine
89
- # local :name do; sh 'uname'; end
90
- #
91
- # # => Execute commands both on servers side and local side
92
- # remote :name do |t|
93
- # t.run 'run this command on remote servers'
94
- # sh 'run this command on my local machine'
95
- # end
96
- #
97
- # # same of:
98
- #
99
- # task :name do |t|
100
- # t.run 'command on remote servers'
101
- # sh 'command on my local machine'
102
- # end
103
- #
104
- # # => Execute command only on remote server srv1
105
- # task :name => :srv1 do
106
- # run 'command only on remote server srv1'
107
- # end
110
+ # Log text under current_server if available
108
111
  #
109
- def remote(args, &block)
110
- args = { args => :servers } unless args.is_a?(Hash)
111
- local(args) do
112
- name = args.is_a?(Hash) ? args.keys[0] : args
113
- servers_selected.each do |current|
114
- begin
115
- server_was, @_current_server = @_current_server, current
116
- self.class.send(:define_method, name, &block)
117
- method = self.class.instance_method(name)
118
- self.class.send(:remove_method, name)
119
- block.arity == 1 ? method.bind(self).call(current) : method.bind(current).call
120
- ensure
121
- @_current_server = server_was
122
- end # begin
123
- end # servers
124
- end # local
112
+ def log(text="", new_line=true)
113
+ current_server ? current_server.log(text, new_line) : super(text, new_line)
125
114
  end
126
115
 
127
- alias_method :local, :task
128
- alias_method :task, :remote
129
-
130
116
  ##
131
- # Log text under current_server if available
117
+ # Run commands on current_server if available
132
118
  #
133
- def log(text="", new_line=true)
134
- if current_server
135
- current_server.log(text, new_line)
136
- else
137
- text += "\n" if new_line && text[-1] != ?\n
138
- print(text)
139
- end
119
+ def run(*args)
120
+ current_server ? current_server.run(*args) : super(*args)
121
+ end
122
+
123
+ def method_missing(method, *args, &block)
124
+ current_server && current_server.respond_to?(method) ? current_server.send(method, *args) : super(method, *args, &block)
140
125
  end
141
126
  end # Commands
142
127
  end # DO
143
-
144
- self.extend DO::Commands
145
-
146
- load(File.expand_path('../common.rb', __FILE__))
data/lib/do/common.rb CHANGED
@@ -1,41 +1,40 @@
1
1
  ##
2
2
  # Common tasks performed by doit
3
3
  #
4
-
5
- local :servers do
6
- servers_selected.replace(servers)
7
- end
8
-
9
- local :download, [:recipe] => :setup do |t, options|
10
- if options[:recipe]
11
- name = File.basename(options[:recipe], '.rake')
4
+ desc "download a new recipe with --url="
5
+ task :download => :setup do |options|
6
+ if options[:url]
7
+ name = File.basename(options[:url], '.rake')
12
8
  rc = File.join(DO_PATH, 'dorc')
13
9
  buf = File.read(rc)
14
10
 
15
- if buf.include?(options[:recipe])
16
- log "\e[31mYour '\e[1m%s\e[31m' already has the plugin '\e[1m%s\e[0m'" % [rc, options[:recipe]]
11
+ if buf.include?(options[:url])
12
+ log "'\e[1m%s\e[0m' already has plugin '\e[1m%s\e[0m'" % [rc, options[:url]]
13
+ log
17
14
  log "Please run: $ doit plugin:%s" % name
18
15
  exit
19
16
  else
20
- plugin = "plugin :%s, '%s'\n" % [name, options[:recipe]]
17
+ plugin = "plugin :%s, '%s'\n" % [name, options[:url]]
21
18
  File.open(rc, 'a') { |f| f.write plugin }
22
- load(rc)
23
- Rake::Task['plugin:%s' % name].invoke
19
+ load_recipe(rc)
20
+ task_run('plugin:%s' % name)
24
21
  end
25
22
  else
26
23
  log "\e[31mYou must provide a recipe path ex:\e[0m"
27
24
  log
28
- log " $ doit download[https://raw.github.com/DAddYE/.do/master/l.rake]"
25
+ log " $ doit download --url=https://raw.github.com/DAddYE/.do/master/l.rake"
29
26
  log
30
27
  end
31
28
  end
32
29
 
33
30
  desc "setup a working home directory"
34
- local :setup do
31
+ task :setup do |options|
35
32
  Dir.mkdir(DO_PATH) unless File.exist?(DO_PATH)
36
33
  hrc = File.expand_path("~/.dorc")
37
34
  orc = File.join(DO_PATH, 'dorc')
38
- unless File.exist?(orc)
35
+ if File.exist?(orc)
36
+ log "Config already exist in your %s path" % DO_PATH unless options[:dependency]
37
+ else
39
38
  template = <<-RUBY.gsub(/^ {6}/, '')
40
39
  ##
41
40
  # Server definitions
@@ -54,3 +53,35 @@ local :setup do
54
53
  end
55
54
  sh 'ln -s %s %s' % [orc, hrc] unless File.exist?(hrc)
56
55
  end
56
+
57
+ desc "show version number"
58
+ task :version do
59
+ log "\e[1mDO\e[0m version %s" % DO::VERSION
60
+ end
61
+
62
+ desc "show task list"
63
+ task :list do
64
+ formatted = tasks.map { |t| ["\e[1mdoit\e[0m\e[34m %s:%s\e[0m" % [t[:namespace], t[:name]], t[:desc]] }
65
+ formatted.each { |f| f[0].gsub!(/\s:/, ' ') }
66
+ formatted.reject! { |t, desc| desc == '' }
67
+ max = formatted.max { |a,b| a[0].size <=> b[0].size }[0].size
68
+ log formatted.map { |t, desc| "%s \e[0m# %s" % [t.ljust(max+2), desc] }.join("\n")
69
+ end
70
+
71
+ desc "show help message"
72
+ task :help do
73
+ log <<-TEXT.gsub(/^ {4}/, '')
74
+ Usage \e[1mdoit\e[0m task [options]
75
+
76
+ Available Tasks:
77
+
78
+ TEXT
79
+
80
+ run_task(:list)
81
+
82
+ log <<-TEXT.gsub(/^ {4}/, '')
83
+
84
+ Options:
85
+ Each task can accept multiple options
86
+ TEXT
87
+ end
data/lib/do/parser.rb ADDED
@@ -0,0 +1,38 @@
1
+ module DO
2
+ class Parser < Hash
3
+
4
+ def initialize(*args)
5
+ options = {}
6
+ args.each_with_index do |arg, i|
7
+ case arg
8
+ # --foo=bar
9
+ when /=/
10
+ key, value = *arg.split("=")
11
+ options[key.sub(/^-{1,2}/,'').to_sym] = value
12
+ # --no-foo
13
+ when /^-{1,2}no-(.+)/
14
+ options[$1.to_sym] = false
15
+ # --foo bar
16
+ # --foo
17
+ # -foo
18
+ when /^-{1,2}(.+)/
19
+ value = args[i+1] && args[i+1] != /^--/ ? args.delete_at(i+1) : true
20
+ options[$1.to_sym] = value
21
+ end
22
+ end
23
+
24
+ # Automatically map values
25
+ options.each do |k, v|
26
+ case v
27
+ when /^true$/i then options[k] = true
28
+ when /^false$/i then options[k] = false
29
+ when /^\d+$/ then options[k] = v.to_i
30
+ when /^[\d\.]+$/ then options[k] = v.to_f
31
+ when /,/ then options[k] = v.split(",")
32
+ end
33
+ end
34
+
35
+ self.replace(options)
36
+ end
37
+ end # Parser
38
+ end # DO
data/lib/do/server.rb CHANGED
@@ -5,10 +5,7 @@ module DO
5
5
  class Server
6
6
  include DO::Utils
7
7
 
8
- LOG_FORMAT = "\e[36m%s\e[33m@\e[31m%s \e[33m~ \e[35m#\e[0m %s" unless defined?(LOG_FORMAT)
9
-
10
8
  attr_reader :name, :host, :user, :options
11
- attr_accessor :logger
12
9
 
13
10
  ##
14
11
  # Initialize a new DO Server
@@ -20,16 +17,14 @@ module DO
20
17
  #
21
18
  # ==== Examples:
22
19
  # srv1 = DO::Server.new(:srv1, 'srv1.lipsiasoft.biz', 'root', :keys => %w[/path/to/key.pem]
23
- # srv1.logger = StringIO.new # default is STDOUT
24
20
  #
25
21
  def initialize(name, host, user, options={})
26
22
  @name, @host, @user, @options = name, host, user, options
27
- @logger = STDOUT
28
23
  end
29
24
 
30
25
  ##
31
26
  # Method used to print a formatted version of our commands
32
- # using DO::Server::LOG_FORMAT, by default we have a nice
27
+ # using DO::Server::DO_LOGGER_FORMAT, by default we have a nice
33
28
  # colored version like:
34
29
  #
35
30
  # srv1@root ~ # ls -al
@@ -37,11 +32,10 @@ module DO
37
32
  # If you don't like colors or our format feel free to edit:
38
33
  #
39
34
  # ==== Examples:
40
- # DO::Server::LOG_FORMAT = "%s@%s$ %s"
35
+ # DO::Server::DO_LOGGER_FORMAT = "%s@%s$ %s"
41
36
  #
42
37
  def log(text="", new_line=true)
43
- text += "\n" if new_line && text[-1] != ?\n
44
- logger.print LOG_FORMAT % [user, name, text]
38
+ super(DO_LOGGER_FORMAT % [user, name, text], new_line)
45
39
  end
46
40
 
47
41
  ##
@@ -76,21 +70,34 @@ module DO
76
70
  def run(*args)
77
71
  options = args.last.is_a?(Hash) ? args.pop : {}
78
72
  cmd = args.join(" ")
79
- cmd = "su #{options[:as]} -c '#{cmd.gsub(/'/, "\'")}'" if options[:as]
73
+ if options[:as]
74
+ if options[:as] == 'root'
75
+ cmd = "sudo #{cmd.gsub(/'/, "\'")}"
76
+ else
77
+ cmd = "su #{options[:as]} -c '#{cmd.gsub(/'/, "\'")}'"
78
+ end
79
+ end
80
80
  log cmd
81
81
  result = ""
82
- ssh.exec!(cmd) do |channel, stream, data|
83
- result << data
84
- logger.print(data) unless options[:silent]
85
- if options[:input]
86
- match = options[:match] || /^Enter password:/
87
- if data =~ match
88
- options[:input] += "\n" if options[:input][-1] != ?\n
89
- channel.send_data(options[:input])
90
- logger.puts(options[:input]) unless options[:silent]
82
+ ssh.open_channel do |channel|
83
+ channel.request_pty do |c, success|
84
+ raise "could not request pty" unless success
85
+ channel.exec cmd
86
+ channel.on_data do |c_, data|
87
+ result << data
88
+ DO_LOGGER.print(data) unless options[:silent]
89
+ if options[:input]
90
+ match = options[:match] || /password:/i
91
+ if data =~ match
92
+ options[:input] += "\n" if options[:input][-1] != ?\n
93
+ channel.send_data(options[:input])
94
+ DO_LOGGER.puts(options[:input]) unless options[:silent] || data =~ /password:/i
95
+ end
96
+ end
91
97
  end
92
98
  end
93
99
  end
100
+ ssh.loop
94
101
  result.chomp
95
102
  end
96
103