snailgun 1.0.3

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/README.markdown ADDED
@@ -0,0 +1,177 @@
1
+ Snailgun
2
+ ========
3
+
4
+ Snailgun accelerates the startup of Ruby applications which require large
5
+ numbers of libraries. It does this by preparing a Ruby process with your
6
+ chosen libraries preloaded, and then forking that process whenever a new
7
+ command-line Ruby interpreter is required.
8
+
9
+ Installation
10
+ ------------
11
+
12
+ sudo gem sources -a http://gems.github.com/
13
+ sudo gem install candlerb-snailgun
14
+
15
+ Or for the latest code, `git clone git://github.com/candlerb/snailgun.git`
16
+ and put the bin directory into your PATH.
17
+
18
+ Case 1: standalone
19
+ ------------------
20
+
21
+ # WITHOUT SNAILGUN
22
+ $ time ruby -rubygems -e 'require "active_support"' -e 'puts "".blank?'
23
+ true
24
+
25
+ real 0m2.123s
26
+ user 0m1.424s
27
+ sys 0m0.168s
28
+
29
+ # WITH SNAILGUN
30
+ $ snailgun -rubygems -ractive_support
31
+ Snailgun starting on /home/brian/.snailgun/14781 - 'exit' to end
32
+ $ time fruby -e 'puts "".blank?'
33
+ true
34
+
35
+ real 0m0.064s
36
+ user 0m0.020s
37
+ sys 0m0.004s
38
+
39
+ $ exit
40
+ logout
41
+ Snailgun ended
42
+ $
43
+
44
+ Case 2: Rails app
45
+ -----------------
46
+
47
+ When using Rails or Merb, snailgun will start a process preloaded for the
48
+ `test` environment only unless told otherwise.
49
+
50
+ You need to edit `config/environments/test.rb` and set
51
+ `config.cache_classes = false`. This is so that your application classes
52
+ are loaded each time you run a test, rather than being preloaded into
53
+ the test environment.
54
+
55
+ Snailgun will take several seconds to be ready to process requests. Start
56
+ with `snailgun -v` if you wish to be notified when it is ready.
57
+
58
+ $ rails testapp
59
+ $ cd testapp
60
+ $ vi config/environments/test.rb
61
+ ... set config.cache_classes = false
62
+ $ snailgun
63
+ Use 'exit' to terminate snailgun
64
+
65
+ $ time RAILS_ENV=test fruby script/runner 'puts 1+2'
66
+ 3
67
+
68
+ real 0m0.169s
69
+ user 0m0.040s
70
+ sys 0m0.008s
71
+
72
+ # To run your test suite
73
+ $ frake test # or frake spec
74
+
75
+ Your preloaded process will remain around until you type `exit` to terminate
76
+ it.
77
+
78
+ Note that any attempt by `fruby` or `frake` to perform an action in an
79
+ environment other than 'test' will fail. See below for how to run multiple
80
+ snailgun environments.
81
+
82
+ Merb support has been contributed (using MERB_ENV), but it is untested by
83
+ me.
84
+
85
+ Case 3: Rails with multiple environments
86
+ ----------------------------------------
87
+
88
+ After reading the warnings below, you may choose to start multiple snailgun
89
+ processes each configured for a different environment, as follows:
90
+
91
+ $ snailgun --rails test,development
92
+
93
+ This gives the potential for faster startup of rake tasks which involve
94
+ the development environment (such as migrations) and the console. The
95
+ utility `fconsole` is provided for this.
96
+
97
+ However, beware that frake and fruby need to decide which of the preloaded
98
+ environments to dispatch the command to. The safest way is to force the
99
+ correct one explicitly:
100
+
101
+ RAILS_ENV=test frake test:units
102
+ RAILS_ENV=development fruby script/server
103
+ RAILS_ENV=test fruby script/runner 'puts "".blank?'
104
+
105
+ If you do not specify the environment, then a simple heuristic is used:
106
+
107
+ * `fruby` always defaults to the 'development' environment.
108
+
109
+ * `frake` honours any `RAILS_ENV=xxx` setting on the command line. If
110
+ missing, `frake` defaults to the 'test' environment if no args are given or
111
+ if an arg containing the word 'test' or 'spec' is given; otherwise it falls
112
+ back to the 'development' environment.
113
+
114
+ WARNING: The decision as to which of the preloaded environments to use is
115
+ made *before* actually running the command. If the wrong choice is made, it
116
+ can lead to problems.
117
+
118
+ In the worst case, you may have a 'test'-type task, but find that it is
119
+ wrongly dispatched to your 'development' environment - and possibly ends up
120
+ blowing away your development database. This actually happened to me while
121
+ developing snailgun. SO IF YOUR DEVELOPMENT DATABASE CONTAINS USEFUL DATA,
122
+ KEEP IT BACKED UP.
123
+
124
+ If you run test files individually, it is especially critical that you set
125
+ the correct environment. e.g.
126
+
127
+ RAILS_ENV=test fruby -Ilib -Itest test/unit/some_test.rb
128
+
129
+ autotest
130
+ --------
131
+
132
+ There is some simple support for autotest (from the ZenTest package).
133
+ Just type `fautotest` instead of `autotest` after snailgun has been started.
134
+
135
+ Bypassing rubygems
136
+ ------------------
137
+
138
+ You can get noticeably faster startup if you don't use rubygems to invoke
139
+ the programs. To do this, you can add the binary directory directly into
140
+ the front of your PATH, e.g. for Ubuntu
141
+
142
+ PATH=/var/lib/gems/1.8/gems/snailgun-1.0.2/bin:$PATH
143
+
144
+ Alternatively, create a file called `fruby` somewhere early on in your PATH
145
+ (e.g. under `$HOME/bin`), like this:
146
+
147
+ #!/usr/bin/env ruby
148
+ load '/path/to/the/real/fruby'
149
+
150
+ Repeat for `frake` etc.
151
+
152
+ Other bugs and limitations
153
+ --------------------------
154
+ Only works with Linux/BSD systems, due to use of passing open file
155
+ descriptors across a socket.
156
+
157
+ Ctrl-C doesn't terminate frake processes.
158
+
159
+ `fruby script/console` doesn't give any speedup, because script/console uses
160
+ exec to invoke irb. Use the supplied `fconsole` instead.
161
+
162
+ The environment is not currently passed across the socket to the ruby
163
+ process. This means it's not usable as a fast CGI replacement.
164
+
165
+ In Rails, you need to beware that any changes to your `config/environment*`
166
+ will not be reflected until you stop and restart snailgun.
167
+
168
+ Licence
169
+ -------
170
+ This code is released under the same licence as Ruby itself.
171
+
172
+ Author
173
+ ------
174
+ Brian Candler <B.Candler@pobox.com>
175
+
176
+ Credits:
177
+ Jan X <jan.h.xie@gmail.com>
data/bin/fautotest ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) Brian Candler 2009. Released under the Ruby licence.
3
+
4
+ # shortcut for: RAILS_ENV=test fruby /path/to/autotest
5
+
6
+ ENV["RAILS_ENV"] = "test"
7
+ Test::Unit.run = true if defined?(Test::Unit) && Test::Unit.respond_to?(:run=)
8
+ ARGV[0,0] = ["-e","gem 'ZenTest'","-e","load 'autotest'","--"]
9
+ load File.join(File.dirname(__FILE__), "fruby")
data/bin/fconsole ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) Brian Candler 2009. Released under the Ruby licence.
3
+
4
+ ENV['RAILS_ENV'] = ARGV.shift if ARGV[0] =~ /^\w/
5
+
6
+ ARGV[0,0] = [
7
+ "-rirb",
8
+ "-rirb/completion",
9
+ "-rconsole_app",
10
+ "-rconsole_with_helpers",
11
+ "-eIRB.start", "--", "--simple-prompt"
12
+ ]
13
+ load File.join(File.dirname(__FILE__), "fruby")
data/bin/frake ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) Brian Candler 2009. Released under the Ruby licence.
3
+ # Here we run rake within a pre-forked ruby process
4
+
5
+ # Pre-parse environment - see collect_tasks in rake/lib/rake.rb
6
+ ARGV.each do |arg|
7
+ if arg =~ /^(\w+)=(.*)$/
8
+ ENV[$1] = $2
9
+ end
10
+ end
11
+
12
+ # Make a guess at the correct environment
13
+ if File.exist?("config/boot.rb") || File.exist?("config/init.rb")
14
+ # Rails: default task is 'test'
15
+ $DEFAULT_ENV='test' if ARGV.find { |arg| arg =~ /\b(test|spec)\b/ } || !ARGV.find { |arg| arg !~ /^-/ }
16
+ end
17
+
18
+ ARGV[0,0] = ["-rrake", "-eRake.application.run", "--"]
19
+ load File.join(File.dirname(__FILE__), "fruby")
data/bin/fruby ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) Brian Candler 2009. Released under the Ruby licence.
3
+ # This could be rewritten in C for even faster startup
4
+
5
+ require 'socket'
6
+ if ENV['SNAILGUN_SOCK']
7
+ sockname = ENV['SNAILGUN_SOCK']
8
+ elsif File.directory?('tmp/sockets/snailgun')
9
+ env = ENV['RAILS_ENV'] || ENV['MERB_ENV']
10
+ unless env
11
+ # Normally default to development: see railties/lib/tasks/misc.rake
12
+ env = $DEFAULT_ENV || 'development'
13
+ STDERR.puts "Snailgun assuming environment '#{env}'"
14
+ end
15
+ sockname = "tmp/sockets/snailgun/#{env}"
16
+ end
17
+
18
+ unless sockname
19
+ STDERR.puts <<EOS
20
+ Unable to find path to snailgun socket.
21
+ - did you run this in a session with a snailgun parent?
22
+ - you can do 'SNAILGUN_SOCK=/path/to/sock #{$0} ...'
23
+ EOS
24
+ exit 1
25
+ end
26
+
27
+ server = UNIXSocket.open(sockname)
28
+ server.send_io(STDIN)
29
+ server.send_io(STDOUT)
30
+ server.send_io(STDERR)
31
+ args = Marshal.dump([ARGV, Dir.pwd, Process.getpgrp])
32
+ server.write [args.size].pack("N")
33
+ server.write args
34
+ begin
35
+ rc = (server.read(1) || "\000").unpack("C").first
36
+ exit rc
37
+ rescue Interrupt
38
+ server.write('X')
39
+ exit 1
40
+ end
data/bin/snailgun ADDED
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) Brian Candler 2009. Released under the Ruby licence.
3
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
4
+ require 'snailgun/server'
5
+ require 'optparse'
6
+
7
+ sockpath = nil
8
+ mode = nil
9
+ envs = "test"
10
+ rake = false
11
+ verbose = false
12
+
13
+ def fix_rake
14
+ require 'rbconfig'
15
+ Config::CONFIG['bindir'] = File.expand_path(File.dirname(__FILE__))
16
+ Config::CONFIG['ruby_install_name'] = 'fruby'
17
+ require 'rubygems'
18
+ require 'rake'
19
+ require 'rake/testtask'
20
+ require 'rake/rdoctask'
21
+ end
22
+
23
+ OptionParser.new do |opts|
24
+ opts.on("-I DIR", "add to load path") { |v| $:.unshift v }
25
+ opts.on("-r LIB", "require library") { |v| require v }
26
+ opts.on("--rails [ENVS]", "rails mode") { |v| mode = :rails; envs = v }
27
+ opts.on("--ruby [SOCKPATH]", "ruby mode") { |v| mode = :ruby; sockpath = v }
28
+ opts.on("--rake", "add rake support") { rake = true }
29
+ opts.on("-v", "--verbose", "show progress") { verbose = true }
30
+ end.parse!
31
+
32
+ mode ||= if File.exist?("config/boot.rb")
33
+ :rails
34
+ elsif File.exist?("config/init.rb")
35
+ :merb
36
+ else
37
+ :ruby
38
+ end
39
+
40
+ STDERR.puts "Starting in #{mode} mode" if verbose
41
+ case mode
42
+ when :ruby
43
+ unless sockpath
44
+ dir = File.join(ENV['HOME'], '.snailgun')
45
+ begin
46
+ Dir.mkdir dir, 0700
47
+ rescue Errno::EEXIST
48
+ File.chmod 0700, dir
49
+ end
50
+ sockpath = File.join dir, $$.to_s
51
+ end
52
+ fix_rake if rake
53
+ server = Snailgun::Server.new(sockpath)
54
+ server.interactive!
55
+
56
+ when :rails
57
+ conf = File.expand_path('config/boot.rb')
58
+ unless File.exist?(conf)
59
+ raise '#{conf} does not exist, cannot continue'
60
+ end
61
+ sockdir = File.expand_path('tmp/sockets/snailgun')
62
+ begin
63
+ Dir.mkdir sockdir, 0700
64
+ rescue Errno::EEXIST
65
+ File.chmod 0700, sockdir
66
+ end
67
+ pids = {}
68
+ fix_rake # TODO: separate process for rake (but then need to choose right RAILS_ENV)
69
+ envs.split(/[\s,]+/).uniq.each do |env|
70
+ pids[env] = fork do
71
+ server = Snailgun::Server.new("#{sockdir}/#{env}")
72
+ ENV['RAILS_ENV'] = env
73
+ load conf
74
+ require File.expand_path(RAILS_ROOT + '/config/environment')
75
+ # We can get some drastic test speedups by preloading test frameworks
76
+ if env != 'test'
77
+ # do nothing
78
+ elsif File.exist?('test/test_helper.rb')
79
+ require 'test_help'
80
+ elsif File.exist?('spec/spec_helper.rb')
81
+ require 'spec'
82
+ require 'spec/rails'
83
+ end
84
+ if Rails.respond_to?(:configuration) && Rails.configuration.cache_classes
85
+ STDERR.puts <<EOS
86
+ WARNING: Snailgun doesn't work well with `cache_classes`. Strongly recommend
87
+ `config.cache_classes = false` in config/environments/#{env}.rb
88
+ EOS
89
+ end
90
+ STDERR.puts "Started server for #{env}" if verbose
91
+ server.run
92
+ end
93
+ end
94
+ STDERR.puts "Use 'exit' to terminate snailgun"
95
+ Snailgun::Server.shell
96
+ pids.each do |env,pid|
97
+ Process.kill('TERM',pid)
98
+ end
99
+ # TODO: wait a few secs for them to die, 'KILL' if required
100
+ STDERR.puts "Snailgun ended"
101
+
102
+ when :merb
103
+ conf = File.expand_path('config/init.rb')
104
+ unless File.exist?(conf)
105
+ raise '#{conf} does not exist, cannot continue'
106
+ end
107
+ sockdir = File.expand_path('tmp/sockets/snailgun')
108
+ begin
109
+ require 'fileutils'
110
+ FileUtils.mkdir_p sockdir
111
+ ensure
112
+ File.chmod 0700, sockdir
113
+ end
114
+ pids = {}
115
+ fix_rake # TODO: separate process for rake (but then need to choose right RAILS_ENV)
116
+ envs.split(/\s*,\s*/).uniq.each do |env|
117
+ pids[env] = fork do
118
+ server = Snailgun::Server.new("#{sockdir}/#{env}")
119
+ ENV['MERB_ENV'] = env
120
+
121
+ require 'rubygems'
122
+ gem 'merb-core'
123
+ require 'merb'
124
+ Merb.start_environment([env])
125
+
126
+ STDERR.puts "Started server for #{env}" if verbose
127
+ server.run
128
+ end
129
+ end
130
+ STDERR.puts "Use 'exit' to terminate snailgun"
131
+ Snailgun::Server.shell
132
+ pids.each do |env,pid|
133
+ Process.kill('TERM',pid)
134
+ end
135
+ # TODO: wait a few secs for them to die, 'KILL' if required
136
+ STDERR.puts "Snailgun ended"
137
+ end
@@ -0,0 +1,112 @@
1
+ # Copyright (C) Brian Candler 2009. Released under the Ruby licence.
2
+
3
+ # Our at_exit handler must be called *last*, so register it first
4
+ at_exit { $SNAILGUN_EXIT.call if $SNAILGUN_EXIT }
5
+
6
+ # Fix truncation of $0. See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/336743
7
+ $progname = $0
8
+ alias $PROGRAM_NAME $0
9
+ alias $0 $progname
10
+ trace_var(:$0) {|val| $PROGRAM_NAME = val} # update for ps
11
+
12
+ require 'socket'
13
+ require 'optparse'
14
+
15
+ module Snailgun
16
+ class Server
17
+ attr_accessor :sockname
18
+
19
+ def initialize(sockname = nil)
20
+ @sockname = sockname || "/tmp/snailgun#{$$}"
21
+ File.delete(@sockname) rescue nil
22
+ @socket = UNIXServer.open(@sockname)
23
+ yield self if block_given?
24
+ end
25
+
26
+ def run
27
+ while client = @socket.accept
28
+ fork do
29
+ begin
30
+ STDIN.reopen(client.recv_io)
31
+ STDOUT.reopen(client.recv_io)
32
+ STDERR.reopen(client.recv_io)
33
+ nbytes = client.read(4).unpack("N").first
34
+ args, cwd, pgid = Marshal.load(client.read(nbytes))
35
+ Dir.chdir(cwd)
36
+ begin
37
+ Process.setpgid(0, pgid)
38
+ rescue Errno::EPERM
39
+ end
40
+ exit_status = 0
41
+ $SNAILGUN_EXIT = lambda {
42
+ begin
43
+ client.write [exit_status].pack("C")
44
+ rescue Errno::EPIPE
45
+ end
46
+ }
47
+ #This doesn't work in 1.8.6:
48
+ #Thread.new { client.read(1); Thread.main.raise Interrupt }
49
+ Thread.new { client.read(1); exit 1 }
50
+ start_ruby(args)
51
+ rescue SystemExit => e
52
+ exit_status = e.status
53
+ raise # for the benefit of Test::Unit
54
+ rescue Exception => e
55
+ STDERR.puts "#{e}\n\t#{e.backtrace.join("\n\t")}"
56
+ exit 1
57
+ end
58
+ end
59
+ client.close
60
+ end
61
+ ensure
62
+ File.delete(@sockname) rescue nil
63
+ end
64
+
65
+ # Process the received ruby command line. (TODO: implement more options)
66
+ def start_ruby(args)
67
+ e = []
68
+ OptionParser.new do |opts|
69
+ opts.on("-e EXPR") do |v|
70
+ e << v
71
+ end
72
+ opts.on("-I DIR") do |v|
73
+ $:.unshift v
74
+ end
75
+ opts.on("-r LIB") do |v|
76
+ require v
77
+ end
78
+ end.order!(args)
79
+
80
+ ARGV.replace(args)
81
+ if !e.empty?
82
+ $0 = '-e'
83
+ e.each { |expr| eval(expr, TOPLEVEL_BINDING) }
84
+ elsif ARGV.empty?
85
+ $0 = '-'
86
+ eval(STDIN.read, TOPLEVEL_BINDING)
87
+ else
88
+ cmd = ARGV.shift
89
+ $0 = cmd
90
+ load(cmd)
91
+ end
92
+ end
93
+
94
+ def self.shell
95
+ system(ENV['shell'] || 'bash')
96
+ end
97
+
98
+ # Interactive mode (start a subshell with SNAILGUN_SOCK set up,
99
+ # and terminate the snailgun server when the subshell exits)
100
+ def interactive!
101
+ ENV['SNAILGUN_SOCK'] = @sockname
102
+ pid = Process.fork {
103
+ STDERR.puts "Snailgun starting on #{sockname} - 'exit' to end"
104
+ run
105
+ }
106
+ self.class.shell
107
+ Process.kill('TERM',pid)
108
+ # TODO: wait a few secs for it to die, 'KILL' if required
109
+ STDERR.puts "Snailgun ended"
110
+ end
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snailgun
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Brian Candler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-19 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Snailgun accelerates the startup of Ruby applications which require large numbers of libraries
17
+ email: b.candler@pobox.com
18
+ executables:
19
+ - fautotest
20
+ - fconsole
21
+ - frake
22
+ - fruby
23
+ - snailgun
24
+ extensions: []
25
+
26
+ extra_rdoc_files:
27
+ - README.markdown
28
+ files:
29
+ - bin/fautotest
30
+ - bin/fconsole
31
+ - bin/frake
32
+ - bin/fruby
33
+ - bin/snailgun
34
+ - lib/snailgun/server.rb
35
+ - README.markdown
36
+ has_rdoc: true
37
+ homepage: http://github.com/candlerb/snailgun
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --inline-source
41
+ - --charset=UTF-8
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project: snailgun
59
+ rubygems_version: 1.3.1
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: Command-line startup accelerator
63
+ test_files: []
64
+