Module: RUtilAnts::ForeignProcess
- Defined in:
- lib/rUtilAnts/ForeignProcess.rb
Overview
This module defines a method to run a given Ruby’s object and parameters in a separate process. This can be useful when $LD_LIBRARY_PATH has to be changed before continuing.
Defined Under Namespace
Classes: MethodCallInfo
Class Method Summary collapse
-
.execCmdOtherSession(iShellCmd, iObject, iMethod, iParameters) ⇒ Object
Execute a command in another Ruby session, executing some Shell commands before invocation.
-
.executeEmbeddedFunction(iInfoFileName, iResultFileName) ⇒ Object
Execute a function along with its parameters stored in a file.
-
.initializeForeignProcess ⇒ Object
Initialize the ForeignProcess methods in the Object namespace.
Class Method Details
.execCmdOtherSession(iShellCmd, iObject, iMethod, iParameters) ⇒ Object
Execute a command in another Ruby session, executing some Shell commands before invocation.
Parameters:
-
iShellCmd (String): Shell command to invoke before Ruby
-
iObject (Object): Object that will have a function to call in the new session
-
iMethod (Symbol): Method to call on the object
-
Parameters (list<Object>): Remaining parameters
Return:
-
Exception: An error, or nil if success
-
Object: The result of the function call (valid only if no error returned)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/rUtilAnts/ForeignProcess.rb', line 68 def self.execCmdOtherSession(iShellCmd, iObject, iMethod, iParameters) rError = nil rResult = nil # Protect it from exceptions, to ensure that a valid error message will be returned begin logDebug "Execute method #{iMethod}(#{iParameters.join(', ')}) in a new process with shell command: #{iShellCmd} ..." # Create an object that we will serialize, containing all needed information for the session lInfo = MethodCallInfo.new lInfo.LogFile = getLogFile lInfo.LibRootDir = getLibRootDir lInfo.BugTrackerURL = getBugTrackerURL lInfo.RequireFiles = [] # Do not store ForeignProcess require $".each do |iRequireName| if (iRequireName.match(/ForeignProcess/) == nil) lInfo.RequireFiles << iRequireName end end lInfo.LoadPath = $LOAD_PATH.clone lMethodDetails = MethodCallInfo::MethodDetails.new lMethodDetails.Parameters = iParameters lMethodDetails.Method = iMethod lMethodDetails.Object = iObject logDebug "Method to be marshalled: #{lMethodDetails.inspect}" lInfo.SerializedMethodDetails = Marshal.dump(lMethodDetails) lCurrentThread = Thread.current # Dump this object in a temporary file require 'tmpdir' lInfoFileName = "#{Dir.tmpdir}/RubyExec_#{lCurrentThread.object_id}_Info" File.open(lInfoFileName, 'w') do |oFile| oFile.write(Marshal.dump(lInfo)) end # For security reasons, ensure that only us can read this file. It can contain passwords. require 'fileutils' FileUtils.chmod(0700, lInfoFileName) # Generate the Ruby file that will run everything lExecFileName = "#{Dir.tmpdir}/RubyExec_#{lCurrentThread.object_id}_Exec.rb" File.open(lExecFileName, 'w') do |oFile| oFile << " \# This is a generated file that should not stay persistent. You can delete it. \# It has been generated by rUtilAnts::ForeignProcess module. Check http://rutilants.sourceforge.net for further details. require '#{File.(__FILE__)}' RUtilAnts::ForeignProcess::executeEmbeddedFunction(ARGV[0], ARGV[1]) " end # For security reasons, ensure that only us can read and execute this file. FileUtils.chmod(0700, lExecFileName) # Name the file that will receive the result of the function call lResultFileName = "#{Dir.tmpdir}/RubyExec_#{lCurrentThread.object_id}_Result" # Call this Ruby file by first executing the Shell command lCmd = "#{iShellCmd}; ruby -w #{lExecFileName} #{lInfoFileName} #{lResultFileName} 2>&1" lOutput = `#{lCmd}` lErrorCode = $? if (lErrorCode == 0) # Read the result file File.open(lResultFileName, 'r') do |iFile| rResult = Marshal.load(iFile.read) end else rError = RuntimeError.new("Error while running command \"#{lCmd}\". Here is the output:\n#{lOutput}.") end # Remove files File.unlink(lInfoFileName) File.unlink(lExecFileName) if (File.exists?(lResultFileName)) File.unlink(lResultFileName) end rescue Exception rError = $! end logDebug "Method executed with error #{rError} and result #{rResult}." return rError, rResult end |
.executeEmbeddedFunction(iInfoFileName, iResultFileName) ⇒ Object
Execute a function along with its parameters stored in a file. This method is used by the file generated by execCmdOtherSession. It should not be called directly.
Parameters:
-
iInfoFileName (String): The file containing info
-
iResultFileName (String): The file used to store the result serialized
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/rUtilAnts/ForeignProcess.rb', line 155 def self.executeEmbeddedFunction(iInfoFileName, iResultFileName) begin # Read the file lInfo = nil File.open(iInfoFileName, 'r') do |iFile| lInfo = Marshal.load(iFile.read) end # Set the load path lInfo.LoadPath.each do |iDir| if (!$LOAD_PATH.include?(iDir)) $LOAD_PATH << iDir end end # Require all given files lInfo.RequireFiles.each do |iRequireName| require iRequireName end # Initialize logging RUtilAnts::Logging::initializeLogging(lInfo.LibRootDir, lInfo.BugTrackerURL) setLogFile(lInfo.LogFile) logDebug "New process spawned with requires: #{lInfo.RequireFiles.join(', ')}." # Unserialize the method details lMethodDetails = Marshal.load(lInfo.SerializedMethodDetails) # Call the method on the object with all its parameters logDebug "Calling method #{lMethodDetails.Method}(#{lMethodDetails.Parameters.join(', ')}) ..." lResult = lMethodDetails.Object.send(lMethodDetails.Method, *lMethodDetails.Parameters) logDebug "Method returned #{lResult}." rescue Exception lResult = RuntimeError.new("Error occurred while executing foreign call: #{$!}. Backtrace: #{$!.backtrace.join("\n")}") end begin # Store the result in the file for return File.open(iResultFileName, 'w') do |oFile| oFile.write(Marshal.dump(lResult)) end # For security reasons, ensure that only us can read this file. It can contain passwords. require 'fileutils' FileUtils.chmod(0700, iResultFileName) rescue Exception logErr "Error while writing result in to #{iResultFileName}: #{$!}." end end |
.initializeForeignProcess ⇒ Object
Initialize the ForeignProcess methods in the Object namespace
199 200 201 |
# File 'lib/rUtilAnts/ForeignProcess.rb', line 199 def self.initializeForeignProcess Object.module_eval('include RUtilAnts::ForeignProcess') end |