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.
Files changed (49) hide show
  1. data/Gemfile +6 -2
  2. data/Gemfile.lock +42 -18
  3. data/README.md +707 -72
  4. data/RELEASE_NOTES.md +62 -0
  5. data/Rakefile +40 -9
  6. data/TODO.md +8 -2
  7. data/command_exec.gemspec +3 -2
  8. data/gemfiles/Gemfile.default +28 -0
  9. data/gemfiles/Gemfile.travis +16 -0
  10. data/gemfiles/Gemfile.travis.lock +48 -0
  11. data/lib/command_exec.rb +22 -2
  12. data/lib/command_exec/command.rb +307 -157
  13. data/lib/command_exec/exceptions.rb +16 -6
  14. data/lib/command_exec/field_helper.rb +263 -0
  15. data/lib/command_exec/formatter/array.rb +158 -0
  16. data/lib/command_exec/formatter/hash.rb +78 -0
  17. data/lib/command_exec/formatter/json.rb +22 -0
  18. data/lib/command_exec/formatter/string.rb +22 -0
  19. data/lib/command_exec/formatter/xml.rb +22 -0
  20. data/lib/command_exec/formatter/yaml.rb +22 -0
  21. data/lib/command_exec/logger.rb +9 -0
  22. data/lib/command_exec/process.rb +294 -0
  23. data/lib/command_exec/spec_helper_module.rb +52 -0
  24. data/lib/command_exec/version.rb +1 -1
  25. data/script/console +8 -0
  26. data/spec/command/command_spec.rb +413 -117
  27. data/spec/command/test_data/echo_test +3 -0
  28. data/spec/command/test_data/exit_status_test +2 -0
  29. data/spec/command/test_data/log_file_test +3 -0
  30. data/spec/command/test_data/logger_test +2 -0
  31. data/spec/command/test_data/not_raise_error_test +4 -0
  32. data/spec/command/test_data/not_throw_error_test +4 -0
  33. data/spec/command/test_data/output_test +6 -0
  34. data/spec/command/test_data/raise_error_test +6 -0
  35. data/spec/command/test_data/runner_open3_test +4 -0
  36. data/spec/command/test_data/runner_system_test +4 -0
  37. data/spec/command/test_data/stderr_test +4 -0
  38. data/spec/command/test_data/stdout_multiple_lines_test +4 -0
  39. data/spec/command/test_data/stdout_test +4 -0
  40. data/spec/command/test_data/throw_error_test +6 -0
  41. data/spec/command/test_data/true_test +2 -0
  42. data/spec/formatter/array_spec.rb +215 -0
  43. data/spec/formatter/hash_spec.rb +117 -0
  44. data/spec/formatter/json_spec.rb +21 -0
  45. data/spec/formatter/xml_spec.rb +33 -0
  46. data/spec/formatter/yaml_spec.rb +21 -0
  47. data/spec/process/process_spec.rb +329 -0
  48. data/spec/spec_helper.rb +15 -4
  49. 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,9 @@
1
+ # encoding: utf-8
2
+ #ruby's logging class
3
+ class Logger
4
+ #container for extra severities
5
+ module Severity
6
+ #keep logger silent
7
+ SILENT = 999999
8
+ end
9
+ 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
+