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
-
.exec_cmd_other_session(iShellCmd, iObject, iMethod, iParameters) ⇒ Object
Execute a command in another Ruby session, executing some Shell commands before invocation.
-
.execute_embedded_function(iInfoFileName, iResultFileName) ⇒ Object
Execute a function along with its parameters stored in a file.
-
.install_foreign_process_on_object ⇒ Object
Initialize the ForeignProcess methods in the Object namespace.
Class Method Details
.exec_cmd_other_session(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)
63 64 65 66 67 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 |
# File 'lib/rUtilAnts/ForeignProcess.rb', line 63 def self.exec_cmd_other_session(iShellCmd, iObject, iMethod, iParameters) rError = nil rResult = nil # Protect it from exceptions, to ensure that a valid error message will be returned begin log_debug "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 = get_log_file lInfo.LibRootDir = get_lib_root_dir lInfo.BugTrackerURL = get_bug_tracker_url 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 log_debug "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::execute_embedded_function(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 log_debug "Method executed with error #{rError} and result #{rResult}." return rError, rResult end |
.execute_embedded_function(iInfoFileName, iResultFileName) ⇒ Object
Execute a function along with its parameters stored in a file. This method is used by the file generated by exec_cmd_other_session. It should not be called directly.
- Parameters
-
iInfoFileName (String): The file containing info
-
iResultFileName (String): The file used to store the result serialized
150 151 152 153 154 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 |
# File 'lib/rUtilAnts/ForeignProcess.rb', line 150 def self.(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::install_logger_on_object(:lib_root_dir => lInfo.LibRootDir, :bug_tracker_url => lInfo.BugTrackerURL, :log_file => lInfo.LogFile) log_debug "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 log_debug "Calling method #{lMethodDetails.Method}(#{lMethodDetails.Parameters.join(', ')}) ..." lResult = lMethodDetails.Object.send(lMethodDetails.Method, *lMethodDetails.Parameters) log_debug "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 log_err "Error while writing result in to #{iResultFileName}: #{$!}." end end |
.install_foreign_process_on_object ⇒ Object
Initialize the ForeignProcess methods in the Object namespace
193 194 195 |
# File 'lib/rUtilAnts/ForeignProcess.rb', line 193 def self.install_foreign_process_on_object Object.module_eval('include RUtilAnts::ForeignProcess') end |