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 +2 -1
- data/README.md +38 -25
- data/Rakefile +7 -10
- data/bin/doit +1 -25
- data/do.gemspec +0 -2
- data/lib/do/cli.rb +14 -0
- data/lib/do/commands.rb +71 -90
- data/lib/do/common.rb +47 -16
- data/lib/do/parser.rb +38 -0
- data/lib/do/server.rb +26 -19
- data/lib/do/tasks.rb +66 -0
- data/lib/do/utils.rb +30 -7
- data/lib/do/version.rb +1 -1
- data/lib/do.rb +6 -20
- data/spec/cli_spec.rb +22 -0
- data/spec/commands_spec.rb +157 -0
- data/spec/parser_spec.rb +76 -0
- data/spec/server_spec.rb +2 -4
- data/spec/spec_helper.rb +10 -9
- data/spec/tasks_spec.rb +154 -0
- data/spec/utils_spec.rb +36 -0
- metadata +25 -51
data/Gemfile
CHANGED
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
|
21
|
-
$ doit
|
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
|
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
|
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
|
-
|
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
|
-
|
262
|
+
run 'rm -rf .git'
|
250
263
|
end
|
251
264
|
|
252
|
-
|
253
|
-
|
254
|
-
|
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
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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 --
|
281
|
-
$ doit configure:new --
|
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 '
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
#
|
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
|
110
|
-
|
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
|
-
#
|
117
|
+
# Run commands on current_server if available
|
132
118
|
#
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
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[:
|
16
|
-
log "
|
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[:
|
17
|
+
plugin = "plugin :%s, '%s'\n" % [name, options[:url]]
|
21
18
|
File.open(rc, 'a') { |f| f.write plugin }
|
22
|
-
|
23
|
-
|
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
|
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
|
-
|
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
|
-
|
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::
|
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::
|
35
|
+
# DO::Server::DO_LOGGER_FORMAT = "%s@%s$ %s"
|
41
36
|
#
|
42
37
|
def log(text="", new_line=true)
|
43
|
-
|
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
|
-
|
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.
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
|