command_exec 0.1.3 → 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/Gemfile +6 -2
- data/Gemfile.lock +42 -18
- data/README.md +707 -72
- data/RELEASE_NOTES.md +62 -0
- data/Rakefile +40 -9
- data/TODO.md +8 -2
- data/command_exec.gemspec +3 -2
- data/gemfiles/Gemfile.default +28 -0
- data/gemfiles/Gemfile.travis +16 -0
- data/gemfiles/Gemfile.travis.lock +48 -0
- data/lib/command_exec.rb +22 -2
- data/lib/command_exec/command.rb +307 -157
- data/lib/command_exec/exceptions.rb +16 -6
- data/lib/command_exec/field_helper.rb +263 -0
- data/lib/command_exec/formatter/array.rb +158 -0
- data/lib/command_exec/formatter/hash.rb +78 -0
- data/lib/command_exec/formatter/json.rb +22 -0
- data/lib/command_exec/formatter/string.rb +22 -0
- data/lib/command_exec/formatter/xml.rb +22 -0
- data/lib/command_exec/formatter/yaml.rb +22 -0
- data/lib/command_exec/logger.rb +9 -0
- data/lib/command_exec/process.rb +294 -0
- data/lib/command_exec/spec_helper_module.rb +52 -0
- data/lib/command_exec/version.rb +1 -1
- data/script/console +8 -0
- data/spec/command/command_spec.rb +413 -117
- data/spec/command/test_data/echo_test +3 -0
- data/spec/command/test_data/exit_status_test +2 -0
- data/spec/command/test_data/log_file_test +3 -0
- data/spec/command/test_data/logger_test +2 -0
- data/spec/command/test_data/not_raise_error_test +4 -0
- data/spec/command/test_data/not_throw_error_test +4 -0
- data/spec/command/test_data/output_test +6 -0
- data/spec/command/test_data/raise_error_test +6 -0
- data/spec/command/test_data/runner_open3_test +4 -0
- data/spec/command/test_data/runner_system_test +4 -0
- data/spec/command/test_data/stderr_test +4 -0
- data/spec/command/test_data/stdout_multiple_lines_test +4 -0
- data/spec/command/test_data/stdout_test +4 -0
- data/spec/command/test_data/throw_error_test +6 -0
- data/spec/command/test_data/true_test +2 -0
- data/spec/formatter/array_spec.rb +215 -0
- data/spec/formatter/hash_spec.rb +117 -0
- data/spec/formatter/json_spec.rb +21 -0
- data/spec/formatter/xml_spec.rb +33 -0
- data/spec/formatter/yaml_spec.rb +21 -0
- data/spec/process/process_spec.rb +329 -0
- data/spec/spec_helper.rb +15 -4
- metadata +79 -5
@@ -0,0 +1,78 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
#Main
|
4
|
+
module CommandExec
|
5
|
+
#Formatting output
|
6
|
+
module Formatter
|
7
|
+
#Style hash
|
8
|
+
class Hash
|
9
|
+
|
10
|
+
include FieldHelper
|
11
|
+
|
12
|
+
# @!attribute [r] output
|
13
|
+
# return the formatted output
|
14
|
+
attr_reader :output
|
15
|
+
# @!attribute [w] logger
|
16
|
+
# set the logger after object creation
|
17
|
+
attr_writer :logger
|
18
|
+
|
19
|
+
public
|
20
|
+
|
21
|
+
# Create new hash formatter
|
22
|
+
#
|
23
|
+
# @param [Hash] options
|
24
|
+
# Options for formatter
|
25
|
+
#
|
26
|
+
# @option options [Symbol] :logger
|
27
|
+
# Logger to output information. Needs to have the same interface like
|
28
|
+
# the ruby `Logger`-class.
|
29
|
+
def initialize(options={})
|
30
|
+
@options = {
|
31
|
+
logger: Logger.new($stdout),
|
32
|
+
}.deep_merge options
|
33
|
+
|
34
|
+
@logger = @options[:logger]
|
35
|
+
|
36
|
+
super()
|
37
|
+
end
|
38
|
+
|
39
|
+
def status(value)
|
40
|
+
prepare_status(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Build the data structure for output
|
46
|
+
#
|
47
|
+
# @param [Array] fields
|
48
|
+
# which fields should be outputted
|
49
|
+
#
|
50
|
+
# @return [Hash]
|
51
|
+
# the formatted output
|
52
|
+
def prepare_output(fields=[])
|
53
|
+
out = {}
|
54
|
+
|
55
|
+
fields = default_fields if fields.blank?
|
56
|
+
|
57
|
+
fields.each do |f|
|
58
|
+
out[f] = available_fields[f] if available_fields.has_key?(f)
|
59
|
+
end
|
60
|
+
|
61
|
+
out
|
62
|
+
end
|
63
|
+
|
64
|
+
public
|
65
|
+
|
66
|
+
# Output the prepared output
|
67
|
+
#
|
68
|
+
# @param [Array,Symbol) fields
|
69
|
+
# the fields which should be outputted
|
70
|
+
#
|
71
|
+
# @return [Hash]
|
72
|
+
# the formatted output
|
73
|
+
def output(*fields)
|
74
|
+
prepare_output(fields.flatten)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
#Main
|
4
|
+
module CommandExec
|
5
|
+
#Formatting output
|
6
|
+
module Formatter
|
7
|
+
#Style as json string
|
8
|
+
class JSON < CommandExec::Formatter::Hash
|
9
|
+
|
10
|
+
# convert the prepared output to json
|
11
|
+
#
|
12
|
+
# @param [Array,Symbol) fields
|
13
|
+
# the fields which should be outputted
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
# the output formatted as json string
|
17
|
+
def output(*fields)
|
18
|
+
::JSON.generate prepare_output(fields.flatten)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
#Main
|
4
|
+
module CommandExec
|
5
|
+
#Formatting output
|
6
|
+
module Formatter
|
7
|
+
#Style as simple string
|
8
|
+
class String < CommandExec::Formatter::Array
|
9
|
+
|
10
|
+
# convert the prepared output to single string
|
11
|
+
#
|
12
|
+
# @param [Array,Symbol) fields
|
13
|
+
# the fields which should be outputted
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
# the output formatted as simple string
|
17
|
+
def output(*fields)
|
18
|
+
prepare_output(fields.flatten).join("\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
#Main
|
4
|
+
module CommandExec
|
5
|
+
#Formatting output
|
6
|
+
module Formatter
|
7
|
+
#Style as xml string
|
8
|
+
class XML < CommandExec::Formatter::Hash
|
9
|
+
|
10
|
+
# convert the prepared output to a xml string
|
11
|
+
#
|
12
|
+
# @param [Array,Symbol) fields
|
13
|
+
# the fields which should be outputted
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
# the output formatted as a xml string
|
17
|
+
def output(*fields)
|
18
|
+
XmlSimple.xml_out(prepare_output(fields.flatten), 'RootName' => 'command', 'NoAttr' => true)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
#Main
|
4
|
+
module CommandExec
|
5
|
+
#Formatting output
|
6
|
+
module Formatter
|
7
|
+
#Style as yaml string
|
8
|
+
class YAML < CommandExec::Formatter::Hash
|
9
|
+
|
10
|
+
# convert the prepared output to a yaml string
|
11
|
+
#
|
12
|
+
# @param [Array,Symbol) fields
|
13
|
+
# the fields which should be outputted
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
# the output formatted as a xml string
|
17
|
+
def output(*fields)
|
18
|
+
Psych.dump prepare_output(fields.flatten)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
#Main
|
4
|
+
module CommandExec
|
5
|
+
# The class used to save the data about
|
6
|
+
# the executed command
|
7
|
+
class Process
|
8
|
+
|
9
|
+
include FieldHelper
|
10
|
+
|
11
|
+
# @!attribute [rw] executable
|
12
|
+
# Set/Get the executable of the command
|
13
|
+
attr_accessor :executable
|
14
|
+
|
15
|
+
# @!attribute [r] status
|
16
|
+
# Get the status of the command
|
17
|
+
#
|
18
|
+
# @!attribute [r] stdout
|
19
|
+
# Get stdout of the command
|
20
|
+
#
|
21
|
+
# @!attribute [r] stderr
|
22
|
+
# Get stderr of the command
|
23
|
+
#
|
24
|
+
# @!attribute [r] reason_for_failure
|
25
|
+
# Get the reason why `command_exec` thinks a command failed
|
26
|
+
#
|
27
|
+
# @!attribute [r] return_code
|
28
|
+
# Get the exit code of the command
|
29
|
+
#
|
30
|
+
# @!attribute [r] pid
|
31
|
+
# Get the pid of the command
|
32
|
+
#
|
33
|
+
# @!attribute [r] start_time
|
34
|
+
# Return the time when the execution of the command started
|
35
|
+
#
|
36
|
+
# @!attribute [r] end_time
|
37
|
+
# Return the time when the execution of the command finished
|
38
|
+
attr_reader :status, :log_file, :stdout, :stderr, :reason_for_failure, :return_code, :pid, :start_time, :end_time
|
39
|
+
|
40
|
+
# Create a process object
|
41
|
+
#
|
42
|
+
# @param [Hash] options
|
43
|
+
# options for the process
|
44
|
+
#
|
45
|
+
# @option options [Logger] lib_logger
|
46
|
+
# The logger which is used to output information generated by the
|
47
|
+
# library. The logger which is provided needs to be compatible with api
|
48
|
+
# of the Ruby `Logger`-class.
|
49
|
+
#
|
50
|
+
# @option options [Array] stderr
|
51
|
+
# content of stderr of the process
|
52
|
+
#
|
53
|
+
# @option options [Array] stdout
|
54
|
+
# content of stdout of the process
|
55
|
+
#
|
56
|
+
# @option options [Array] log_file
|
57
|
+
# content of the log file of the process
|
58
|
+
#
|
59
|
+
# @option options [Number,String] pid
|
60
|
+
# the pid of the process
|
61
|
+
#
|
62
|
+
# @option options [Number,String] return_code
|
63
|
+
# the exit status of the process
|
64
|
+
#
|
65
|
+
# @option options [Array] reason_for_failure
|
66
|
+
# the reason for failure
|
67
|
+
#
|
68
|
+
# @option options [Symbol] status
|
69
|
+
# execution was successful, failed
|
70
|
+
def initialize(options={})
|
71
|
+
@options = {
|
72
|
+
lib_logger: Logger.new($stderr),
|
73
|
+
stderr: [],
|
74
|
+
stdout: [],
|
75
|
+
log_file: [],
|
76
|
+
pid: nil,
|
77
|
+
return_code: nil,
|
78
|
+
reason_for_failure: [],
|
79
|
+
status: :success,
|
80
|
+
executable: nil,
|
81
|
+
}.merge options
|
82
|
+
|
83
|
+
@logger = @options[:lib_logger]
|
84
|
+
|
85
|
+
@stderr = @options[:stderr]
|
86
|
+
@stdout = @options[:stdout]
|
87
|
+
@status = @options[:status]
|
88
|
+
@log_file = @options[:log_file]
|
89
|
+
@pid = @options[:pid]
|
90
|
+
@reason_for_failure = @options[:reason_for_failure]
|
91
|
+
@return_code = @options[:return_code]
|
92
|
+
@executable = @options[:executable]
|
93
|
+
|
94
|
+
@start_time = nil
|
95
|
+
@end_time = nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# Set the name of the log file
|
99
|
+
#
|
100
|
+
# @param [String] filename
|
101
|
+
# the name of the log file
|
102
|
+
def log_file=(filename=nil)
|
103
|
+
if filename.blank?
|
104
|
+
file = StringIO.new
|
105
|
+
@logger.debug "No file name for log file given. Using empty String"
|
106
|
+
else
|
107
|
+
begin
|
108
|
+
file = File.open(filename)
|
109
|
+
@logger.debug "read logfile \"#{file}\" "
|
110
|
+
rescue Errno::ENOENT
|
111
|
+
file = StringIO.new
|
112
|
+
@logger.warn "Logfile #{filename} not found!"
|
113
|
+
rescue Exception => e
|
114
|
+
file = StringIO.new
|
115
|
+
@logger.warn "An error happen while reading log_file \"#{filename}\": #{e.message}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
@log_file = file.readlines.map(&:chomp)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Set the pid of the process
|
123
|
+
#
|
124
|
+
# @param [Number,String] value
|
125
|
+
def pid=(value)
|
126
|
+
@pid = value.to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
# Set the value of stdout
|
130
|
+
#
|
131
|
+
# @param [Array, String] content
|
132
|
+
# the content of stdout
|
133
|
+
def stdout=(*content)
|
134
|
+
@stdout += content.flatten
|
135
|
+
end
|
136
|
+
|
137
|
+
# Set the value of stderr
|
138
|
+
#
|
139
|
+
# @param [Array, String] content
|
140
|
+
# the content of stderr
|
141
|
+
def stderr=(*content)
|
142
|
+
@stderr += content.flatten
|
143
|
+
end
|
144
|
+
|
145
|
+
# Set the status of command execution
|
146
|
+
#
|
147
|
+
# @param [Array, String] value
|
148
|
+
# the status
|
149
|
+
def status=(value)
|
150
|
+
case value.to_s
|
151
|
+
when 'success'
|
152
|
+
@status = :success
|
153
|
+
when 'failed'
|
154
|
+
@status = :failed
|
155
|
+
else
|
156
|
+
@status = :failed
|
157
|
+
end
|
158
|
+
|
159
|
+
@status
|
160
|
+
end
|
161
|
+
|
162
|
+
# Why the execution failed
|
163
|
+
#
|
164
|
+
# @param [String] content
|
165
|
+
# the reason for failure. When you run it mulitple times, the string is
|
166
|
+
# added at the end.
|
167
|
+
def reason_for_failure=(content)
|
168
|
+
@reason_for_failure << content.to_s
|
169
|
+
end
|
170
|
+
|
171
|
+
# Set the exit status of the command
|
172
|
+
#
|
173
|
+
# @param [Number,String] value
|
174
|
+
# the exit status of the command
|
175
|
+
def return_code=(value)
|
176
|
+
@return_code = value
|
177
|
+
end
|
178
|
+
|
179
|
+
# Set the path to the executable
|
180
|
+
#
|
181
|
+
# @param [Number,String] value
|
182
|
+
# the path to the executable of the command
|
183
|
+
def executable=(value)
|
184
|
+
@executable = value
|
185
|
+
end
|
186
|
+
|
187
|
+
# Set the start time of the command execution
|
188
|
+
#
|
189
|
+
# @param [Number,String] value
|
190
|
+
# the path to the executable of the command
|
191
|
+
def start_time=(value)
|
192
|
+
@start_time = value
|
193
|
+
end
|
194
|
+
|
195
|
+
# Set the end time of the command execution
|
196
|
+
#
|
197
|
+
# @param [Number,String] value
|
198
|
+
# the path to the executable of the command
|
199
|
+
def end_time=(value)
|
200
|
+
@end_time = value
|
201
|
+
end
|
202
|
+
|
203
|
+
def run_time
|
204
|
+
end_time - start_time
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
# Generate formatted output
|
210
|
+
#
|
211
|
+
# @param [Symbol,Array of Symbols] fields
|
212
|
+
# the field which should be part of the output
|
213
|
+
#
|
214
|
+
# @param [Formatter] formatter
|
215
|
+
# the formatter which is used to format the output
|
216
|
+
def output(*fields,formatter)
|
217
|
+
|
218
|
+
fields.flatten.each do |f|
|
219
|
+
formatter.public_send(f, available_fields[f])
|
220
|
+
end
|
221
|
+
|
222
|
+
formatter.output(fields.flatten)
|
223
|
+
end
|
224
|
+
|
225
|
+
public
|
226
|
+
|
227
|
+
# Output process data as array
|
228
|
+
#
|
229
|
+
# @param [Array of Symbols] fields
|
230
|
+
# the fields which should be outputed
|
231
|
+
#
|
232
|
+
# @param [Formatter] formatter (Formatter::Array.new)
|
233
|
+
# the formatter which is used the format the output
|
234
|
+
def to_a(fields=default_fields, formatter=Formatter::Array.new)
|
235
|
+
output(fields, formatter)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Output process data as hash
|
239
|
+
#
|
240
|
+
# @param [Array of Symbols] fields
|
241
|
+
# the fields which should be outputed
|
242
|
+
#
|
243
|
+
# @param [Formatter] formatter (Formatter::Hash.new)
|
244
|
+
# the formatter which is used the format the output
|
245
|
+
def to_h(fields=default_fields, formatter=Formatter::Hash.new)
|
246
|
+
output(fields, formatter)
|
247
|
+
end
|
248
|
+
|
249
|
+
# Output process data as string
|
250
|
+
#
|
251
|
+
# @param [Array of Symbols] fields
|
252
|
+
# the fields which should be outputed
|
253
|
+
#
|
254
|
+
# @param [Formatter] formatter (Formatter::String.new)
|
255
|
+
# the formatter which is used the format the output
|
256
|
+
def to_s(fields=default_fields, formatter=Formatter::String.new)
|
257
|
+
output(fields, formatter)
|
258
|
+
end
|
259
|
+
|
260
|
+
# Output process data as xml
|
261
|
+
#
|
262
|
+
# @param [Array of Symbols] fields
|
263
|
+
# the fields which should be outputed
|
264
|
+
#
|
265
|
+
# @param [Formatter] formatter (Formatter::XML.new)
|
266
|
+
# the formatter which is used the format the output
|
267
|
+
def to_xml(fields=default_fields, formatter=Formatter::XML.new)
|
268
|
+
output(fields, formatter)
|
269
|
+
end
|
270
|
+
|
271
|
+
# Output process data as json
|
272
|
+
#
|
273
|
+
# @param [Array of Symbols] fields
|
274
|
+
# the fields which should be outputed
|
275
|
+
#
|
276
|
+
# @param [Formatter] formatter (Formatter::JSON.new)
|
277
|
+
# the formatter which is used the format the output
|
278
|
+
def to_json(fields=default_fields, formatter=Formatter::JSON.new)
|
279
|
+
output(fields, formatter)
|
280
|
+
end
|
281
|
+
|
282
|
+
# Output process data as yaml
|
283
|
+
#
|
284
|
+
# @param [Array of Symbols] fields
|
285
|
+
# the fields which should be outputed
|
286
|
+
#
|
287
|
+
# @param [Formatter] formatter (Formatter::YAML.new)
|
288
|
+
# the formatter which is used the format the output
|
289
|
+
def to_yaml(fields=default_fields, formatter=Formatter::YAML.new)
|
290
|
+
output(fields, formatter)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|