execute_shell 0.0.5 → 1.0.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 +1 -11
- data/Gemfile.lock +13 -9
- data/README +30 -9
- data/execute_shell.gemspec +6 -6
- data/lib/execute_shell.rb +40 -3
- data/lib/execute_shell/execute_shell.rb +170 -116
- data/lib/execute_shell/shell_result.rb +101 -0
- data/license/gpl +612 -0
- data/license/lgpl +157 -0
- data/license/lgplv3-88x31.png +0 -0
- data/rakefile +1 -2
- data/test/helper.rb +37 -0
- data/test/unit/execute_shell_test.rb +152 -0
- data/test/unit/shell_result_test.rb +63 -0
- metadata +73 -99
- data/test/execute_shell_test.rb +0 -127
- data/test/require.rb +0 -7
data/Gemfile
CHANGED
@@ -1,13 +1,3 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
|
4
|
-
gem 'rake_tasks', '~> 0.0.1'
|
5
|
-
end
|
6
|
-
|
7
|
-
group :test do
|
8
|
-
gem 'Platform', '~> 0.4.0', :require => 'platform'
|
9
|
-
gem 'open4', '~> 1.0.1'
|
10
|
-
gem 'win32-open3-19', '~> 0.0.1', :require => 'open3'
|
11
|
-
|
12
|
-
gem 'app_mode', '~> 1.0.0'
|
13
|
-
end
|
3
|
+
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
execute_shell (1.0.0)
|
5
|
+
Platform (~> 0.4.0)
|
6
|
+
open4 (~> 1.0.1)
|
7
|
+
win32-open3-19 (~> 0.0.1)
|
8
|
+
|
1
9
|
GEM
|
2
10
|
remote: http://rubygems.org/
|
3
11
|
specs:
|
4
12
|
Platform (0.4.0)
|
5
|
-
app_mode (1.0.1)
|
6
13
|
open4 (1.0.1)
|
7
|
-
|
8
|
-
|
9
|
-
rake (~> 0.8.7)
|
14
|
+
rake_tasks (2.0.5)
|
15
|
+
test_unit_helper (0.0.1)
|
10
16
|
win32-open3-19 (0.0.1)
|
11
17
|
|
12
18
|
PLATFORMS
|
13
19
|
ruby
|
14
20
|
|
15
21
|
DEPENDENCIES
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
rake_tasks (~> 0.0.1)
|
20
|
-
win32-open3-19 (~> 0.0.1)
|
22
|
+
execute_shell!
|
23
|
+
rake_tasks (~> 2.0.5)
|
24
|
+
test_unit_helper (~> 0.0.1)
|
data/README
CHANGED
@@ -20,24 +20,43 @@ in the octagon with a pig.
|
|
20
20
|
|
21
21
|
== Usage
|
22
22
|
|
23
|
-
1.
|
23
|
+
1. Simply call ExecuteShell.run as needed:
|
24
24
|
|
25
|
-
|
25
|
+
result = ExecuteShell.run('ls ~')
|
26
26
|
|
27
|
-
|
27
|
+
result will be a ShellResult object containing information
|
28
|
+
regarding the executed command.
|
28
29
|
|
29
|
-
|
30
|
+
Available methods include:
|
31
|
+
|
32
|
+
out ...... Standard out.
|
33
|
+
err ...... Standard error.
|
34
|
+
success? . Whether the command was executed successfully.
|
35
|
+
to_s ..... Standard out and standard error concatenated.
|
36
|
+
|
37
|
+
2. If you wish to simply get a single success, output, or error value back,
|
38
|
+
you may use calls such as:
|
39
|
+
|
40
|
+
ExecuteShell.run_success?('ls ~')
|
41
|
+
ExecuteShell.run_out('ls ~')
|
42
|
+
ExecuteShell.run_err('ls ~')
|
43
|
+
ExecuteShell.run_to_s('ls ~')
|
44
|
+
|
45
|
+
These may be chained together and will be returned in an array in the order
|
46
|
+
they are specified:
|
47
|
+
|
48
|
+
ExecuteShell.run_out_err('ls ~')
|
49
|
+
ExecuteShell.run_to_s_success_out('ls ~')
|
50
|
+
ExecuteShell.run_err_out_success('ls ~')
|
30
51
|
|
31
52
|
== Additional Notes
|
32
53
|
|
33
|
-
* The
|
54
|
+
* The run method has a second optional parameter, which is a path.
|
34
55
|
If specified, the working directory will be changed to this path prior
|
35
56
|
to executing the shell command. It will be set back to the original
|
36
57
|
working directory before returning to the calling function.
|
37
58
|
|
38
|
-
* Success
|
39
|
-
to stderr. The other is if an exception is raised. In either case, the
|
40
|
-
information is returned in the output.
|
59
|
+
* Success is based on the content of the err attribute of ShellResult.
|
41
60
|
|
42
61
|
== Additional Documentation
|
43
62
|
|
@@ -45,4 +64,6 @@ in the octagon with a pig.
|
|
45
64
|
|
46
65
|
== License
|
47
66
|
|
48
|
-
ExecuteShell is released under the
|
67
|
+
ExecuteShell is released under the {LGPLv3 license}[link:../../license/lgpl].
|
68
|
+
|
69
|
+
link:../../license/lgplv3-88x31.png
|
data/execute_shell.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'execute_shell'
|
3
|
-
s.version = '0.0
|
3
|
+
s.version = '1.0.0'
|
4
4
|
|
5
5
|
s.summary = 'Cross-platform shell commands.'
|
6
6
|
s.description = %Q{
|
@@ -13,20 +13,20 @@ in the octagon with a pig.
|
|
13
13
|
s.email = 'tthetoad@gmail.com'
|
14
14
|
s.homepage = 'http://www.bitbucket.org/ToadJamb/gems_execute_shell'
|
15
15
|
|
16
|
-
s.license = '
|
16
|
+
s.license = 'LGPLv3'
|
17
17
|
|
18
|
-
s.extra_rdoc_files
|
18
|
+
s.extra_rdoc_files = Dir['README', 'license/*']
|
19
19
|
|
20
20
|
s.require_paths = ['lib']
|
21
|
-
s.files = Dir['lib/**/*.rb', '
|
21
|
+
s.files = Dir['*', 'lib/**/*.rb', 'license/*']
|
22
22
|
s.test_files = Dir['test/**/*.rb']
|
23
23
|
|
24
24
|
s.add_dependency 'Platform', '~> 0.4.0'
|
25
25
|
s.add_dependency 'open4', '~> 1.0.1'
|
26
26
|
s.add_dependency 'win32-open3-19', '~> 0.0.1'
|
27
|
-
s.add_dependency 'app_mode', '~> 1.0.0'
|
28
27
|
|
29
|
-
s.add_development_dependency 'rake_tasks',
|
28
|
+
s.add_development_dependency 'rake_tasks', '~> 2.0.5'
|
29
|
+
s.add_development_dependency 'test_unit_helper', '~> 0.0.1'
|
30
30
|
|
31
31
|
s.has_rdoc = true
|
32
32
|
end
|
data/lib/execute_shell.rb
CHANGED
@@ -1,8 +1,45 @@
|
|
1
|
+
#--
|
2
|
+
################################################################################
|
3
|
+
# Copyright (C) 2011 Travis Herrick #
|
4
|
+
################################################################################
|
5
|
+
# #
|
6
|
+
# \v^V,^!v\^/ #
|
7
|
+
# ~% %~ #
|
8
|
+
# { _ _ } #
|
9
|
+
# ( * - ) #
|
10
|
+
# | / | #
|
11
|
+
# \ _, / #
|
12
|
+
# \__.__/ #
|
13
|
+
# #
|
14
|
+
################################################################################
|
15
|
+
# This program is free software: you can redistribute it #
|
16
|
+
# and/or modify it under the terms of the GNU Lesser General Public License #
|
17
|
+
# as published by the Free Software Foundation, #
|
18
|
+
# either version 3 of the License, or (at your option) any later version. #
|
19
|
+
################################################################################
|
20
|
+
# This program is distributed in the hope that it will be useful, #
|
21
|
+
# but WITHOUT ANY WARRANTY; #
|
22
|
+
# without even the implied warranty of MERCHANTABILITY #
|
23
|
+
# or FITNESS FOR A PARTICULAR PURPOSE. #
|
24
|
+
# See the GNU Lesser General Public License for more details. #
|
25
|
+
# #
|
26
|
+
# You should have received a copy of the GNU Lesser General Public License #
|
27
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
28
|
+
################################################################################
|
29
|
+
#++
|
30
|
+
|
1
31
|
gem_name = File.basename(__FILE__, '.rb')
|
2
32
|
|
3
|
-
require 'app_mode'
|
4
33
|
require 'platform'
|
5
|
-
require 'open4' if [:linux].include?(Platform::IMPL)
|
6
|
-
require 'open3' if [:mingw].include?(Platform::IMPL)
|
7
34
|
|
35
|
+
case Platform::IMPL
|
36
|
+
when :linux
|
37
|
+
require 'open4'
|
38
|
+
when :mingw
|
39
|
+
require 'open3'
|
40
|
+
end
|
41
|
+
|
42
|
+
require_relative File.join(gem_name, 'shell_result')
|
8
43
|
require_relative File.join(gem_name, gem_name)
|
44
|
+
|
45
|
+
ExecuteShell.raise_not_implemented(gem_name) unless ExecuteShell.supported?
|
@@ -15,62 +15,50 @@
|
|
15
15
|
# #
|
16
16
|
################################################################################
|
17
17
|
# This program is free software: you can redistribute it #
|
18
|
-
# and/or modify it under the terms of the GNU General Public License
|
18
|
+
# and/or modify it under the terms of the GNU Lesser General Public License #
|
19
19
|
# as published by the Free Software Foundation, #
|
20
20
|
# either version 3 of the License, or (at your option) any later version. #
|
21
|
-
# #
|
22
|
-
# Commercial licensing may be available for a fee under a different license. #
|
23
21
|
################################################################################
|
24
22
|
# This program is distributed in the hope that it will be useful, #
|
25
23
|
# but WITHOUT ANY WARRANTY; #
|
26
24
|
# without even the implied warranty of MERCHANTABILITY #
|
27
25
|
# or FITNESS FOR A PARTICULAR PURPOSE. #
|
28
|
-
# See the GNU General Public License for more details.
|
26
|
+
# See the GNU Lesser General Public License for more details. #
|
29
27
|
# #
|
30
|
-
# You should have received a copy of the GNU General Public License
|
28
|
+
# You should have received a copy of the GNU Lesser General Public License #
|
31
29
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
32
30
|
################################################################################
|
33
31
|
#++
|
34
32
|
|
35
33
|
# Contains methods for returning output from console commands.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
[:linux, :mingw].include?(Platform::IMPL)
|
59
|
-
|
60
|
-
out = ''
|
61
|
-
err = ''
|
62
|
-
success = nil
|
63
|
-
|
64
|
-
path ||= Dir.getwd
|
65
|
-
|
66
|
-
begin
|
67
|
-
STDOUT.puts command if ExecuteShellMode.development
|
34
|
+
class ExecuteShell
|
35
|
+
class << self
|
36
|
+
# Raises an error indicating that the class/method/feature is not supported.
|
37
|
+
# ==== Input
|
38
|
+
# [text : String] The class/method/feature that isnot supported.
|
39
|
+
def raise_not_implemented(text)
|
40
|
+
raise NotImplementedError,
|
41
|
+
"#{text} has not been implemented for #{Platform::IMPL}."
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns output from a console command.
|
45
|
+
# ==== Input
|
46
|
+
# [command : String] The command to be run.
|
47
|
+
# [path : String : Dir.getwd] The path to use for the command.
|
48
|
+
# ==== Output
|
49
|
+
# [ShellResult] A ShellResult object that contains information
|
50
|
+
# regarding the output, errors, and success.
|
51
|
+
def run(command, path = File.expand_path(Dir.getwd))
|
52
|
+
raise_not_implemented(__method__) unless supported?
|
53
|
+
|
54
|
+
out = ''
|
55
|
+
err = ''
|
68
56
|
|
69
57
|
block = case Platform::IMPL
|
70
58
|
when :mingw
|
71
59
|
lambda {
|
72
60
|
# Run the command and wait for it to execute.
|
73
|
-
|
61
|
+
Open3::popen3('cmd') do |std_in, std_out, std_err, thread|
|
74
62
|
# Set up the command.
|
75
63
|
std_in.puts command
|
76
64
|
|
@@ -85,7 +73,7 @@ module ExecuteShell
|
|
85
73
|
when :linux
|
86
74
|
lambda {
|
87
75
|
# Run the command and wait for it to execute.
|
88
|
-
|
76
|
+
Open4::popen4('bash') do |pid, std_in, std_out, std_err|
|
89
77
|
# Set up the command.
|
90
78
|
std_in.puts command
|
91
79
|
|
@@ -99,93 +87,159 @@ module ExecuteShell
|
|
99
87
|
}
|
100
88
|
end
|
101
89
|
|
102
|
-
|
103
|
-
|
104
|
-
# Success is determined by lack of error text.
|
105
|
-
success = err.empty?
|
90
|
+
wrap_path path, block
|
106
91
|
|
107
|
-
|
108
|
-
if Platform::IMPL == :mingw
|
109
|
-
out.gsub!(/\n\n#{path.gsub(%r[/], '\\\\\\')}>\Z/, '')
|
92
|
+
out = ShellResult.cleanup(command, path, out)
|
110
93
|
|
111
|
-
|
112
|
-
|
113
|
-
replace = path.gsub(%r[/], '\\\\\\')
|
114
|
-
replace += '>'
|
115
|
-
replace += command[0..(command.index(/ /) || 0) - 1]
|
116
|
-
|
117
|
-
# Remove the header portion of the text.
|
118
|
-
# This includes the Microsoft 'banner' text
|
119
|
-
# that consumes the first two lines.
|
120
|
-
out = out.gsub(/\A.+#{replace}.*?$/m, '').strip
|
121
|
-
end
|
94
|
+
return ShellResult.new(out, err)
|
95
|
+
end
|
122
96
|
|
123
|
-
|
124
|
-
|
125
|
-
|
97
|
+
# Indicates whether the specified operating system is supported.
|
98
|
+
# ==== Input
|
99
|
+
# [os : Symbol,String : Platform::IMPL] The operating system to check for.
|
100
|
+
# ==== Output
|
101
|
+
# [Boolean] A boolean value indicating whether the system is supported.
|
102
|
+
# ==== Examples
|
103
|
+
# ExecuteShell.supported? #=> true
|
104
|
+
# ExecuteShell.supported?(:linux) #=> true
|
105
|
+
# ExecuteShell.supported?(:my_os) #=> false
|
106
|
+
def supported?(os = Platform::IMPL)
|
107
|
+
supported_systems.include? os.to_sym
|
108
|
+
end
|
126
109
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
110
|
+
# Returns an array of the supported systems as returned by Platform::IMPL.
|
111
|
+
# ==== Output
|
112
|
+
# [Array] The supported operating systems.
|
113
|
+
# ==== Examples
|
114
|
+
# ExecuteShell.supported_systems #=> [:linux, :mingw]
|
115
|
+
def supported_systems
|
116
|
+
[:linux, :mingw]
|
133
117
|
end
|
134
118
|
|
135
|
-
|
136
|
-
|
119
|
+
# Allows method calls such as run_success? or run_err_out.
|
120
|
+
# ==== Input
|
121
|
+
# [method : Symbol] The missing method that is being called.
|
122
|
+
# [*args : Array] Arguments that were passed to the method.
|
123
|
+
# [&block : Block] The block passed to the method.
|
124
|
+
# ==== Output
|
125
|
+
# The output depends on the method called.
|
126
|
+
#
|
127
|
+
# This method supports any method that starts with "run_" and
|
128
|
+
# combines methods available from a ShellResult object.
|
129
|
+
#
|
130
|
+
# For example, the following are all valid calls:
|
131
|
+
# ExecuteShell.run_success? "echo 'hi'"
|
132
|
+
# ExecuteShell.run_success "echo 'hi'"
|
133
|
+
# ExecuteShell.run_success_err_out "echo 'hi'"
|
134
|
+
# ExecuteShell.run_out_to_s_err "echo 'hi'"
|
135
|
+
#
|
136
|
+
# If only one method name is provided, that value will be returned alone.
|
137
|
+
#
|
138
|
+
# If more than one method name is provided, the results will be returned
|
139
|
+
# in an array listing the results in the order specified in the method call.
|
140
|
+
def method_missing(method, *args, &block)
|
141
|
+
return super unless method.to_s =~ /^run_/
|
142
|
+
|
143
|
+
# Execute the command.
|
144
|
+
shell_result = run(*args)
|
145
|
+
|
146
|
+
# Get a list of the requested result values.
|
147
|
+
method_list = method.to_s.sub(/^run_/, '').split('_')
|
148
|
+
|
149
|
+
results = []
|
150
|
+
skip = nil
|
151
|
+
|
152
|
+
# Loop through the methods, building an array of result values.
|
153
|
+
method_list.each_with_index do |item, i|
|
154
|
+
# Skip to the next one if two methods have already been combined.
|
155
|
+
# i.e. 'to_s'
|
156
|
+
if skip
|
157
|
+
skip = false
|
158
|
+
next
|
159
|
+
end
|
160
|
+
|
161
|
+
item += '?' if item == 'success'
|
162
|
+
|
163
|
+
if item == 'to'
|
164
|
+
item += "_#{method_list[i + 1]}"
|
165
|
+
skip = true
|
166
|
+
end
|
167
|
+
|
168
|
+
results << shell_result.send(item.to_sym)
|
169
|
+
end
|
137
170
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# ==== Output
|
146
|
-
# [String] The error information in a readable format.
|
147
|
-
def format_error(exception)
|
148
|
-
error_format = '%s: %s%s'
|
149
|
-
error_format % [exception.class, exception.message,
|
150
|
-
ExecuteShellMode.development ? "\n#{exception.backtrace.join("\n")}" : '']
|
151
|
-
end
|
171
|
+
# Return the result(s) in an appropriate way.
|
172
|
+
return case results.length
|
173
|
+
when 0; nil
|
174
|
+
when 1; results[0]
|
175
|
+
else; results
|
176
|
+
end
|
177
|
+
end
|
152
178
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
179
|
+
# Indicates that this class will respond to
|
180
|
+
# calls such as run_success? or run_err_out.
|
181
|
+
# ==== Input
|
182
|
+
# [method : Symbol] The method that is being checked.
|
183
|
+
# [include_private : Boolean] Whether to include private methods
|
184
|
+
# in the search.
|
185
|
+
# ==== Output
|
186
|
+
# [Boolean] Indicates whether the class responds to the specified method.
|
187
|
+
# ==== Examples
|
188
|
+
# a #=> b
|
189
|
+
def respond_to_missing?(method, include_private)
|
190
|
+
return super unless method.to_s =~ /^run_/
|
191
|
+
|
192
|
+
method_list = method.to_s.sub(/^run_/, '').split('_')
|
193
|
+
|
194
|
+
skip = nil
|
195
|
+
|
196
|
+
shell_result = ShellResult.new('', '')
|
197
|
+
|
198
|
+
# Loop through the methods, checking the validity of each.
|
199
|
+
method_list.each_with_index do |item, i|
|
200
|
+
# Skip to the next one if two methods have already been combined.
|
201
|
+
# i.e. 'to_s'
|
202
|
+
if skip
|
203
|
+
skip = false
|
204
|
+
next
|
205
|
+
end
|
206
|
+
|
207
|
+
item += '?' if item == 'success'
|
208
|
+
|
209
|
+
if item == 'to'
|
210
|
+
item += "_#{method_list[i + 1]}"
|
211
|
+
skip = true
|
212
|
+
end
|
213
|
+
|
214
|
+
# Return false if the ShellResult object does not respond to the method.
|
215
|
+
return false unless shell_result.respond_to?(item.to_sym)
|
216
|
+
end
|
162
217
|
|
163
|
-
|
164
|
-
# ==== Input
|
165
|
-
# [path : String] The path to change to prior to running the block.
|
166
|
-
# [block : Proc] The code block to execute.
|
167
|
-
# [*args : Array] Any other parameters
|
168
|
-
# that will be passed on to <tt>block</tt>.
|
169
|
-
# ==== Output
|
170
|
-
# [Boolean] Indicates whether the block was executed successfully.
|
171
|
-
# [String] Any error messages from trapped errors.
|
172
|
-
def wrap_path(path, block, *args)
|
173
|
-
path ||= File.expand_path(Dir.getwd)
|
174
|
-
original = File.expand_path(Dir.getwd)
|
175
|
-
out = nil
|
176
|
-
|
177
|
-
STDOUT.puts path if ExecuteShellMode.development
|
178
|
-
|
179
|
-
begin
|
180
|
-
Dir.chdir path unless path == original
|
181
|
-
block.call(*args)
|
182
|
-
rescue Exception => exc
|
183
|
-
# Format exception messages.
|
184
|
-
out = format_error(exc)
|
185
|
-
ensure
|
186
|
-
Dir.chdir original unless path == original
|
218
|
+
return true
|
187
219
|
end
|
188
220
|
|
189
|
-
|
221
|
+
########################################################################
|
222
|
+
private
|
223
|
+
########################################################################
|
224
|
+
|
225
|
+
# Runs a block of code by changing the path first.
|
226
|
+
# ==== Input
|
227
|
+
# [path : String] The path to change to prior to running the block.
|
228
|
+
# [block : Proc] The code block to execute.
|
229
|
+
# [*args : Array] Any other parameters
|
230
|
+
# that will be passed on to <tt>block</tt>.
|
231
|
+
# ==== Output
|
232
|
+
# [String] Any error messages from trapped errors.
|
233
|
+
def wrap_path(path, block, *args)
|
234
|
+
path ||= File.expand_path(Dir.getwd)
|
235
|
+
original = File.expand_path(Dir.getwd)
|
236
|
+
|
237
|
+
begin
|
238
|
+
Dir.chdir path unless path == original
|
239
|
+
block.call(*args)
|
240
|
+
ensure
|
241
|
+
Dir.chdir original unless path == original
|
242
|
+
end
|
243
|
+
end
|
190
244
|
end
|
191
245
|
end
|