command_exec 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/Gemfile CHANGED
@@ -1,12 +1,11 @@
1
1
  source :rubygems
2
2
 
3
3
  # Specify your gem's dependencies in workplace-letter_generator.gemspec
4
- gemspec
4
+ gemspec
5
5
 
6
6
  group :test do
7
7
  gem 'rake'
8
8
  gem 'rspec'
9
- gem 'tmrb'
10
9
  gem 'simplecov'
11
10
  gem 'aruba'
12
11
  gem 'fuubar'
@@ -20,5 +19,10 @@ end
20
19
 
21
20
  group :development do
22
21
  gem 'tmrb'
22
+ gem 'debugger'
23
+ gem 'pry'
24
+ gem 'pry-doc'
25
+ gem 'awesome_print'
26
+ gem 'travis-lint'
23
27
  gem 'activesupport'
24
28
  end
data/Gemfile.lock CHANGED
@@ -1,18 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- command_exec (0.1.0)
5
- POpen4
6
- colored
4
+ command_exec (0.1.3)
5
+ activesupport
6
+ smart_colored
7
+ xml-simple
7
8
 
8
9
  GEM
9
10
  remote: http://rubygems.org/
10
11
  specs:
11
- POpen4 (0.1.4)
12
- Platform (>= 0.4.0)
13
- open4
14
- Platform (0.4.0)
15
- activesupport (3.2.6)
12
+ activesupport (3.2.8)
16
13
  i18n (~> 0.6)
17
14
  multi_json (~> 1.0)
18
15
  aruba (0.4.11)
@@ -20,28 +17,45 @@ GEM
20
17
  cucumber (>= 1.1.1)
21
18
  ffi (>= 1.0.11)
22
19
  rspec (>= 2.7.0)
20
+ awesome_print (1.0.2)
23
21
  builder (3.0.0)
24
- childprocess (0.3.4)
22
+ childprocess (0.3.5)
25
23
  ffi (~> 1.0, >= 1.0.6)
26
- colored (1.2)
24
+ coderay (1.0.7)
25
+ columnize (0.3.6)
27
26
  cucumber (1.2.1)
28
27
  builder (>= 2.1.2)
29
28
  diff-lcs (>= 1.1.3)
30
29
  gherkin (~> 2.11.0)
31
30
  json (>= 1.4.6)
31
+ debugger (1.2.0)
32
+ columnize (>= 0.3.1)
33
+ debugger-linecache (~> 1.1.1)
34
+ debugger-ruby_core_source (~> 1.1.3)
35
+ debugger-linecache (1.1.2)
36
+ debugger-ruby_core_source (>= 1.1.1)
37
+ debugger-ruby_core_source (1.1.3)
32
38
  diff-lcs (1.1.3)
33
- ffi (1.1.0)
39
+ ffi (1.1.5)
34
40
  fuubar (1.0.0)
35
41
  rspec (~> 2.0)
36
42
  rspec-instafail (~> 0.2.0)
37
43
  ruby-progressbar (~> 0.0.10)
38
- gherkin (2.11.1)
44
+ gherkin (2.11.2)
39
45
  json (>= 1.4.6)
40
46
  github-markup (0.7.4)
41
- i18n (0.6.0)
42
- json (1.7.3)
47
+ hashr (0.0.22)
48
+ i18n (0.6.1)
49
+ json (1.7.5)
50
+ method_source (0.8)
43
51
  multi_json (1.3.6)
44
- open4 (1.3.0)
52
+ pry (0.9.10)
53
+ coderay (~> 1.0.5)
54
+ method_source (~> 0.8)
55
+ slop (~> 3.3.1)
56
+ pry-doc (0.4.4)
57
+ pry (>= 0.9.9.6)
58
+ yard (~> 0.8.1)
45
59
  rake (0.9.2.2)
46
60
  redcarpet (2.1.1)
47
61
  rspec (2.11.0)
@@ -49,18 +63,23 @@ GEM
49
63
  rspec-expectations (~> 2.11.0)
50
64
  rspec-mocks (~> 2.11.0)
51
65
  rspec-core (2.11.1)
52
- rspec-expectations (2.11.1)
66
+ rspec-expectations (2.11.3)
53
67
  diff-lcs (~> 1.1.3)
54
68
  rspec-instafail (0.2.4)
55
- rspec-mocks (2.11.1)
69
+ rspec-mocks (2.11.2)
56
70
  ruby-progressbar (0.0.10)
57
71
  simplecov (0.6.4)
58
72
  multi_json (~> 1.0)
59
73
  simplecov-html (~> 0.5.3)
60
74
  simplecov-html (0.5.3)
61
- thor (0.15.4)
75
+ slop (3.3.3)
76
+ smart_colored (1.1.1)
77
+ thor (0.16.0)
62
78
  tmrb (1.2.7)
63
79
  thor
80
+ travis-lint (1.4.0)
81
+ hashr (>= 0.0.19)
82
+ xml-simple (1.1.1)
64
83
  yard (0.8.2.1)
65
84
 
66
85
  PLATFORMS
@@ -69,12 +88,17 @@ PLATFORMS
69
88
  DEPENDENCIES
70
89
  activesupport
71
90
  aruba
91
+ awesome_print
72
92
  command_exec!
93
+ debugger
73
94
  fuubar
74
95
  github-markup
96
+ pry
97
+ pry-doc
75
98
  rake
76
99
  redcarpet
77
100
  rspec
78
101
  simplecov
79
102
  tmrb
103
+ travis-lint
80
104
  yard
data/README.md CHANGED
@@ -1,132 +1,752 @@
1
- command-exec(1) -- execute shell commands with ease
2
- ===================================================
1
+ # command-exec -- execute shell commands with ease
3
2
 
4
- ## Description
3
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/maxmeyer/command_exec)
4
+ [![Build Status](https://secure.travis-ci.org/maxmeyer/command_exec.png)](http://travis-ci.org/maxmeyer/command_exec)
5
5
 
6
- This gem brings command execution via POpen4 with all the bells and whistles.
6
+ ## <a name="introduction">Introduction</a>
7
7
 
8
- ## Usage
8
+ ### Description
9
+
10
+ The name of the library is `command_exec`. It's helps you running programs and
11
+ check if the run was successful. It supports a vast amount of options you find
12
+ in the one of the following sections [usage](#usage).
13
+
14
+ `Example`:
9
15
 
10
16
  ```ruby
11
17
  require 'command_exec'
12
18
 
13
- #long form
14
- command = CommandExec::Command.new( 'command' )
19
+ # command has to be in $PATH
20
+ command = CommandExec::Command.new( :echo , :parameter => 'hello world' )
15
21
  command.run
22
+ p command.result
23
+ ```
24
+
25
+ ### Target "Group"
26
+
27
+ If you need a library to execute programs which do a job and then terminate,
28
+ `command_exec` is your friend.
29
+
30
+ If you need a library which supports error detection based on STDOUT, STDERR,
31
+ RETURN CODE and/or LOG FILE `command_exec` is the right choice.
32
+
33
+ ### Limitations
34
+
35
+ The programs should NOT produce gigabytes of output (STDOUT, STDERR, LOG FILE)
36
+ to search for errors.
37
+
38
+ ### Structure of documentation
39
+
40
+ <table>
41
+ <tr>
42
+ <th>Section</th>
43
+ <th>Description</th>
44
+ </tr>
45
+ <tr>
46
+ <td>Introduction</td>
47
+ <td>Metainformation</td>
48
+ </tr>
49
+ <tr>
50
+ <td>Usage</td>
51
+ <td>How to use the library</td>
52
+ </tr>
53
+ <tr>
54
+ <td>Options</td>
55
+ <td>Which options are available to parametrize the library</td>
56
+ </tr>
57
+ <tr>
58
+ <td>HowTo</td>
59
+ <td>How to do ... with library</td>
60
+ </tr>
61
+ <tr>
62
+ <td>Further reading</td>
63
+ <td>Other helpful information</td>
64
+ </tr>
65
+ </table>
66
+
67
+ ## <a name="usage">Usage<a/>
68
+
69
+ ### Gem versioning
70
+
71
+ This gem uses semantic versioning. The major version is increased when breaking
72
+ changes has been made. The minor version is increased if backward-compatiable
73
+ changes introduce new functionality. The patch version is increased if a bug
74
+ was fixed and the change is backward-compatible. Please see http://semver.org/
75
+ for more information.
76
+
77
+ ### Ruby Version
78
+
79
+ This gem supports ruby up from 1.9.3.
80
+
81
+ ### Install gem
82
+
83
+ Install the `command_exec`-gem via `rubygems` or whatever package manager (e.g. `bundler`) you like
84
+ to use.
85
+
86
+ ```bash
87
+ gem install command_exec
88
+ ```
89
+
90
+ ### Include library
91
+
92
+ To include the library in your code, you could use this code snippet.
93
+
94
+ ```ruby
95
+ require 'command_exec'
96
+ ```
97
+ ### Run command
98
+
99
+ There are two forms to execute a program. You could either use the long or the
100
+ short form. In both cases a `CommandExec::Command`-object will be returned.
101
+
102
+ ```ruby
103
+ command = CommandExec::Command.new( :echo , :parameter => 'hello world' )
104
+ command.run
105
+ p command.result
106
+ ```
107
+
108
+ ```ruby
109
+ command = CommandExec::Command.execute( :echo , :parameter => 'hello world' )
110
+ p command.result
111
+ ```
112
+
113
+ ### <a name="result_of_command_execution">Result of command execution</a>
114
+
115
+ That `result`-object can be used to inspect the result of the command execution. It
116
+ supports several different methods, but only some are from interest for
117
+ external use. If you want a full list, please see the API-documentation at
118
+ [rdoc.info](http://www.rdoc.info/github/maxmeyer/command_exec/CommandExec/Process).
119
+
120
+ ```ruby
121
+ result = command.result
122
+
123
+ # which executable was run
124
+ result.executable
125
+
126
+ # !!content!! of log file
127
+ result.log_file
128
+
129
+ # pid unter which the command was run
130
+ result.pid
16
131
 
17
- #short form
18
- command = CommandExec::Command.execute( 'command')
132
+ #if failed, why
133
+ result.reason_for_failure
19
134
 
20
- #full path to commadn
21
- command = CommandExec::Command.execute( 'path/to/command')
135
+ #return code of command
136
+ result.return_code
137
+
138
+ #status of command execution
139
+ result.status
140
+
141
+ #content of stderr
142
+ result.stderr
143
+
144
+ #content of stdout
145
+ result.stdout
146
+ ```
147
+
148
+ ### Serialize result of command execution
149
+
150
+ There are some methods which need a little more explanation. Those methods
151
+ return a string representation of the result.
152
+
153
+ ```ruby
154
+ #return an array of lines
155
+ result.to_a
156
+
157
+ #return a hash
158
+ result.to_h
159
+
160
+ #serialize data to json
161
+ result.to_json
162
+
163
+ #serialize data to string
164
+ result.to_s
165
+
166
+ #serialize data to xml
167
+ result.to_xml
168
+
169
+ #serialize data to yaml
170
+ result.to_yaml
171
+ ```
172
+
173
+ One can tell those methods which data should be returned. There are different
174
+ fields available:
175
+
176
+ <table>
177
+ <tr>
178
+ <th>Field</th>
179
+ <th>Symbol</th>
180
+ </tr>
181
+ <tr>
182
+ <td>Status</td>
183
+ <td>:status</td>
184
+ </tr>
185
+ <tr>
186
+ <td>Return code</td>
187
+ <td>:return_code</td>
188
+ </tr>
189
+ <tr>
190
+ <td>STDERR</td>
191
+ <td>:stderr</td>
192
+ </tr>
193
+ <tr>
194
+ <td>STDOUT</td>
195
+ <td>:stdout</td>
196
+ </tr>
197
+ <tr>
198
+ <td>Log file</td>
199
+ <td>:log_file</td>
200
+ </tr>
201
+ <tr>
202
+ <td>Process identitfier (PID)</td>
203
+ <td>:pid</td>
204
+ </tr>
205
+ <tr>
206
+ <td>Reason for failure</td>
207
+ <td>reason_for_failure</td>
208
+ </tr>
209
+ </table>
210
+
211
+ Now, some small examples:
212
+
213
+ ```ruby
214
+ #result.<method>(field1,field2, ... , fieldn)
215
+ #result.<method>([field1,field2, ... , fieldn])
216
+
217
+ #all fields
218
+ result.to_a
219
+
220
+ #stderr and stdout only
221
+ result.to_a(:stderr, :stdout)
222
+
223
+ #stderr and stdout only (parameters given as a single array)
224
+ result.to_a([:stderr, :stdout])
225
+ ```
226
+
227
+ ## Extended usage
228
+
229
+ There are multiple ways to tell `command_exec` about a command:
230
+
231
+ ### Search command in PATH
232
+
233
+ If the first parameter of `run` and `execute` is a `Symbol` the library will
234
+ search for the command in the paths given in the $PATH-shell-variable.
235
+
236
+ ```ruby
237
+ command = CommandExec::Command.execute( :echo ,
238
+ :parameter => 'hello world',
239
+ )
240
+ p command.result
241
+ ```
242
+
243
+ ### Path to command
244
+
245
+ If you prefer to use a full qualified path, this is possible as well.
246
+
247
+ ```ruby
248
+ command = CommandExec::Command.execute( '/bin/echo' ,
249
+ :parameter => 'hello world',
250
+ )
251
+ p command.result
252
+ ```
253
+
254
+ It also supports relative paths. But be aware to tell the library the correct
255
+ one. The base path for relative ones is the working directory of the *library*,
256
+ not the working directory of the command (see section "[Working
257
+ directory](#working_directory)" about that).
258
+
259
+
260
+ ```ruby
261
+ Dir.chdir('/tmp') do
262
+ command = CommandExec::Command.execute( '../bin/echo' ,
263
+ :parameter => 'hello world',
264
+ :logger => Logger.new($stderr)
265
+ )
266
+ p command.result
267
+ end
22
268
  ```
23
269
 
24
270
  ## Options
25
271
 
26
- * `:logger`: Logger for output of information
272
+ ### Logging
273
+
274
+ `command_exec` makes use of the Ruby `Logger`-class. If you would like to use
275
+ another class/gem, nevermind, but it has to be compatible with the `Logger`-API.
276
+
277
+ To make it easier for you, `command_exec` provides a `:logger` option. It
278
+ defaults to `Logger.new($stderr)`.
27
279
 
28
280
  ```ruby
29
- command = CommandExec::Command.new(
30
- 'command',
31
- :logger => Logger.new($stderr),
32
- }
33
- command.run
281
+ command = CommandExec::Command.execute( :echo ,
282
+ :parameter => 'hello world',
283
+ :logger => Logger.new($stderr),
284
+ )
285
+ p command.result
286
+ ```
287
+
288
+ If you prefer more or less information you can make use of the
289
+ `:lib_log_level`-option. With one exception, those log levels are the same like in
290
+ the `Logger`-class. Additionally you can use `:silent` to suppress all output
291
+ of the library, if you use the `open3` and not the `system` runner. If you
292
+ choose to use the system runner, STDOUT from the command won't be captured.
293
+
294
+
295
+ <table>
296
+ <tr>
297
+ <td><strong>Option value</strong></td>
298
+ <td><strong>Logger loglevel</strong></td>
299
+ </tr>
300
+ <tr>
301
+ <td>:debug</td>
302
+ <td>Logger::DEBUG</td>
303
+ </tr>
304
+ <tr>
305
+ <td>:info</td>
306
+ <td>Logger::INFO</td>
307
+ </tr>
308
+ <tr>
309
+ <td>:warn</td>
310
+ <td>Logger::WARN</td>
311
+ </tr>
312
+ <tr>
313
+ <td>:error</td>
314
+ <td>Logger::ERROR</td>
315
+ </tr>
316
+ <tr>
317
+ <td>:fatal</td>
318
+ <td>Logger::FATAL</td>
319
+ </tr>
320
+ <tr>
321
+ <td>:unknown</td>
322
+ <td>Logger::UNKNOWN</td>
323
+ </tr>
324
+ <tr>
325
+ <td>:silent</td>
326
+ <td>no output (log device is set to nil)</td>
327
+ </tr>
328
+ </table>
329
+
330
+
331
+ ```ruby
332
+ command = CommandExec::Command.execute( :echo ,
333
+ :parameter => 'hello world' ,
334
+ :lib_log_level => :debug,
335
+ )
336
+ p command.result
34
337
  ```
35
338
 
36
- * `:options`: Commandline options for executed command
339
+ ### Command options and parameter
340
+
341
+ The next two options (command options and command parameters) are very similar.
342
+ Both will be used to build the command which should be executed. The main
343
+ difference is the position of given string in the command string.
344
+
345
+
346
+ ```
347
+ <command> <options> <parameter>
348
+ ```
349
+
350
+ So, if you don't want to use the `options`- and/or the `parameter`-option, you
351
+ don't need to do it. But may be there are situations, where you would like to
352
+ be as concise as possible.
353
+
354
+
355
+ Recommended:
37
356
 
38
357
  ```ruby
39
- command = CommandExec::Command.new(
40
- 'command',
41
- :options => '--command options',
42
- }
43
- command.run
358
+ command = CommandExec::Command.execute( :ls ,
359
+ :options => '-al',
360
+ :parameter => '/bin',
361
+ )
362
+ p command.result
44
363
  ```
45
364
 
46
- * `error_keywords`: Keywords which indicate error(s)
365
+ But also valid:
47
366
 
48
- Are there any keywords in stdout of the command which should be executed, which
49
- indicate errors?
367
+ ```ruby
368
+ command = CommandExec::Command.execute( :ls ,
369
+ :options => '-al /bin',
370
+ )
371
+ p command.result
372
+ ```
373
+
374
+ Or:
50
375
 
51
376
  ```ruby
52
- command = CommandExec::Command.new(
53
- 'command',
54
- :error_keywords => ['key words in', 'stdout with indicate errors' ],
55
- }
56
- command.run
377
+ command = CommandExec::Command.execute( :ls ,
378
+ :parameter => '-al /bin',
379
+ )
380
+ p command.result
57
381
  ```
58
382
 
59
- * `:working_directory`: Change working directory of command
383
+ Please check if you use single or double quotes correctly! `command_exec` takes
384
+ the parameters and options as given. That's why
60
385
 
61
- Change working directory to given one before command execution.
386
+ ```ruby
387
+ #will succeed
388
+ #see debug output for reason
389
+ command = CommandExec::Command.execute( :echo ,
390
+ :options => '-e',
391
+ :parameter => "\"Thats a string\n with a newline\"",
392
+ :lib_log_level => :debug,
393
+ )
394
+ p command.result
395
+ ```
396
+
397
+ isn't the same like
62
398
 
63
399
  ```ruby
64
- command = CommandExec::Command.new(
65
- 'command',
66
- :working_directory => 'working/directory/where/the/command/should/be/executed/in',
67
- }
68
- command.run
400
+ #will fail
401
+ #see debug output for reason
402
+ command = CommandExec::Command.execute( :echo ,
403
+ :options => '-e',
404
+ :parameter => "Thats a string\n with a newline",
405
+ :lib_log_level => :debug,
406
+ )
407
+ p command.result
69
408
  ```
70
409
 
71
- * `logfile`: Logfile of command
410
+ ### <a name="log_file">Command log file</a>
72
411
 
73
- The first 30 lines of the command-logfile will be output by logger if an error
74
- occured.
412
+ If the command creates a log file, you can tell `command_exec` about that file
413
+ via the `:log_file`-option. Honestly, this option only makes sense if you
414
+ configure `command_exec`to search for errors in the file (please see the
415
+ chapter about [Error detection](#error_detection) for further information about
416
+ that).
75
417
 
76
418
  ```ruby
77
- command = CommandExec::Command.new(
78
- 'command',
79
- :logfile => 'path/to/logfile.log',
80
- }
81
- command.run
419
+ command = CommandExec::Command.execute( :ls ,
420
+ :options => '-al',
421
+ :log_file => '/path/to/log_file',
422
+ )
423
+ p command.result
82
424
  ```
83
425
 
84
- * `:log_level`:
426
+ ### Command search path
85
427
 
86
- What should be put to logger? Available choices are :debug, :info, :warn,
87
- :error, :fatal, :unkonwn, :silent. If you choose :silent nothing will be
88
- output.
428
+ If you need to change the paths where a command can be found, you could use the
429
+ `:search_path`-option. It defaults to those paths found in $PATH.
89
430
 
431
+ It supports multiple values as `Array`:
90
432
 
91
433
  ```ruby
92
- command = CommandExec::Command.new(
93
- 'command',
94
- :logfile => 'path/to/logfile.log',
95
- :log_level => :debug
96
- }
97
- command.run
434
+ command = CommandExec::Command.execute( :ls ,
435
+ :options => '-al',
436
+ :search_paths => [ '/bin' ],
437
+ )
438
+ p command.result
98
439
  ```
99
440
 
100
- ## Output
441
+ Or single values as `String`:
442
+
443
+ ```ruby
444
+ command = CommandExec::Command.execute( :ls ,
445
+ :options => '-al',
446
+ :search_paths => '/bin',
447
+ )
448
+ p command.result
449
+ ```
101
450
 
102
- After execute the command you get the following output. Today it's not possible
103
- to suppress that output, but it's on the roadmap.
451
+ ### <a name="error_detection">Error detection</a>
452
+
453
+ `command_exec` is capable of searching for errors. To enable error detection
454
+ you need to activate it via the `:error_detection_on`-option. It supports error
455
+ detection on:
456
+
457
+ <table>
458
+ <tr>
459
+ <td><strong>Search in...</strong></td>
460
+ <td><strong>Symbol</strong></td>
461
+ </tr>
462
+ <tr>
463
+ <td>Return code</td>
464
+ <td>:return_code</td>
465
+ </tr>
466
+ <tr>
467
+ <td>STDOUT</td>
468
+ <td>:stdout</td>
469
+ </tr>
470
+ <tr>
471
+ <td>STDERR</td>
472
+ <td>:stderr</td>
473
+ </tr>
474
+ <tr>
475
+ <td>Log file</td>
476
+ <td>:log_file</td>
477
+ </tr>
478
+ </table>
479
+
480
+ But you need to provide information, what item indicates an error.
481
+
482
+ <table>
483
+ <tr>
484
+ <td><strong>Indicator for...</strong></td>
485
+ <td><strong>Options</strong></td>
486
+ <td><strong>Type</strong></td>
487
+ </tr>
488
+ <tr>
489
+ <td>Return code</td>
490
+ <td>
491
+ :allowed_return_code<br/>
492
+ :forbidden_return_code
493
+ </td>
494
+ <td>
495
+ Array
496
+ </td>
497
+ </tr>
498
+ <tr>
499
+ <td>STDERR</td>
500
+ <td>
501
+ :allowed_words_in_stderr<br/>
502
+ :forbidden_words_in_stderr
503
+ </td>
504
+ <td>
505
+ Array
506
+ </td>
507
+ </tr>
508
+ <tr>
509
+ <td>STDOUT</td>
510
+ <td>
511
+ :allowed_words_in_stdout<br/>
512
+ :forbidden_words_in_stdout
513
+ </td>
514
+ <td>
515
+ Array
516
+ </td>
517
+ </tr>
518
+ <tr>
519
+ <td>Log file</td>
520
+ <td>
521
+ :allowed_words_in_log_file<br/>
522
+ :forbidden_words_in_log_file
523
+ </td>
524
+ <td>
525
+ Array
526
+ </td>
527
+ </tr>
528
+ </table>
529
+
530
+ *Return code*
531
+
532
+ If the command returns helpful return codes, those can be used to check if an
533
+ error occured. You can tell `command_exec` about allowed or forbidden return
534
+ codes.
104
535
 
105
- ### Successfull
106
536
 
537
+ ```ruby
538
+ #All error codes except `0` will be detected as an error.
539
+ command = CommandExec::Command.execute( :false ,
540
+ :error_detection_on => [:return_code],
541
+ :error_indicators => {
542
+ :allowed_return_code => [0],
543
+ },
544
+ )
545
+ p command.result
546
+
547
+ #If the command exits with a return code of `1`, this will be detected as an
548
+ #error.
549
+ command = CommandExec::Command.execute( :false ,
550
+ :error_detection_on => [:return_code],
551
+ :error_indicators => {
552
+ :forbidden_return_code => [1],
553
+ },
554
+ )
555
+ p command.result
107
556
  ```
108
- <timestamp> command: OK
557
+
558
+ In the case of the detection of errors `command_exec`defaults to:
559
+
560
+ ```ruby
561
+ :error_detection_on => [:return_code],
562
+ :allowed_return_code => [0],
109
563
  ```
110
564
 
111
- ### Failed with STDERR set
565
+ *STDOUT*
112
566
 
567
+ `command_exec` can search for errors in STDOUT. To enable this functionality,
568
+ you need to set the `:error_detection_on`-option on ':stdout'. Furthermore you
569
+ need to tell the library, what strings are error indicators
570
+ (`forbidden_words_in_stdout`). If there are some strings which contain the
571
+ error string(s), but are no errors, you need to use the
572
+ `allowed_words_in_stdout`-option. The same is true, if the allowed word is in
573
+ the same line.
574
+
575
+ ```ruby
576
+ #Simple error search
577
+ #will fail
578
+ command = CommandExec::Command.execute( :echo ,
579
+ :options => '-e',
580
+ :parameter => "\"wow, a test. That's great.\nBut an error occured in this line\"",
581
+ :error_detection_on => [:stdout],
582
+ :error_indicators => {
583
+ :forbidden_words_in_stdout => %w{ error }
584
+ },
585
+ )
586
+ p command.result
587
+
588
+ #error indicator in string, which is no error
589
+ #will succeed
590
+ command = CommandExec::Command.execute( :echo ,
591
+ :options => '-e',
592
+ :parameter => "\"wow, a test. That's great.\nBut no error occured in this line\"",
593
+ :error_detection_on => [:stdout],
594
+ :error_indicators => {
595
+ :forbidden_words_in_stdout => %w{ error },
596
+ :allowed_words_in_stdout => ["no error occured"] ,
597
+ },
598
+ )
599
+ p command.result
600
+
601
+ #error indicator in same line, which is no error
602
+ #will succeed
603
+ command = CommandExec::Command.execute( :echo ,
604
+ :options => '-e',
605
+ :parameter => "\"wow, a test. That's great.\nBut no error occured in this line because of some other string\"",
606
+ :error_detection_on => [:stdout],
607
+ :error_indicators => {
608
+ :forbidden_words_in_stdout => %w{ error },
609
+ :allowed_words_in_stdout => ["some other string"] ,
610
+ },
611
+ )
612
+ p command.result
113
613
  ```
114
- <timestamp> command: FAILED
115
- ================== LOGFILE ==================
116
- [...]
117
- ================== STDOUT ==================
118
- [...]
119
- ================== STDERR ==================
120
- [...]
614
+
615
+ *STDERR*
616
+
617
+ The same is true for STDERR. You need to activate the error detection via
618
+ `:error_detection_on => [:stderr]`. The error indicators can be given via
619
+ `:forbidden_words_in_stderr => %w{ error }` and `:allowed_words_in_stdout =>
620
+ ["some other string"]`.
621
+
622
+ ```ruby
623
+ #will fail
624
+ command = CommandExec::Command.execute( :echo ,
625
+ :options => '-e',
626
+ :parameter => "\"wow, a test. That's great.\nBut an error occured in this line\" >&2",
627
+ :error_detection_on => [:stderr],
628
+ :error_indicators => {
629
+ :forbidden_words_in_stderr => %w{ error },
630
+ },
631
+ )
632
+ p command.result
121
633
  ```
122
634
 
123
- ### Failed with string in STDOUT indicating an error
635
+ *LOG FILE*
636
+
637
+ To search for errors in the log file a command created during execution, you
638
+ need to provide the information where `command_exec` finds the log file (see
639
+ section [Command Log file](#log_file)).
124
640
 
641
+ The options are very similar to those for STDERR and STDOUT: To activate error
642
+ detection for log files use `:error_detection_on => [:log_file]`. The error
643
+ indicators can be given via `:forbidden_words_in_log_file => %w{ error }` and
644
+ `:allowed_words_in_log_file => ["some other string"]`.
645
+
646
+ ```ruby
647
+ File.open('/tmp/test.log', 'w') do |f|
648
+ f.write "wow, a test. That's great.\nBut an error occured in this line"
649
+ end
650
+
651
+ #will fail
652
+ command = CommandExec::Command.execute( :echo ,
653
+ :error_detection_on => [:log_file],
654
+ :log_file => '/tmp/test.log',
655
+ :error_indicators => {
656
+ :forbidden_words_in_log_file => %w{ error },
657
+ },
658
+ )
659
+ p command.result
125
660
  ```
126
- <timestamp> command: FAILED
127
- ================== STDOUT ==================
661
+
662
+ ### <a name="working_directory">Working directory</a>
663
+
664
+ To change the working directory for the command you can use the `:working_directory`-option.
665
+
666
+ ```ruby
667
+ command = CommandExec::Command.execute( :ls ,
668
+ :options => '-al',
669
+ :working_directory => '/tmp',
670
+ )
671
+ p command.result
128
672
  ```
129
673
 
674
+ ### Error reaction
675
+
676
+ If an error occured, `command_exec` can raise an exception, 'throw' an error or
677
+ do nothing at all. Besides the configured option, on every run it returns the
678
+ result for the run (see [Result of command
679
+ execution](#result_of_command_execution) for more details).
680
+
681
+ *Raise an exception aka error*
682
+
683
+ If an error occured during command execution, you can tell `command_exec` to
684
+ raise an exception.
685
+
686
+ ```ruby
687
+ begin
688
+ command = CommandExec::Command.execute( :false ,
689
+ :on_error_do => :raise_error,
690
+ )
691
+ rescue CommandExec::Exceptions::CommandExecutionFailed => e
692
+ puts e.message
693
+ end
694
+ ```
695
+
696
+ *Throw error*
697
+
698
+ If you prefer not to use execptions, you can use ruby's
699
+ `throw`-`catch`-mechanism.
700
+
701
+ ```ruby
702
+ catch :command_execution_failed do
703
+ command = CommandExec::Command.execute( :false ,
704
+ :on_error_do => :throw_error,
705
+ )
706
+ end
707
+ ```
708
+
709
+ ### Runner
710
+
711
+ Today there are two runners available: `:open3` and `system`. Use the first one
712
+ if you want `:stdout` and `:stderr` to be captured and searched for errors. If
713
+ you're only interested in the `:return_code` you could use the
714
+ `:system`-runner. Please be aware, that using the `system`-runner + error
715
+ detection on `stdout`, `stderr` is not working as you might expect.
716
+
717
+ ```ruby
718
+ #will fail
719
+ command = CommandExec::Command.execute( :echo ,
720
+ :options => '-e',
721
+ :parameter => "\"wow, a test. That's great.\nBut an error occured in this line\"",
722
+ :error_detection_on => [:stdout],
723
+ :error_indicators => {
724
+ :forbidden_words_in_stdout => %w{ error }
725
+ },
726
+ :run_via => :open3,
727
+ )
728
+ p command.result
729
+
730
+ #will succeed, because stdout was not caputured
731
+ command = CommandExec::Command.execute( :echo ,
732
+ :options => '-e',
733
+ :parameter => "\"wow, a test. That's great.\nBut an error occured in this line\"",
734
+ :error_detection_on => [:stdout],
735
+ :error_indicators => {
736
+ :forbidden_words_in_stdout => %w{ error }
737
+ },
738
+ :run_via => :system,
739
+ )
740
+ p command.result
741
+ ```
742
+ ## HowTo
743
+
744
+ TBD
745
+
746
+ ## Further Reading
747
+
748
+ * API-documentation: http://rdoc.info/github/maxmeyer/command_exec/frames
749
+
130
750
  ## Dependencies
131
751
 
132
752
  Please see the gemspec for runtime dependencies and the 'Gemfile' for
@@ -136,6 +756,21 @@ development dependencies.
136
756
 
137
757
  Please see TODO.md for enhancements which are planned for implementation.
138
758
 
759
+ ## Development
760
+
761
+ 1. Fork it
762
+ 2. Create your remote (`git remote add <your_remote_repo> <path_to_repo>`)
763
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
764
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
765
+ 4. Push to the branch (`git push <your_remote_repo> my-new-feature`)
766
+ 5. Create new Pull Request
767
+
768
+ The API-documentation can be found at
769
+ http://rdoc.info/github/maxmeyer/command_exec/frames
770
+
771
+ Please see 'http://git-scm.com/book' first if you have further questions about
772
+ `git`.
773
+
139
774
  ## Copyright
140
775
 
141
776
  (c) 2012-, Max Meyer