dotanuki 0.0.3 → 0.0.4
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/.gitignore +3 -1
- data/README.md +18 -5
- data/lib/dotanuki/version.rb +2 -1
- data/lib/dotanuki.rb +60 -16
- metadata +7 -7
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -6,17 +6,17 @@ failed commands.
|
|
6
6
|
|
7
7
|
Examples
|
8
8
|
========
|
9
|
-
In the following example, if the mkdir fails, none of the other commands will
|
9
|
+
In the following example, if the `mkdir` fails, none of the other commands will
|
10
10
|
be executed.
|
11
11
|
|
12
|
-
class
|
13
|
-
include
|
12
|
+
class Example
|
13
|
+
include Dotanuki
|
14
14
|
|
15
15
|
def test
|
16
16
|
commands = [
|
17
17
|
"mkdir /tmp/foo",
|
18
|
-
"
|
19
|
-
"cp /etc/
|
18
|
+
"cp /etc/hosts /tmp/foo",
|
19
|
+
"cp /etc/passwd /tmp/foo"
|
20
20
|
]
|
21
21
|
|
22
22
|
result = execute(commands)
|
@@ -25,3 +25,16 @@ be executed.
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
29
|
+
It can also be used with a `guard` block, which will raise an `ExecError` if a command fails.
|
30
|
+
|
31
|
+
class Example
|
32
|
+
include Dotanuki
|
33
|
+
def test
|
34
|
+
guard do
|
35
|
+
execute "mkdir /tmp/foo"
|
36
|
+
execute "cp /etc/hosts /tmp/foo"
|
37
|
+
execute "cp /etc/passwd /tmp/foo"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/dotanuki/version.rb
CHANGED
data/lib/dotanuki.rb
CHANGED
@@ -1,17 +1,40 @@
|
|
1
1
|
require 'popen4'
|
2
2
|
|
3
|
+
# Module intented to be included into classes which execute system commands
|
4
|
+
# @author Martin Englund
|
3
5
|
module Dotanuki
|
4
6
|
|
5
|
-
#
|
7
|
+
# Error raised when an execution error occurs
|
6
8
|
class ExecError < StandardError
|
7
|
-
|
8
|
-
|
9
|
+
# Create a new ExecError
|
10
|
+
#
|
11
|
+
# @param [String] message error message
|
12
|
+
def initialize(message)
|
13
|
+
super(message)
|
9
14
|
end
|
10
15
|
end
|
11
16
|
|
12
|
-
#
|
17
|
+
# Result of one or more command executions
|
13
18
|
class ExecResult
|
14
|
-
|
19
|
+
|
20
|
+
# Array of stdout from each command executed
|
21
|
+
# @return [Array]
|
22
|
+
attr_reader :stdout
|
23
|
+
|
24
|
+
# Array of stderr from each command executed
|
25
|
+
# @return [Array]
|
26
|
+
attr_reader :stderr
|
27
|
+
|
28
|
+
# Exit status of the command that failed, nil if the command was not found
|
29
|
+
# and 0 if all commands succeeded
|
30
|
+
#
|
31
|
+
# @return [Fixnum]
|
32
|
+
attr_reader :status
|
33
|
+
|
34
|
+
# Index of the command that failed, or nil if all commands succeeded
|
35
|
+
# @return [Fixnum]
|
36
|
+
attr_reader :failed_index
|
37
|
+
|
15
38
|
def initialize
|
16
39
|
@stdout = []
|
17
40
|
@stderr = []
|
@@ -19,7 +42,7 @@ module Dotanuki
|
|
19
42
|
@failed_index = nil
|
20
43
|
end
|
21
44
|
|
22
|
-
# Returns true if
|
45
|
+
# Returns true if a command has failed
|
23
46
|
def failed?
|
24
47
|
status != 0
|
25
48
|
end
|
@@ -29,15 +52,17 @@ module Dotanuki
|
|
29
52
|
stderr[@failed_index]
|
30
53
|
end
|
31
54
|
|
55
|
+
# Add the result of a command execution
|
32
56
|
def add(stdout, stderr, status)
|
33
57
|
@stdout << stdout
|
34
58
|
@stderr << stderr
|
35
|
-
@status = status
|
36
59
|
if status.nil? || status != 0
|
60
|
+
@status = status
|
37
61
|
@failed_index = @stdout.size - 1
|
38
62
|
end
|
39
63
|
end
|
40
64
|
|
65
|
+
# Add another [ExecResult] to this
|
41
66
|
def <<(result)
|
42
67
|
raise ArgumentError unless result.is_a?(ExecResult)
|
43
68
|
# TODO merge correctly
|
@@ -45,24 +70,30 @@ module Dotanuki
|
|
45
70
|
end
|
46
71
|
end
|
47
72
|
|
73
|
+
# Default options for executing commands
|
74
|
+
DEFAULT_OPTIONS = {:on_error => :exception}
|
75
|
+
|
76
|
+
# @param [Hash] options the options for error handling
|
77
|
+
# @option options [Symbol] :on_error How to handle errors,
|
78
|
+
# can be either `:exception` or `:silent`
|
48
79
|
def initialize(options={})
|
49
|
-
@defaults =
|
50
|
-
@defaults[:on_error] = :exception
|
51
|
-
@defaults.merge!(options)
|
80
|
+
@defaults = DEFAULT_OPTIONS.merge(options)
|
52
81
|
end
|
53
82
|
|
54
|
-
# Execute commands in a block
|
83
|
+
# Execute commands wrapped in a block
|
55
84
|
#
|
85
|
+
# @param [Hash] options (see #guard)
|
86
|
+
# @return [ExecResult]
|
56
87
|
# @example
|
57
88
|
# guard do
|
58
89
|
# execute "uname -a"
|
59
90
|
# execute "ls /does/not/exist"
|
60
91
|
# end
|
61
|
-
#
|
62
|
-
# TODO this is not thread safe
|
92
|
+
# @note this method isn't thread safe
|
63
93
|
def guard(options={}, &block)
|
64
94
|
opts = @defaults.merge(options)
|
65
95
|
validate_options(opts)
|
96
|
+
# TODO this is not thread safe
|
66
97
|
@guard = ExecResult.new
|
67
98
|
yield
|
68
99
|
clear_guard
|
@@ -72,14 +103,18 @@ module Dotanuki
|
|
72
103
|
result
|
73
104
|
end
|
74
105
|
|
75
|
-
#
|
106
|
+
# Execute one or more commands
|
107
|
+
#
|
108
|
+
# @param [String, Array] commands string or array containing the command to be executed
|
109
|
+
# @param [Hash] options (see #guard)
|
110
|
+
# @return [ExecResult]
|
76
111
|
def execute(commands, options={})
|
77
112
|
validate_options(options)
|
78
113
|
|
79
114
|
result = ExecResult.new
|
80
115
|
|
81
116
|
[commands].flatten.each do |command|
|
82
|
-
stdout, stderr, exit_status = _execute(command
|
117
|
+
stdout, stderr, exit_status = _execute(command)
|
83
118
|
result.add(stdout, stderr, exit_status)
|
84
119
|
if options[:on_error] == :exception || @guard
|
85
120
|
if exit_status.nil?
|
@@ -98,7 +133,12 @@ module Dotanuki
|
|
98
133
|
return result
|
99
134
|
end
|
100
135
|
|
101
|
-
|
136
|
+
# Execute a single command
|
137
|
+
#
|
138
|
+
# @param [String] command string containing the command to be executed
|
139
|
+
# @return [String, String, Fixnum] standard out, standard error and exit
|
140
|
+
# status of the command
|
141
|
+
def _execute(command)
|
102
142
|
stdout = stderr = ""
|
103
143
|
|
104
144
|
status =
|
@@ -110,6 +150,9 @@ module Dotanuki
|
|
110
150
|
return stdout, stderr, status ? status.exitstatus : status
|
111
151
|
end
|
112
152
|
|
153
|
+
# Validates options for Dotanuki#execute or Dotanuki#guard
|
154
|
+
#
|
155
|
+
# @raise [ArgumentError] if an unknown option is given
|
113
156
|
def validate_options(options)
|
114
157
|
options.each do |option, value|
|
115
158
|
if option == :on_error && ! [:exception, :silent].include?(value)
|
@@ -121,6 +164,7 @@ module Dotanuki
|
|
121
164
|
|
122
165
|
private
|
123
166
|
|
167
|
+
# TODO this is not thread safe
|
124
168
|
def clear_guard
|
125
169
|
result = @guard
|
126
170
|
@guard = nil
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dotanuki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -14,7 +14,7 @@ default_executable:
|
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: popen4
|
17
|
-
requirement: &
|
17
|
+
requirement: &2161180600 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2161180600
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec
|
28
|
-
requirement: &
|
28
|
+
requirement: &2161180020 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2161180020
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: metric_fu
|
39
|
-
requirement: &
|
39
|
+
requirement: &2161179480 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *2161179480
|
48
48
|
description: A command executioner which doesn't blindly stumble on when a command
|
49
49
|
fails'
|
50
50
|
email:
|