dk 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +643 -1
- data/bin/dk +7 -0
- data/dk.gemspec +7 -3
- data/lib/dk/ansi.rb +98 -0
- data/lib/dk/cli.rb +173 -0
- data/lib/dk/config.rb +217 -0
- data/lib/dk/config_runner.rb +24 -0
- data/lib/dk/dk_runner.rb +13 -0
- data/lib/dk/dry_runner.rb +43 -0
- data/lib/dk/has_set_param.rb +42 -0
- data/lib/dk/has_ssh_opts.rb +36 -0
- data/lib/dk/has_the_runs.rb +23 -0
- data/lib/dk/has_the_stubs.rb +116 -0
- data/lib/dk/local.rb +84 -0
- data/lib/dk/null_logger.rb +13 -0
- data/lib/dk/remote.rb +132 -0
- data/lib/dk/runner.rb +202 -0
- data/lib/dk/task.rb +266 -0
- data/lib/dk/task_run.rb +17 -0
- data/lib/dk/test_runner.rb +54 -0
- data/lib/dk/tree_runner.rb +64 -0
- data/lib/dk/version.rb +1 -1
- data/lib/dk.rb +23 -1
- data/test/helper.rb +6 -1
- data/test/support/config/dk.rb +7 -0
- data/test/support/config/task_defs.rb +10 -0
- data/test/support/factory.rb +38 -0
- data/test/support/log/.gitkeep +0 -0
- data/test/system/has_the_stubs_tests.rb +355 -0
- data/test/system/runner_tests.rb +222 -0
- data/test/unit/ansi_tests.rb +40 -0
- data/test/unit/cli_tests.rb +317 -0
- data/test/unit/config_runner_tests.rb +60 -0
- data/test/unit/config_tests.rb +427 -0
- data/test/unit/dk_runner_tests.rb +34 -0
- data/test/unit/dk_tests.rb +49 -0
- data/test/unit/dry_runner_tests.rb +71 -0
- data/test/unit/has_set_param_tests.rb +46 -0
- data/test/unit/has_ssh_opts_tests.rb +81 -0
- data/test/unit/has_the_runs_tests.rb +37 -0
- data/test/unit/has_the_stubs_tests.rb +279 -0
- data/test/unit/local_tests.rb +174 -0
- data/test/unit/null_logger_tests.rb +17 -0
- data/test/unit/remote_tests.rb +330 -0
- data/test/unit/runner_tests.rb +398 -0
- data/test/unit/task_run_tests.rb +40 -0
- data/test/unit/task_tests.rb +943 -0
- data/test/unit/test_runner_tests.rb +189 -0
- data/test/unit/tree_runner_tests.rb +152 -0
- metadata +106 -9
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'much-plugin'
|
2
|
+
require 'dk/local'
|
3
|
+
require 'dk/remote'
|
4
|
+
|
5
|
+
module Dk
|
6
|
+
|
7
|
+
module HasTheStubs
|
8
|
+
include MuchPlugin
|
9
|
+
|
10
|
+
plugin_included do
|
11
|
+
include InstanceMethods
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
|
17
|
+
# cmd stub api
|
18
|
+
|
19
|
+
def local_cmd_stubs
|
20
|
+
@local_cmd_stubs ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def stub_cmd(cmd_str, args = nil, &block)
|
24
|
+
args ||= {}
|
25
|
+
|
26
|
+
cmd_str_proc = get_cmd_ssh_proc(cmd_str)
|
27
|
+
input_proc = get_cmd_ssh_proc(args[:input])
|
28
|
+
given_opts_proc = get_cmd_ssh_proc(args[:opts])
|
29
|
+
|
30
|
+
local_cmd_stubs.unshift(
|
31
|
+
Stub.new(cmd_str_proc, input_proc, given_opts_proc, block)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def unstub_all_cmds
|
36
|
+
local_cmd_stubs.clear
|
37
|
+
end
|
38
|
+
|
39
|
+
# ssh stub API
|
40
|
+
|
41
|
+
def remote_cmd_stubs
|
42
|
+
@remote_cmd_stubs ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def stub_ssh(cmd_str, args = nil, &block)
|
46
|
+
args ||= {}
|
47
|
+
|
48
|
+
cmd_str_proc = get_cmd_ssh_proc(cmd_str)
|
49
|
+
input_proc = get_cmd_ssh_proc(args[:input])
|
50
|
+
given_opts_proc = get_cmd_ssh_proc(args[:opts])
|
51
|
+
|
52
|
+
remote_cmd_stubs.unshift(
|
53
|
+
Stub.new(cmd_str_proc, input_proc, given_opts_proc, block)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def unstub_all_ssh
|
58
|
+
remote_cmd_stubs.clear
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def get_cmd_ssh_proc(obj)
|
64
|
+
obj.kind_of?(::Proc) ? obj : proc{ obj }
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_cmd_ssh_stub_block(stubs, task, cmd_str, input, given_opts)
|
68
|
+
stub = stubs.find do |stub|
|
69
|
+
task.instance_eval(&stub.cmd_str_proc) == cmd_str &&
|
70
|
+
task.instance_eval(&stub.input_proc) == input &&
|
71
|
+
task.instance_eval(&stub.given_opts_proc) == given_opts
|
72
|
+
end
|
73
|
+
stub ? stub.block : nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# if the cmd is stubbed, build a spy and apply the stub (or return the
|
77
|
+
# cached spy), otherwise let the runner decide how to handle the local
|
78
|
+
# cmd
|
79
|
+
def build_local_cmd(task, cmd_str, input, given_opts)
|
80
|
+
b = find_cmd_ssh_stub_block(local_cmd_stubs, task, cmd_str, input, given_opts)
|
81
|
+
if b
|
82
|
+
Local::CmdSpy.new(cmd_str, given_opts).tap(&b)
|
83
|
+
else
|
84
|
+
has_the_stubs_build_local_cmd(cmd_str, given_opts)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def has_the_stubs_build_local_cmd(cmd_str, given_opts)
|
89
|
+
raise NotImplementedError
|
90
|
+
end
|
91
|
+
|
92
|
+
# if the cmd is stubbed, build a spy and apply the stub (or return the
|
93
|
+
# cached spy), otherwise let the runner decide how to handle the remote
|
94
|
+
# cmd; when building the spy use the ssh opts, this allows stubbing and
|
95
|
+
# calling ssh cmds with the same opts but also allows building a valid
|
96
|
+
# remote cmd that has an ssh host
|
97
|
+
def build_remote_cmd(task, cmd_str, input, given_opts, ssh_opts)
|
98
|
+
b = find_cmd_ssh_stub_block(remote_cmd_stubs, task, cmd_str, input, given_opts)
|
99
|
+
if b
|
100
|
+
Remote::CmdSpy.new(cmd_str, ssh_opts).tap(&b)
|
101
|
+
else
|
102
|
+
has_the_stubs_build_remote_cmd(cmd_str, ssh_opts)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def has_the_stubs_build_remote_cmd(cmd_str, ssh_opts)
|
107
|
+
raise NotImplementedError
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
Stub = Struct.new(:cmd_str_proc, :input_proc, :given_opts_proc, :block)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/lib/dk/local.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'scmd'
|
2
|
+
|
3
|
+
module Dk; end
|
4
|
+
module Dk::Local
|
5
|
+
|
6
|
+
class BaseCmd
|
7
|
+
|
8
|
+
attr_reader :scmd, :cmd_str
|
9
|
+
|
10
|
+
def initialize(scmd_or_spy_klass, cmd_str, opts)
|
11
|
+
opts ||= {}
|
12
|
+
|
13
|
+
@cmd_str = cmd_str
|
14
|
+
@scmd = scmd_or_spy_klass.new(@cmd_str, :env => opts[:env])
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s; self.cmd_str; end
|
18
|
+
|
19
|
+
def run(input = nil)
|
20
|
+
@scmd.run(input)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def stdout; @scmd.stdout; end
|
25
|
+
def stderr; @scmd.stderr; end
|
26
|
+
def success?; @scmd.success?; end
|
27
|
+
|
28
|
+
def output_lines
|
29
|
+
build_stdout_lines(self.stdout) + build_stderr_lines(self.stderr)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def build_stdout_lines(stdout)
|
35
|
+
build_output_lines('stdout', stdout)
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_stderr_lines(stderr)
|
39
|
+
build_output_lines('stderr', stderr)
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_output_lines(name, output)
|
43
|
+
output.to_s.strip.split("\n").map{ |line| OutputLine.new(name, line) }
|
44
|
+
end
|
45
|
+
|
46
|
+
OutputLine = Struct.new(:name, :line)
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class Cmd < BaseCmd
|
51
|
+
|
52
|
+
def initialize(cmd_str, opts = nil)
|
53
|
+
super(Scmd, cmd_str, opts)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
class CmdSpy < BaseCmd
|
59
|
+
|
60
|
+
attr_reader :cmd_opts
|
61
|
+
|
62
|
+
def initialize(cmd_str, opts = nil)
|
63
|
+
require 'scmd/command_spy'
|
64
|
+
super(Scmd::CommandSpy, cmd_str, opts)
|
65
|
+
@cmd_opts = opts
|
66
|
+
end
|
67
|
+
|
68
|
+
def run_input
|
69
|
+
return nil unless self.run_called?
|
70
|
+
self.run_calls.first.input
|
71
|
+
end
|
72
|
+
|
73
|
+
def stdout=(value); @scmd.stdout = value; end
|
74
|
+
def stderr=(value); @scmd.stderr = value; end
|
75
|
+
def exitstatus=(value); @scmd.exitstatus = value; end
|
76
|
+
|
77
|
+
def run_calls; @scmd.run_calls; end
|
78
|
+
def run_called?; @scmd.run_called?; end
|
79
|
+
|
80
|
+
def ssh?; false; end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/dk/remote.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'dk/config'
|
2
|
+
require 'dk/local'
|
3
|
+
|
4
|
+
module Dk; end
|
5
|
+
module Dk::Remote
|
6
|
+
|
7
|
+
def self.ssh_cmd_str(cmd_str, host, args, host_args)
|
8
|
+
host_args = host_args[host.to_s] if !host.nil?
|
9
|
+
val = "\"#{cmd_str.gsub(/\s+/, ' ')}\"".gsub("\\", "\\\\\\").gsub('"', '\"')
|
10
|
+
"ssh #{args} #{host_args} #{host} -- \"sh -c #{val}\""
|
11
|
+
end
|
12
|
+
|
13
|
+
class BaseCmd
|
14
|
+
|
15
|
+
attr_reader :hosts, :ssh_args, :host_ssh_args, :cmd_str, :local_cmds
|
16
|
+
|
17
|
+
def initialize(local_cmd_or_spy_klass, cmd_str, opts)
|
18
|
+
opts ||= {}
|
19
|
+
if nil_or_empty_or_missing_hosts(opts[:hosts])
|
20
|
+
raise NoHostsError, "no hosts to run cmd on (#{opts[:hosts].inspect})"
|
21
|
+
end
|
22
|
+
|
23
|
+
@hosts = opts[:hosts].sort
|
24
|
+
@ssh_args = opts[:ssh_args] || Dk::Config::DEFAULT_SSH_ARGS.dup
|
25
|
+
@host_ssh_args = opts[:host_ssh_args] || Dk::Config::DEFAULT_HOST_SSH_ARGS.dup
|
26
|
+
@cmd_str = cmd_str
|
27
|
+
|
28
|
+
@local_cmds = @hosts.inject({}) do |cmds, host|
|
29
|
+
cmds[host] = local_cmd_or_spy_klass.new(self.ssh_cmd_str(host), {
|
30
|
+
:env => opts[:env],
|
31
|
+
:dry_tree_run => opts[:dry_tree_run]
|
32
|
+
})
|
33
|
+
cmds
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s; self.cmd_str; end
|
38
|
+
|
39
|
+
def ssh_cmd_str(host)
|
40
|
+
build_ssh_cmd_str(@cmd_str, host, @ssh_args, @host_ssh_args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def run(input = nil)
|
44
|
+
self.hosts.each{ |host| @local_cmds[host].scmd.start(input) }
|
45
|
+
self.hosts.each{ |host| @local_cmds[host].scmd.wait }
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def stdout
|
50
|
+
self.hosts.inject('') do |out, host|
|
51
|
+
out.empty? ? @local_cmds[host].stdout.to_s : out
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def stderr
|
56
|
+
self.hosts.inject('') do |err, host|
|
57
|
+
err.empty? ? @local_cmds[host].stderr.to_s : err
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def success?
|
62
|
+
self.hosts.inject(true) do |success, host|
|
63
|
+
success && @local_cmds[host].success?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def output_lines
|
68
|
+
self.hosts.inject([]) do |lines, host|
|
69
|
+
lines + build_output_lines(host, @local_cmds[host].output_lines)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def nil_or_empty_or_missing_hosts(h)
|
76
|
+
h.nil? ||
|
77
|
+
!h.respond_to?(:empty?) || h.empty? ||
|
78
|
+
!h.respond_to?(:select) || h.select(&:nil?).size > 0
|
79
|
+
end
|
80
|
+
|
81
|
+
# escape everything properly; run in sh to ensure full profile is loaded
|
82
|
+
def build_ssh_cmd_str(cmd_str, host, args, host_args)
|
83
|
+
Dk::Remote.ssh_cmd_str(cmd_str, host, args, host_args)
|
84
|
+
end
|
85
|
+
|
86
|
+
def build_output_lines(host, local_cmd_output_lines)
|
87
|
+
local_cmd_output_lines.map{ |ol| OutputLine.new(host, ol.name, ol.line) }
|
88
|
+
end
|
89
|
+
|
90
|
+
OutputLine = Struct.new(:host, :name, :line)
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
NoHostsError = Class.new(ArgumentError)
|
95
|
+
|
96
|
+
class Cmd < BaseCmd
|
97
|
+
|
98
|
+
def initialize(cmd_str, opts = nil)
|
99
|
+
super(Dk::Local::Cmd, cmd_str, opts)
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class CmdSpy < BaseCmd
|
105
|
+
|
106
|
+
attr_reader :cmd_opts
|
107
|
+
|
108
|
+
def initialize(cmd_str, opts = nil)
|
109
|
+
super(Dk::Local::CmdSpy, cmd_str, opts)
|
110
|
+
@cmd_opts = opts
|
111
|
+
@first_local_cmd_spy = @local_cmds[@hosts.first]
|
112
|
+
end
|
113
|
+
|
114
|
+
def run_input
|
115
|
+
return nil unless self.run_called?
|
116
|
+
self.run_calls.first.input
|
117
|
+
end
|
118
|
+
|
119
|
+
# just set the first local cmd, this will have an overall effect
|
120
|
+
def stdout=(value); @first_local_cmd_spy.stdout = value; end
|
121
|
+
def stderr=(value); @first_local_cmd_spy.stderr = value; end
|
122
|
+
def exitstatus=(value); @first_local_cmd_spy.exitstatus = value; end
|
123
|
+
|
124
|
+
# just query the firs tlocal cmd - if run for one it was run for all
|
125
|
+
def run_calls; @first_local_cmd_spy.scmd.start_calls; end
|
126
|
+
def run_called?; @first_local_cmd_spy.scmd.start_called?; end
|
127
|
+
|
128
|
+
def ssh?; true; end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
data/lib/dk/runner.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'set'
|
3
|
+
require 'dk'
|
4
|
+
require 'dk/ansi'
|
5
|
+
require 'dk/config'
|
6
|
+
require 'dk/has_set_param'
|
7
|
+
require 'dk/has_ssh_opts'
|
8
|
+
require 'dk/local'
|
9
|
+
require 'dk/null_logger'
|
10
|
+
require 'dk/remote'
|
11
|
+
|
12
|
+
module Dk
|
13
|
+
|
14
|
+
class Runner
|
15
|
+
include Dk::HasSetParam
|
16
|
+
include Dk::HasSSHOpts
|
17
|
+
|
18
|
+
TASK_START_LOG_PREFIX = ' >>> '.freeze
|
19
|
+
TASK_END_LOG_PREFIX = ' <<< '.freeze
|
20
|
+
INDENT_LOG_PREFIX = ' '.freeze
|
21
|
+
CMD_LOG_PREFIX = '[CMD] '.freeze
|
22
|
+
SSH_LOG_PREFIX = '[SSH] '.freeze
|
23
|
+
CMD_SSH_OUT_LOG_PREFIX = "> ".freeze
|
24
|
+
|
25
|
+
attr_reader :params, :logger
|
26
|
+
|
27
|
+
def initialize(opts = nil)
|
28
|
+
opts ||= {}
|
29
|
+
@params = Hash.new{ |h, k| raise Dk::NoParamError, "no param named `#{k}`" }
|
30
|
+
@params.merge!(dk_normalize_params(opts[:params]))
|
31
|
+
|
32
|
+
d = Config::DEFAULT_CALLBACKS
|
33
|
+
@task_callbacks = {
|
34
|
+
'before' => opts[:before_callbacks] || d.dup,
|
35
|
+
'prepend_before' => opts[:prepend_before_callbacks] || d.dup,
|
36
|
+
'after' => opts[:after_callbacks] || d.dup,
|
37
|
+
'prepend_after' => opts[:prepend_after_callbacks] || d.dup
|
38
|
+
}
|
39
|
+
|
40
|
+
@ssh_hosts = opts[:ssh_hosts] || Config::DEFAULT_SSH_HOSTS.dup
|
41
|
+
@ssh_args = opts[:ssh_args] || Config::DEFAULT_SSH_ARGS.dup
|
42
|
+
@host_ssh_args = opts[:host_ssh_args] || Config::DEFAULT_HOST_SSH_ARGS.dup
|
43
|
+
|
44
|
+
@logger = opts[:logger] || NullLogger.new
|
45
|
+
|
46
|
+
@has_run_task_classes = Set.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def task_callbacks(named, task_class)
|
50
|
+
@task_callbacks[named][task_class] || []
|
51
|
+
end
|
52
|
+
|
53
|
+
def task_callback_task_classes(named, task_class)
|
54
|
+
task_callbacks(named, task_class).map(&:task_class)
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_task_callback(named, subject_task_class, callback_task_class, params)
|
58
|
+
@task_callbacks[named][subject_task_class] << Task::Callback.new(
|
59
|
+
callback_task_class,
|
60
|
+
params
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
# called by CLI on top-level tasks
|
65
|
+
def run(task_class, params = nil)
|
66
|
+
check_run_once_and_build_and_run_task(task_class, params)
|
67
|
+
end
|
68
|
+
|
69
|
+
# called by other tasks on sub-tasks
|
70
|
+
def run_task(task_class, params = nil)
|
71
|
+
check_run_once_and_build_and_run_task(task_class, params)
|
72
|
+
end
|
73
|
+
|
74
|
+
def log_info(msg, *ansi_styles)
|
75
|
+
self.logger.info("#{INDENT_LOG_PREFIX}#{Ansi.styled_msg(msg, *ansi_styles)}")
|
76
|
+
end
|
77
|
+
|
78
|
+
def log_debug(msg, *ansi_styles)
|
79
|
+
self.logger.debug("#{INDENT_LOG_PREFIX}#{Ansi.styled_msg(msg, *ansi_styles)}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def log_error(msg, *ansi_styles)
|
83
|
+
self.logger.error("#{INDENT_LOG_PREFIX}#{Ansi.styled_msg(msg, *ansi_styles)}")
|
84
|
+
end
|
85
|
+
|
86
|
+
def log_task_run(task_class, &run_block)
|
87
|
+
self.logger.debug "#{TASK_START_LOG_PREFIX}#{task_class}"
|
88
|
+
time = Benchmark.realtime(&run_block)
|
89
|
+
self.logger.debug "#{TASK_END_LOG_PREFIX}#{task_class} (#{self.pretty_run_time(time)})"
|
90
|
+
end
|
91
|
+
|
92
|
+
def log_cli_task_run(task_name, &run_block)
|
93
|
+
self.logger.info "Starting `#{task_name}`."
|
94
|
+
time = Benchmark.realtime(&run_block)
|
95
|
+
self.logger.info "`#{task_name}` finished in #{self.pretty_run_time(time)}."
|
96
|
+
self.logger.info ""
|
97
|
+
self.logger.info ""
|
98
|
+
end
|
99
|
+
|
100
|
+
def log_cli_run(cli_argv, &run_block)
|
101
|
+
15.times{ self.logger.debug "" }
|
102
|
+
self.logger.debug "===================================="
|
103
|
+
self.logger.debug ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> `#{cli_argv}`"
|
104
|
+
self.logger.debug "===================================="
|
105
|
+
time = Benchmark.realtime(&run_block)
|
106
|
+
self.logger.info "(#{self.pretty_run_time(time)})"
|
107
|
+
self.logger.debug "===================================="
|
108
|
+
self.logger.debug "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< `#{cli_argv}`"
|
109
|
+
self.logger.debug "===================================="
|
110
|
+
end
|
111
|
+
|
112
|
+
def cmd(task, cmd_str, input, given_opts)
|
113
|
+
build_and_run_local_cmd(task, cmd_str, input, given_opts)
|
114
|
+
end
|
115
|
+
|
116
|
+
def ssh(task, cmd_str, input, given_opts, ssh_opts)
|
117
|
+
build_and_run_remote_cmd(task, cmd_str, input, given_opts, ssh_opts)
|
118
|
+
end
|
119
|
+
|
120
|
+
def has_run_task?(task_class)
|
121
|
+
@has_run_task_classes.include?(task_class)
|
122
|
+
end
|
123
|
+
|
124
|
+
def pretty_run_time(raw_run_time)
|
125
|
+
if raw_run_time > 1.5 # seconds
|
126
|
+
"#{raw_run_time.to_i / 60}:#{(raw_run_time.round % 60).to_i.to_s.rjust(2, '0')}s"
|
127
|
+
else
|
128
|
+
"#{(raw_run_time * 1000 * 10.0).round / 10.0}ms"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def check_run_once_and_build_and_run_task(task_class, params = nil)
|
135
|
+
if task_class.run_only_once && self.has_run_task?(task_class)
|
136
|
+
build_task(task_class, params)
|
137
|
+
else
|
138
|
+
build_and_run_task(task_class, params)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def build_and_run_task(task_class, params = nil)
|
143
|
+
build_task(task_class, params).tap do |task|
|
144
|
+
task.dk_run
|
145
|
+
@has_run_task_classes << task_class
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def build_task(task_class, params = nil)
|
150
|
+
task_class.new(self, params)
|
151
|
+
end
|
152
|
+
|
153
|
+
def build_and_run_local_cmd(task, cmd_str, input, given_opts)
|
154
|
+
local_cmd = build_local_cmd(task, cmd_str, input, given_opts)
|
155
|
+
log_local_cmd(local_cmd){ |cmd| cmd.run(input) }
|
156
|
+
end
|
157
|
+
|
158
|
+
# input is needed for the `TestRunner` so it can use it with stubbing
|
159
|
+
# otherwise it is ignored when building a local cmd
|
160
|
+
def build_local_cmd(task, cmd_str, input, given_opts)
|
161
|
+
Local::Cmd.new(cmd_str, given_opts)
|
162
|
+
end
|
163
|
+
|
164
|
+
def log_local_cmd(cmd, &block)
|
165
|
+
self.logger.info("#{CMD_LOG_PREFIX}#{cmd.cmd_str}")
|
166
|
+
time = Benchmark.realtime{ block.call(cmd) }
|
167
|
+
self.logger.info("#{INDENT_LOG_PREFIX}(#{self.pretty_run_time(time)})")
|
168
|
+
cmd.output_lines.each do |output_line|
|
169
|
+
self.logger.debug("#{INDENT_LOG_PREFIX}#{CMD_SSH_OUT_LOG_PREFIX}#{output_line.line}")
|
170
|
+
end
|
171
|
+
cmd
|
172
|
+
end
|
173
|
+
|
174
|
+
def build_and_run_remote_cmd(task, cmd_str, input, given_opts, ssh_opts)
|
175
|
+
remote_cmd = build_remote_cmd(task, cmd_str, input, given_opts, ssh_opts)
|
176
|
+
log_remote_cmd(remote_cmd){ |cmd| cmd.run(input) }
|
177
|
+
end
|
178
|
+
|
179
|
+
# input and given opts are needed for the `TestRunner` so it can use it with
|
180
|
+
# stubbing otherwise they are ignored when building a remote cmd
|
181
|
+
def build_remote_cmd(task, cmd_str, input, given_opts, ssh_opts)
|
182
|
+
Remote::Cmd.new(cmd_str, ssh_opts)
|
183
|
+
end
|
184
|
+
|
185
|
+
def log_remote_cmd(cmd, &block)
|
186
|
+
self.logger.info("#{SSH_LOG_PREFIX}#{cmd.cmd_str}")
|
187
|
+
self.logger.debug("#{INDENT_LOG_PREFIX}#{cmd.ssh_cmd_str('<host>')}")
|
188
|
+
cmd.hosts.each do |host|
|
189
|
+
self.logger.info("#{INDENT_LOG_PREFIX}[#{host}]")
|
190
|
+
end
|
191
|
+
time = Benchmark.realtime{ block.call(cmd) }
|
192
|
+
self.logger.info("#{INDENT_LOG_PREFIX}(#{self.pretty_run_time(time)})")
|
193
|
+
cmd.output_lines.each do |ol|
|
194
|
+
self.logger.debug "#{INDENT_LOG_PREFIX}[#{ol.host}] " \
|
195
|
+
"#{CMD_SSH_OUT_LOG_PREFIX}#{ol.line}"
|
196
|
+
end
|
197
|
+
cmd
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|