do 0.0.3 → 0.1.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/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
|
|