Module: Rcodetools::Fork
- Defined in:
- lib/rcodetools/fork.rb,
lib/rcodetools/fork_config.rb
Constant Summary collapse
- USAGE_HELP =
<<XXX rct-fork and rct-fork-client (we) are originally ruby_fork/ruby_fork_client in ZenTest by Zen Spider Software and are slightly modified for rcodetools. Completion or document browsing in a script with heavy libraries such as Rails takes a significant latency. We eliminate constant overhead of loading heavy libraries. rct-fork loads libraries you want to pre-load and opens up a server socket and waits for connection. When a connection comes in rct-fork forks to make a copy of the environment. rct-fork loads rubygems at startup. rct-fork-client connects to the rct-fork server and runs script in server's environment. xmpfilter/rct-complete/rct-doc can auto-detect rct-fork process with --fork option. This means that once you start up rct-fork, you do not have to start up rct-fork-client manually. demo/fork-demo.sh shows rct-fork example. !!WARNING!! We are only meant to run xmpfilter/rct-complete/rct-doc! If you want to run other programs, use original ruby_fork/ruby_fork_client. XXX
- DEFAULT_SETTINGS =
‘
{ :requires => [], :code => [], :extra_paths => [], :port => PORT, }
- PORT =
9085
- PWD_FILE =
Contains $PWD of rct-fork server. Exists only while running.
File. "~/.rct-fork.pwd"
Class Method Summary collapse
- .add_env_args(opts, settings) ⇒ Object
- .chdir_fork_directory ⇒ Object
- .daemonize(io = File.open('/dev/null', 'r+')) ⇒ Object
- .parse_client_args(args) ⇒ Object
- .parse_server_args(args) ⇒ Object
- .run? ⇒ Boolean
- .setup_environment(settings) ⇒ Object
- .start_client(args = ARGV) ⇒ Object
- .start_server(args = ARGV) ⇒ Object
- .write_pwd ⇒ Object
Class Method Details
.add_env_args(opts, settings) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rcodetools/fork.rb', line 64 def self.add_env_args(opts, settings) opts.separator '' opts.separator 'Process environment options:' opts.separator '' opts.on('-e CODE', 'Execute CODE in parent process.', 'May be specified multiple times.') do |code| settings[:code] << code end opts.separator '' opts.on('-I DIRECTORY', 'Adds DIRECTORY to $LOAD_PATH.', 'May be specified multiple times.') do |dir| settings[:extra_paths] << dir end opts.separator '' opts.on('-r LIBRARY', 'Require LIBRARY in the parent process.', 'May be specified multiple times.') do |lib| settings[:requires] << lib end end |
.chdir_fork_directory ⇒ Object
9 10 11 12 13 14 15 |
# File 'lib/rcodetools/fork_config.rb', line 9 def self.chdir_fork_directory if run? Dir.chdir File.read(PWD_FILE) else raise "rct-fork is not running." end end |
.daemonize(io = File.open('/dev/null', 'r+')) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/rcodetools/fork.rb', line 87 def self.daemonize(io = File.open('/dev/null', 'r+')) fork and exit! Process.setsid fork and exit! STDIN.reopen io STDOUT.reopen io STDERR.reopen io yield if block_given? end |
.parse_client_args(args) ⇒ Object
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 |
# File 'lib/rcodetools/fork.rb', line 99 def self.parse_client_args(args) settings = Marshal.load Marshal.dump(DEFAULT_SETTINGS) opts = OptionParser.new do |opts| opts. = "Usage: #{$0} [options]\n#{USAGE_HELP}" opts.separator '' opts.on('-p', '--port PORT', 'Listen for connections on PORT.', "Default: #{settings[:port]}") do |port| settings[:port] = port.to_i end opts.separator '' opts.on('-h', '--help', 'You\'re looking at it.') do $stderr.puts opts exit 1 end add_env_args opts, settings end opts.parse! args return settings end |
.parse_server_args(args) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/rcodetools/fork.rb', line 126 def self.parse_server_args(args) settings = Marshal.load Marshal.dump(DEFAULT_SETTINGS) opts = OptionParser.new do |opts| opts. = "Usage: #{$0} [options]\n#{USAGE_HELP}" opts.separator '' opts.on('-p', '--port PORT', 'Listen for connections on PORT.', "Default: #{settings[:port]}") do |port| settings[:port] = port.to_i end opts.separator '' opts.on('-h', '--help', 'You\'re looking at it.') do $stderr.puts opts exit 1 end add_env_args opts, settings end opts.parse! args return settings end |
.run? ⇒ Boolean
21 22 23 |
# File 'lib/rcodetools/fork_config.rb', line 21 def self.run? File.file? PWD_FILE end |
.setup_environment(settings) ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/rcodetools/fork.rb', line 213 def self.setup_environment(settings) settings[:extra_paths].map! { |dir| dir.split ':' } settings[:extra_paths].flatten! settings[:extra_paths].each { |dir| $:.unshift dir } begin settings[:requires].each { |file| require file } settings[:code].each { |code| eval code, TOPLEVEL_BINDING } rescue Exception $@.reject! {|s| s =~ %r!rcodetools/fork\.rb!} raise end end |
.start_client(args = ARGV) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/rcodetools/fork.rb', line 153 def self.start_client(args = ARGV) trap 'INT' do exit 1 end # Exit gracefully settings = parse_client_args args args = Marshal.dump [settings, ARGV] socket = TCPSocket.new 'localhost', settings[:port] socket.puts args.length socket.write args socket.close_write until socket.eof? $stdout.puts socket.gets end end |
.start_server(args = ARGV) ⇒ Object
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 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/rcodetools/fork.rb', line 171 def self.start_server(args = ARGV) begin require 'rubygems' rescue LoadError end write_pwd settings = parse_server_args args setup_environment settings server = TCPServer.new 'localhost', settings[:port] $stderr.puts "#{$0} Running as PID #{$$} on #{settings[:port]}" loop do Thread.new server.accept do |socket| begin args_length = socket.gets.to_i args = socket.read args_length settings, argv = Marshal.load args fork do daemonize socket do ARGV.replace argv setup_environment settings socket.close end end socket.close # close my copy. rescue => e socket.close if socket end end end rescue Interrupt, SystemExit File.unlink PWD_FILE rescue Exception => e File.unlink PWD_FILE puts "Failed to catch #{e.class}:#{e.}" puts "\t#{e.backtrace.join "\n\t"}" end |
.write_pwd ⇒ Object
17 18 19 |
# File 'lib/rcodetools/fork_config.rb', line 17 def self.write_pwd open(PWD_FILE, "w"){|f| f.print Dir.pwd } end |