ProcessPilot 0.0.1.20120118

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ = Muriel Salvan (murielsalvan@users.sourceforge.net)
data/ChangeLog ADDED
@@ -0,0 +1,5 @@
1
+ = Process Pilot Release History
2
+
3
+ == 0.0.1.20120118 (Beta)
4
+
5
+ * Initial public release.
data/Credits ADDED
@@ -0,0 +1,18 @@
1
+ = Projects used by Process Pilot
2
+
3
+ == ChildProcess
4
+ * Jari Bakken (http://github.com/jarib)
5
+ * http://github.com/jarib/childprocess
6
+ * Used to internally pilot stdin in real time
7
+
8
+ == Ruby
9
+ * Yukihiro « matz » Matsumoto (http://www.rubyist.net/~matz/)
10
+ * http://www.ruby-lang.org/
11
+ * Thanks a lot Matz for this truly wonderful language !
12
+
13
+ == rUtilAnts
14
+ * Muriel Salvan (http://murielsalvan.users.sourceforge.net)
15
+ * http://rutilants.sourceforge.net
16
+ * Used for logging.
17
+
18
+ = People that helped a lot in developing Process Pilot
data/LICENSE ADDED
@@ -0,0 +1,31 @@
1
+
2
+ The license stated herein is a copy of the BSD License (modified on July 1999).
3
+ The AUTHOR mentionned below refers to the list of people involved in the
4
+ creation and modification of any file included in the delivered package.
5
+ This list is found in the file named AUTHORS.
6
+ The AUTHORS and LICENSE files have to be included in any release of software
7
+ embedding source code of this package, or using it as a derivative software.
8
+
9
+ Copyright (c) 2010 - 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright notice,
15
+ this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
25
+ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31
+ OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,18 @@
1
+ -- This file is best viewed when processed by rdoc.
2
+ ++
3
+
4
+ = Process Pilot
5
+
6
+ Ruby library to pilot interactive command line processes in real time.
7
+
8
+ == Where is the documentation ?
9
+
10
+ Check the website at http://processpilot.sourceforge.net
11
+
12
+ == Who wrote it ?
13
+
14
+ Check the AUTHORS[link:files/AUTHORS.html] file.
15
+
16
+ == What is the license ?
17
+
18
+ You can find out in the LICENSE[link:files/LICENSE.html] file.
data/ReleaseInfo ADDED
@@ -0,0 +1,8 @@
1
+
2
+ # This file has been generated by RubyPackager during a delivery.
3
+ # More info about RubyPackager: http://rubypackager.sourceforge.net
4
+ {
5
+ :Version => '0.0.1.20120118',
6
+ :Tags => [ 'Beta' ],
7
+ :DevStatus => 'Beta'
8
+ }
@@ -0,0 +1,197 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ require 'childprocess'
7
+ require 'tempfile'
8
+
9
+ module ProcessPilot
10
+
11
+ # Pilot a process.
12
+ # This will create a new thread for the process to be run.
13
+ # If the process is a Ruby process, you can force STDOUT sync by specifying it in options. In this case the command line should begin with the Ruby file name to be executed (don't use ruby executable, and specifiy ruby options in iOptions[:RubyCmdLine]).
14
+ #
15
+ # Parameters:
16
+ # * *iCmdLine* (<em>list<String></em>): The process' command line
17
+ # * *iOptions* (<em>map<Symbol,Object></em>): Optional arguments [optional = nil]:
18
+ # ** *:ForceRubyProcessSync* (_Boolean_): If the command line is a Ruby process, force setting STDOUT to be synced. [optional = false]
19
+ # ** *:RubyCmdLine* (<em>list<String></em>): Command line of Ruby interpreter with options (used only if :ForceRubyProcessSync is true) [optional = ['ruby']]
20
+ # ** *:Debug* (_Boolean_): Do we activate some debugging traces ? (need rUtilAnts gem if activated) [optional = false]
21
+ # * _CodeBlock_: The code called for process piloting:
22
+ # ** Parameters:
23
+ # ** *oStdIN* (_IO_): The process' STDIN
24
+ # ** *iStdOUT* (_IO_): The process' STDOUT
25
+ # ** *iStdERR* (_IO_): The process' STDERR
26
+ # ** *iChildProcess* (_ChildProcess_): The corresponding child process. Don't use it to pilot std* IO objects.
27
+ # ** Return:
28
+ # ** _Boolean_: Do we have to wait until the process' completion ?
29
+ def self.pilot(*iArgs)
30
+ iCmdLine = iArgs
31
+ iOptions = (iArgs[-1].is_a?(Hash)) ? iArgs.pop : {}
32
+ iForceRubyProcessSync = (iOptions[:ForceRubyProcessSync] || false)
33
+ iRubyCmdLine = (iOptions[:RubyCmdLine] || ['ruby'])
34
+ iDebug = (iOptions[:Debug] || false)
35
+
36
+ if ((iDebug) and (require 'rUtilAnts/Logging'))
37
+ # First time it was required: set it up
38
+ RUtilAnts::Logging::initializeLogging('', '')
39
+ activateLogDebug(true)
40
+ end
41
+
42
+ # Wrap eventually Ruby command line
43
+ lRealCmdLine = (iForceRubyProcessSync) ? iRubyCmdLine + [ "#{File.dirname(__FILE__)}/wrapper.rb" ] + iCmdLine : iCmdLine
44
+
45
+ logDebug "[ProcessPilot] Command line: #{lRealCmdLine.inspect}" if iDebug
46
+ lProcess = ChildProcess.build(*lRealCmdLine)
47
+
48
+ # Indication of stdin usage
49
+ lProcess.duplex = true
50
+
51
+ # Specify files for stdout/stderr
52
+ # ! Use w+ mode to make it possible for our monitoring thread to reopen the file in r mode
53
+ Tempfile.open('processpilot.stdout') do |oStdOUT|
54
+ logDebug "[ProcessPilot] STDOUT file: #{oStdOUT.path}" if iDebug
55
+ lProcess.io.stdout = oStdOUT
56
+ Tempfile.open('processpilot.stderr') do |oStdERR|
57
+ logDebug "[ProcessPilot] STDERR file: #{oStdERR.path}" if iDebug
58
+ lProcess.io.stderr = oStdERR
59
+
60
+ # Start the process: this creates the background thread running our command
61
+ lProcess.start
62
+
63
+ # In our main thread: open the STDOUT/ERR files
64
+ lStdOUT = File.open(oStdOUT.path, 'r')
65
+ lStdERR = File.open(oStdERR.path, 'r')
66
+ lStdIN = lProcess.io.stdin
67
+
68
+ # Call client code
69
+ lWaitUntilCompletion = yield(lStdIN, lStdOUT, lStdERR, lProcess)
70
+
71
+ # Wait for the process termination in case it is late
72
+ if (lWaitUntilCompletion)
73
+ while (!lProcess.exited?)
74
+ sleep 1
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
84
+ # Define some helpers that can be handy in case of process piloting from IO
85
+ class IO
86
+
87
+ # Exception thrown when timeout has been reached
88
+ class TimeOutError < RuntimeError
89
+ end
90
+
91
+ # Implement a blocking read of a new string ending with newline.
92
+ # Make sure we wait for the end of a string before returning.
93
+ # This is done to ensure we will get the new string we are expecting.
94
+ # If the timeout is reached, an exception is thrown.
95
+ #
96
+ # Parameters:
97
+ # * *iOptions* (<em>map<Symbol,Object></em>): Optional arguments [optional = {}]:
98
+ # ** *:TimeOutSecs* (_Integer_): Time out in seconds (nil = no timeout) [optional = nil]
99
+ # ** *:PollingIntervalSecs* (_Float_): Polling interval in seconds [optional = 0.1]
100
+ # ** *:ChildProcess* (_ChildProcess_): Corresponding child process linked to this IO. Can be used to detect the end of IO. [optional = nil]
101
+ # Return:
102
+ # * _String_: The next string from IO (separator is $/). Can be empty if the corresponding child process has exited already.
103
+ def gets_blocking(iOptions = {})
104
+ return get_data_blocking(
105
+ Proc.new { |iStr| iStr[-1..-1] == $/ },
106
+ iOptions
107
+ ) do |iStr|
108
+ next self.gets
109
+ end
110
+ end
111
+
112
+ # Implement a blocking read of a given size.
113
+ # Make sure we wait for the end of a string before returning.
114
+ # This is done to ensure we will get the new string we are expecting.
115
+ # If the timeout is reached, an exception is thrown.
116
+ #
117
+ # Parameters:
118
+ # * *iSize* (_Integer_): Size of the data to read
119
+ # * *iOptions* (<em>map<Symbol,Object></em>): Optional arguments [optional = {}]:
120
+ # ** *:TimeOutSecs* (_Integer_): Time out in seconds (nil = no timeout) [optional = nil]
121
+ # ** *:PollingIntervalSecs* (_Float_): Polling interval in seconds [optional = 0.1]
122
+ # ** *:ChildProcess* (_ChildProcess_): Corresponding child process linked to this IO. Can be used to detect the end of IO. [optional = nil]
123
+ # Return:
124
+ # * _String_: The next string from IO (separator is $/). Can be empty if the corresponding child process has exited already.
125
+ def read_blocking(iSize, iOptions = {})
126
+ return get_data_blocking(
127
+ Proc.new { |iStr| iStr.size == iSize },
128
+ iOptions
129
+ ) do |iStr|
130
+ next self.read(iSize-iStr.size)
131
+ end
132
+ end
133
+
134
+ # Send a synchronized input to an IO.
135
+ # Make sure it will be flushed.
136
+ #
137
+ # Parameters:
138
+ # * *iStr* (_String_): The string to send
139
+ def write_flushed(iStr)
140
+ self.write iStr
141
+ self.flush
142
+ end
143
+
144
+ private
145
+
146
+ # Implement a blocking read of a data unless the data read conforms to a given validation code.
147
+ # Take a validation proc to know if the data was read correctly, and yields code to read effectively data.
148
+ # Proper implementation should have a more efficient algo.
149
+ # If the timeout is reached, an exception is thrown.
150
+ #
151
+ # Parameters:
152
+ # * *iProcValidation* (_Proc_): The validation proc:
153
+ # ** Parameters:
154
+ # ** *iData* (_String_): The data to validate
155
+ # ** Return:
156
+ # ** _Boolean_: Is the data valid ?
157
+ # * *iOptions* (<em>map<Symbol,Object></em>): Optional arguments [optional = {}]:
158
+ # ** *:TimeOutSecs* (_Integer_): Time out in seconds (nil = no timeout) [optional = nil]
159
+ # ** *:PollingIntervalSecs* (_Float_): Polling interval in seconds [optional = 0.1]
160
+ # ** *:ChildProcess* (_ChildProcess_): Corresponding child process linked to this IO. Can be used to detect the end of IO. [optional = nil]
161
+ # * _CodeBlock_: Code called to read data effectively:
162
+ # ** Parameters:
163
+ # ** *iStr* (_String_): The data already read
164
+ # ** Return:
165
+ # ** _String_: String of data read (can be nil if no data was read)
166
+ # Return:
167
+ # * _String_: The next string from IO (separator is $/). Can be empty if the corresponding child process has exited already.
168
+ def get_data_blocking(iProcValidation, iOptions = {})
169
+ rStr = ''
170
+ iPollingInterval = (iOptions[:PollingIntervalSecs] || 0.1)
171
+ iTimeOutSecs = iOptions[:TimeOutSecs]
172
+ iChildProcess = iOptions[:ChildProcess]
173
+
174
+ require 'time' if (iTimeOutSecs != nil)
175
+
176
+ # Concatenate chunks unless we have the separator.
177
+ # As we deal with stdin flow, it is possible to have a line without ending already written in the file and already flushed by the IO.
178
+ lTimeOut = (iTimeOutSecs == nil) ? nil : Time.now + iTimeOutSecs
179
+ while (!iProcValidation.call(rStr))
180
+ lNewChunk = nil
181
+ while (lNewChunk == nil)
182
+ lNewChunk = yield(rStr)
183
+ #$stdout.puts "===== Read #{lNewChunk.inspect}"
184
+ break if ((iChildProcess != nil) and (iChildProcess.exited?))
185
+ if (lNewChunk == nil)
186
+ sleep iPollingInterval
187
+ raise TimeOutError.new("Timeout of #{iTimeOutSecs} secs reached while waiting for data.") if ((lTimeOut != nil) and (Time.now > lTimeOut))
188
+ end
189
+ end
190
+ rStr.concat(lNewChunk) if (lNewChunk != nil)
191
+ break if ((iChildProcess != nil) and (iChildProcess.exited?))
192
+ end
193
+
194
+ return rStr
195
+ end
196
+
197
+ end
@@ -0,0 +1,16 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ # Disable STDOUT caching
7
+ $stdout.sync = true
8
+
9
+ # Get the rb file to execute
10
+ iRBFileName = ARGV[0]
11
+
12
+ # Adapt ARGV for this rb file to get its arguments correctly
13
+ # TODO: Maybe adapt other variables ...
14
+ ARGV.replace(ARGV[1..-1])
15
+
16
+ load iRBFileName
@@ -0,0 +1,241 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module ProcessPilotTest
7
+
8
+ module Common
9
+
10
+ # Get the OS dependant command line for testing non interactive processes
11
+ #
12
+ # Return:
13
+ # * <em>list<String></em>: Command line
14
+ def getNotInteractiveCmdLine
15
+ rCmdLine = nil
16
+
17
+ case $rUtilAnts_Platform_Info.os
18
+ when RUtilAnts::Platform::OS_WINDOWS
19
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/NotInteractive.bat"]
20
+ when RUtilAnts::Platform::OS_LINUX
21
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/NotInteractive.sh"]
22
+ when RUtilAnts::Platform::OS_CYGWIN
23
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/NotInteractive.sh"]
24
+ else
25
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/NotInteractive.sh"]
26
+ end
27
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
28
+
29
+ return rCmdLine
30
+ end
31
+
32
+ # Get the OS dependant command line for testing non interactive processes on STDERR
33
+ #
34
+ # Return:
35
+ # * <em>list<String></em>: Command line
36
+ def getNotInteractiveCmdLineSTDERR
37
+ rCmdLine = nil
38
+
39
+ case $rUtilAnts_Platform_Info.os
40
+ when RUtilAnts::Platform::OS_WINDOWS
41
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/NotInteractiveSTDERR.bat"]
42
+ when RUtilAnts::Platform::OS_LINUX
43
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/NotInteractiveSTDERR.sh"]
44
+ when RUtilAnts::Platform::OS_CYGWIN
45
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/NotInteractiveSTDERR.sh"]
46
+ else
47
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/NotInteractiveSTDERR.sh"]
48
+ end
49
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
50
+
51
+ return rCmdLine
52
+ end
53
+
54
+ # Get the OS dependant command line for testing interactive processes
55
+ #
56
+ # Return:
57
+ # * <em>list<String></em>: Command line
58
+ def getInteractiveCmdLine
59
+ rCmdLine = nil
60
+
61
+ case $rUtilAnts_Platform_Info.os
62
+ when RUtilAnts::Platform::OS_WINDOWS
63
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/Interactive.bat"]
64
+ when RUtilAnts::Platform::OS_LINUX
65
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/Interactive.sh"]
66
+ when RUtilAnts::Platform::OS_CYGWIN
67
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/Interactive.sh"]
68
+ else
69
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/Interactive.sh"]
70
+ end
71
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
72
+
73
+ return rCmdLine
74
+ end
75
+
76
+ # Get the OS dependant command line for testing interactive processes on STDERR
77
+ #
78
+ # Return:
79
+ # * <em>list<String></em>: Command line
80
+ def getInteractiveCmdLineSTDERR
81
+ rCmdLine = nil
82
+
83
+ case $rUtilAnts_Platform_Info.os
84
+ when RUtilAnts::Platform::OS_WINDOWS
85
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/InteractiveSTDERR.bat"]
86
+ when RUtilAnts::Platform::OS_LINUX
87
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractiveSTDERR.sh"]
88
+ when RUtilAnts::Platform::OS_CYGWIN
89
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractiveSTDERR.sh"]
90
+ else
91
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractiveSTDERR.sh"]
92
+ end
93
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
94
+
95
+ return rCmdLine
96
+ end
97
+
98
+ # Get the OS dependant command line for testing interactive processes with a prompt
99
+ #
100
+ # Return:
101
+ # * <em>list<String></em>: Command line
102
+ def getInteractivePromptCmdLine
103
+ rCmdLine = nil
104
+
105
+ case $rUtilAnts_Platform_Info.os
106
+ when RUtilAnts::Platform::OS_WINDOWS
107
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/InteractivePrompt.bat"]
108
+ when RUtilAnts::Platform::OS_LINUX
109
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractivePrompt.sh"]
110
+ when RUtilAnts::Platform::OS_CYGWIN
111
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractivePrompt.sh"]
112
+ else
113
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractivePrompt.sh"]
114
+ end
115
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
116
+
117
+ return rCmdLine
118
+ end
119
+
120
+ # Get the OS dependant command line for testing interactive processes with a prompt on STDERR
121
+ #
122
+ # Return:
123
+ # * <em>list<String></em>: Command line
124
+ def getInteractivePromptCmdLineSTDERR
125
+ rCmdLine = nil
126
+
127
+ case $rUtilAnts_Platform_Info.os
128
+ when RUtilAnts::Platform::OS_WINDOWS
129
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/InteractivePromptSTDERR.bat"]
130
+ when RUtilAnts::Platform::OS_LINUX
131
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractivePromptSTDERR.sh"]
132
+ when RUtilAnts::Platform::OS_CYGWIN
133
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractivePromptSTDERR.sh"]
134
+ else
135
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractivePromptSTDERR.sh"]
136
+ end
137
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
138
+
139
+ return rCmdLine
140
+ end
141
+
142
+ # Get the OS dependant command line for testing interactive processes with several prompts
143
+ #
144
+ # Return:
145
+ # * <em>list<String></em>: Command line
146
+ def getInteractiveSeveralPrompts
147
+ rCmdLine = nil
148
+
149
+ case $rUtilAnts_Platform_Info.os
150
+ when RUtilAnts::Platform::OS_WINDOWS
151
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Windows/InteractiveSeveralPrompts.bat"]
152
+ when RUtilAnts::Platform::OS_LINUX
153
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractiveSeveralPrompts.sh"]
154
+ when RUtilAnts::Platform::OS_CYGWIN
155
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractiveSeveralPrompts.sh"]
156
+ else
157
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Bash/InteractiveSeveralPrompts.sh"]
158
+ end
159
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
160
+
161
+ return rCmdLine
162
+ end
163
+
164
+ # Get the command line for testing synced Ruby programs
165
+ #
166
+ # Return:
167
+ # * <em>list<String></em>: Command line
168
+ def getSyncedRubyCmdLine
169
+ rCmdLine = ['ruby', "#{$ProcessPilotTest_RootPath}/test/Programs/Ruby/SyncedSTDOUT.rb"]
170
+
171
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
172
+
173
+ return rCmdLine
174
+ end
175
+
176
+ # Get the command line for testing normal Ruby programs
177
+ #
178
+ # Return:
179
+ # * <em>list<String></em>: Command line
180
+ def getNormalRubyCmdLine
181
+ rCmdLine = ['ruby', "#{$ProcessPilotTest_RootPath}/test/Programs/Ruby/NormalSTDOUT.rb"]
182
+
183
+ rCmdLine << { :Debug => true } if ($ProcessPilotTest_Debug)
184
+
185
+ return rCmdLine
186
+ end
187
+
188
+ # Get the command line for testing normal Ruby programs and forcing them to sync
189
+ #
190
+ # Return:
191
+ # * <em>list<String></em>: Command line
192
+ def getNormalRubyWithSyncCmdLine
193
+ rCmdLine = ["#{$ProcessPilotTest_RootPath}/test/Programs/Ruby/NormalSTDOUT.rb"]
194
+
195
+ lOptions = {
196
+ :ForceRubyProcessSync => true
197
+ }
198
+ lOptions[:Debug] = true if ($ProcessPilotTest_Debug)
199
+ rCmdLine << lOptions
200
+
201
+ return rCmdLine
202
+ end
203
+
204
+ # Assert a common given scenario.
205
+ # This has been put in such a method as the same scenario is used in different scripts.
206
+ #
207
+ # Parameters:
208
+ # * *oStdIN* (_IO_): STDIN
209
+ # * *iStdOUT* (_IO_): STDOUT
210
+ # * *iStdERR* (_IO_): STDERR
211
+ # * *iChildProcess* (_ChildProcess_): Corresponding ChildProcess
212
+ def assert_testing_scenario(oStdIN, iStdOUT, iStdERR, iChildProcess)
213
+ assert_equal "STDOUT Line 1\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
214
+ assert_equal 'Enter string 1 from STDOUT: ', iStdOUT.read_blocking(28, :ChildProcess => iChildProcess)
215
+ assert_raise IO::TimeOutError do
216
+ iStdERR.read_blocking(1, :TimeOutSecs => 1, :ChildProcess => iChildProcess)
217
+ end
218
+ assert_raise IO::TimeOutError do
219
+ iStdOUT.read_blocking(1, :TimeOutSecs => 1, :ChildProcess => iChildProcess)
220
+ end
221
+ oStdIN.write_flushed "Test String 1\n"
222
+ assert_equal "STDOUT Line 2 Test String 1\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
223
+ assert_equal "STDERR Line 1\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
224
+ assert_equal 'Enter string 2 from STDERR: ', iStdERR.read_blocking(28, :ChildProcess => iChildProcess)
225
+ assert_raise IO::TimeOutError do
226
+ iStdERR.read_blocking(1, :TimeOutSecs => 1, :ChildProcess => iChildProcess)
227
+ end
228
+ assert_raise IO::TimeOutError do
229
+ iStdOUT.read_blocking(1, :TimeOutSecs => 1, :ChildProcess => iChildProcess)
230
+ end
231
+ oStdIN.write_flushed "Test String 2\n"
232
+ assert_equal "STDOUT Line 3 Test String 2\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
233
+ assert_equal "STDERR Line 2\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
234
+ assert_equal '', iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
235
+ assert_equal '', iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
236
+ assert iChildProcess.exited?
237
+ end
238
+
239
+ end
240
+
241
+ end
@@ -0,0 +1,114 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module ProcessPilotTest
7
+
8
+ class NonRuby < ::Test::Unit::TestCase
9
+
10
+ include ProcessPilotTest::Common
11
+
12
+ def testNotInteractiveSTDOUT
13
+ ProcessPilot::pilot(*getNotInteractiveCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
14
+ assert_equal "Hello World\n", iStdOUT.gets_blocking(:TimeOutSecs => 1)
15
+ assert_raise IO::TimeOutError do
16
+ iStdERR.gets_blocking(:TimeOutSecs => 1)
17
+ end
18
+ assert iChildProcess.exited?
19
+ next true
20
+ end
21
+ end
22
+
23
+ def testNotInteractiveSTDOUTEndOfProcess
24
+ ProcessPilot::pilot(*getNotInteractiveCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
25
+ assert_equal "Hello World\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
26
+ assert_equal '', iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
27
+ assert_equal '', iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
28
+ assert iChildProcess.exited?
29
+ next true
30
+ end
31
+ end
32
+
33
+ def testNotInteractiveSTDERR
34
+ ProcessPilot::pilot(*getNotInteractiveCmdLineSTDERR) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
35
+ assert_equal '', iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
36
+ assert_equal "Hello World\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
37
+ assert_equal '', iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
38
+ assert iChildProcess.exited?
39
+ next true
40
+ end
41
+ end
42
+
43
+ def testInteractiveSTDOUT
44
+ ProcessPilot::pilot(*getInteractiveCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
45
+ assert_equal "Hello World\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
46
+ assert_raise IO::TimeOutError do
47
+ iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
48
+ end
49
+ oStdIN.write_flushed "Test String\n"
50
+ assert_equal "Hello Test String\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
51
+ assert_equal '', iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
52
+ assert iChildProcess.exited?
53
+ next true
54
+ end
55
+ end
56
+
57
+ def testInteractiveSTDERR
58
+ ProcessPilot::pilot(*getInteractiveCmdLineSTDERR) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
59
+ assert_raise IO::TimeOutError do
60
+ iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
61
+ end
62
+ assert_equal "Hello World\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
63
+ assert_raise IO::TimeOutError do
64
+ iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
65
+ end
66
+ oStdIN.write_flushed "Test String\n"
67
+ assert_equal '', iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
68
+ assert_equal "Hello Test String\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
69
+ assert_equal '', iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
70
+ assert iChildProcess.exited?
71
+ next true
72
+ end
73
+ end
74
+
75
+ def testInteractiveWithPromptSTDOUT
76
+ ProcessPilot::pilot(*getInteractivePromptCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
77
+ assert_equal "Hello World\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
78
+ assert_equal 'Enter string: ', iStdOUT.read_blocking(14, :ChildProcess => iChildProcess)
79
+ assert_raise IO::TimeOutError do
80
+ iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
81
+ end
82
+ oStdIN.write_flushed "Test String\n"
83
+ assert_equal "Hello Test String\n", iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
84
+ assert_equal '', iStdOUT.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
85
+ assert iChildProcess.exited?
86
+ next true
87
+ end
88
+ end
89
+
90
+ def testInteractiveWithPromptSTDERR
91
+ ProcessPilot::pilot(*getInteractivePromptCmdLineSTDERR) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
92
+ assert_equal "Hello World\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
93
+ assert_equal 'Enter string: ', iStdERR.read_blocking(14, :ChildProcess => iChildProcess)
94
+ assert_raise IO::TimeOutError do
95
+ iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
96
+ end
97
+ oStdIN.write_flushed "Test String\n"
98
+ assert_equal "Hello Test String\n", iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
99
+ assert_equal '', iStdERR.gets_blocking(:TimeOutSecs => 1, :ChildProcess => iChildProcess)
100
+ assert iChildProcess.exited?
101
+ next true
102
+ end
103
+ end
104
+
105
+ def testSeveralPrompts
106
+ ProcessPilot::pilot(*getInteractiveSeveralPrompts) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
107
+ assert_testing_scenario(oStdIN, iStdOUT, iStdERR, iChildProcess)
108
+ next true
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ end
@@ -0,0 +1,38 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module ProcessPilotTest
7
+
8
+ class Ruby < ::Test::Unit::TestCase
9
+
10
+ include ProcessPilotTest::Common
11
+
12
+ def testSyncedSTDOUT
13
+ ProcessPilot::pilot(*getSyncedRubyCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
14
+ assert_testing_scenario(oStdIN, iStdOUT, iStdERR, iChildProcess)
15
+ next true
16
+ end
17
+ end
18
+
19
+ def testNormalSTDOUT
20
+ ProcessPilot::pilot(*getNormalRubyCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
21
+ assert_raise IO::TimeOutError do
22
+ iStdOUT.read_blocking(1, :TimeOutSecs => 1, :ChildProcess => iChildProcess)
23
+ end
24
+ iChildProcess.stop
25
+ next true
26
+ end
27
+ end
28
+
29
+ def testNormalSTDOUTWithForceSync
30
+ ProcessPilot::pilot(*getNormalRubyWithSyncCmdLine) do |oStdIN, iStdOUT, iStdERR, iChildProcess|
31
+ assert_testing_scenario(oStdIN, iStdOUT, iStdERR, iChildProcess)
32
+ next true
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+
3
+ echo "Hello World"
4
+ read VAR
5
+ echo "Hello ${VAR}"
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ echo "Hello World"
4
+ echo -n "Enter string: "
5
+ read VAR
6
+ echo "Hello ${VAR}"
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ echo "Hello World" >&2
4
+ echo -n "Enter string: " >&2
5
+ read VAR
6
+ echo "Hello ${VAR}" >&2
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+
3
+ echo "Hello World" >&2
4
+ read VAR
5
+ echo "Hello ${VAR}" >&2
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+
3
+ echo "STDOUT Line 1"
4
+ echo -n "Enter string 1 from STDOUT: "
5
+ read VAR
6
+ echo "STDOUT Line 2 ${VAR}"
7
+ echo "STDERR Line 1" >&2
8
+ echo -n "Enter string 2 from STDERR: " >&2
9
+ read VAR
10
+ echo "STDOUT Line 3 ${VAR}"
11
+ echo "STDERR Line 2" >&2
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ echo "Hello World"
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ echo "Hello World" >&2
@@ -0,0 +1,8 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ require "#{File.dirname(__FILE__)}/Scenario.rb"
7
+
8
+ ProcessPilotTest::Scenario::run
@@ -0,0 +1,25 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module ProcessPilotTest
7
+
8
+ module Scenario
9
+
10
+ # Execute the testing scenario
11
+ def self.run
12
+ $stdout.puts 'STDOUT Line 1'
13
+ $stdout.write 'Enter string 1 from STDOUT: '
14
+ lVar = $stdin.gets
15
+ $stdout.puts "STDOUT Line 2 #{lVar}"
16
+ $stderr.puts 'STDERR Line 1'
17
+ $stderr.write 'Enter string 2 from STDERR: '
18
+ lVar = $stdin.gets
19
+ $stdout.puts "STDOUT Line 3 #{lVar}"
20
+ $stderr.puts 'STDERR Line 2'
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,10 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ $stdout.sync = true
7
+
8
+ require "#{File.dirname(__FILE__)}/Scenario.rb"
9
+
10
+ ProcessPilotTest::Scenario::run
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ echo Hello World
3
+ set /p var="" %=%
4
+ echo Hello %var%
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ echo Hello World
3
+ set /p var="Enter string: " %=%
4
+ echo Hello %var%
@@ -0,0 +1,5 @@
1
+ @echo off
2
+ echo Hello World>&2
3
+ echo/|set /p ="Enter string: " >&2
4
+ set /p var= %=%
5
+ echo Hello %var%>&2
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ echo Hello World >&2
3
+ set /p var="" %=%
4
+ echo Hello %var% >&2
@@ -0,0 +1,9 @@
1
+ @echo off
2
+ echo STDOUT Line 1
3
+ set /p var="Enter string 1 from STDOUT: " %=%
4
+ echo STDOUT Line 2 %var%
5
+ echo "STDERR Line 1">&2
6
+ echo/|set /p ="Enter string 2 from STDERR: " >&2
7
+ set /p var= %=%
8
+ echo STDOUT Line 3 %var%
9
+ echo "STDERR Line 2">&2
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ echo Hello World
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ echo Hello World>&2
data/test/run.rb ADDED
@@ -0,0 +1,30 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ $ProcessPilotTest_Debug = true
7
+
8
+ require 'test/unit'
9
+ require 'rUtilAnts/Logging'
10
+ RUtilAnts::Logging::initializeLogging('', '')
11
+ activateLogDebug($ProcessPilotTest_Debug)
12
+ require 'rUtilAnts/Misc'
13
+ RUtilAnts::Misc::initializeMisc
14
+ require 'rUtilAnts/Platform'
15
+ RUtilAnts::Platform::initializePlatform
16
+
17
+ $ProcessPilotTest_RootPath = File.expand_path("#{File.dirname(__FILE__)}/..")
18
+
19
+ # Add the test directory to the current load path
20
+ $: << "#{$ProcessPilotTest_RootPath}/test"
21
+ # And the lib one too
22
+ $: << "#{$ProcessPilotTest_RootPath}/lib"
23
+
24
+ # Require the main library
25
+ require 'processpilot/processpilot'
26
+
27
+ # Load test files to execute
28
+ require 'ProcessPilotTest/Common'
29
+ require 'ProcessPilotTest/NonRuby'
30
+ require 'ProcessPilotTest/Ruby'
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ProcessPilot
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ - 20120118
10
+ version: 0.0.1.20120118
11
+ platform: ruby
12
+ authors:
13
+ - Muriel Salvan
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-01-18 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rUtilAnts
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ - 3
32
+ version: "0.3"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: childprocess
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 0
45
+ - 2
46
+ - 3
47
+ version: 0.2.3
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ description: Ruby library giving a simple way to pilot an external process' stdin, stdout and stderr in real time. Very useful for interactive processes testing or automation.
51
+ email: muriel@x-aeon.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - AUTHORS
60
+ - ChangeLog
61
+ - Credits
62
+ - lib/processpilot/processpilot.rb
63
+ - lib/processpilot/wrapper.rb
64
+ - LICENSE
65
+ - README
66
+ - ReleaseInfo
67
+ - test/ProcessPilotTest/Common.rb
68
+ - test/ProcessPilotTest/NonRuby.rb
69
+ - test/ProcessPilotTest/Ruby.rb
70
+ - test/Programs/Bash/Interactive.sh
71
+ - test/Programs/Bash/InteractivePrompt.sh
72
+ - test/Programs/Bash/InteractivePromptSTDERR.sh
73
+ - test/Programs/Bash/InteractiveSeveralPrompts.sh
74
+ - test/Programs/Bash/InteractiveSTDERR.sh
75
+ - test/Programs/Bash/NotInteractive.sh
76
+ - test/Programs/Bash/NotInteractiveSTDERR.sh
77
+ - test/Programs/Ruby/NormalSTDOUT.rb
78
+ - test/Programs/Ruby/Scenario.rb
79
+ - test/Programs/Ruby/SyncedSTDOUT.rb
80
+ - test/Programs/Windows/Interactive.bat
81
+ - test/Programs/Windows/InteractivePrompt.bat
82
+ - test/Programs/Windows/InteractivePromptSTDERR.bat
83
+ - test/Programs/Windows/InteractiveSeveralPrompts.bat
84
+ - test/Programs/Windows/InteractiveSTDERR.bat
85
+ - test/Programs/Windows/NotInteractive.bat
86
+ - test/Programs/Windows/NotInteractiveSTDERR.bat
87
+ - test/run.rb
88
+ has_rdoc: true
89
+ homepage: http://processpilot.sourceforge.net/
90
+ licenses: []
91
+
92
+ post_install_message:
93
+ rdoc_options: []
94
+
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ requirements: []
114
+
115
+ rubyforge_project: processpilot
116
+ rubygems_version: 1.3.7
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: Ruby library to pilot interactive command line processes in real time.
120
+ test_files:
121
+ - test/run.rb