Checkout of Instiki Trunk 1/21/2007.

This commit is contained in:
Jacques Distler 2007-01-22 07:43:50 -06:00
commit 69b62b6f33
1138 changed files with 139586 additions and 0 deletions

View file

@ -0,0 +1,2 @@
require 'environment'
puts Rails::Info

View file

@ -0,0 +1 @@
require 'breakpoint_client'

View file

@ -0,0 +1,25 @@
irb = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
require 'optparse'
options = { :sandbox => false, :irb => irb }
OptionParser.new do |opt|
opt.banner = "Usage: console [environment] [options]"
opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
opt.parse!(ARGV)
end
libs = " -r irb/completion"
libs << " -r #{RAILS_ROOT}/config/environment"
libs << " -r console_app"
libs << " -r console_sandbox" if options[:sandbox]
libs << " -r console_with_helpers"
ENV['RAILS_ENV'] = ARGV.first || ENV['RAILS_ENV'] || 'development'
if options[:sandbox]
puts "Loading #{ENV['RAILS_ENV']} environment in sandbox."
puts "Any modifications you make will be rolled back on exit."
else
puts "Loading #{ENV['RAILS_ENV']} environment."
end
exec "#{options[:irb]} #{libs} --simple-prompt"

View file

@ -0,0 +1,6 @@
require "#{RAILS_ROOT}/config/environment"
require 'rails_generator'
require 'rails_generator/scripts/destroy'
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
Rails::Generator::Scripts::Destroy.new.run(ARGV)

View file

@ -0,0 +1,6 @@
require "#{RAILS_ROOT}/config/environment"
require 'rails_generator'
require 'rails_generator/scripts/generate'
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
Rails::Generator::Scripts::Generate.new.run(ARGV)

View file

@ -0,0 +1,86 @@
#!/usr/local/bin/ruby
require 'stringio'
require 'fileutils'
require 'fcgi_handler'
def message(s)
$stderr.puts "listener: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
end
class RemoteCGI < CGI
attr_accessor :stdinput, :stdoutput, :env_table
def initialize(env_table, input = nil, output = nil)
self.env_table = env_table
self.stdinput = input || StringIO.new
self.stdoutput = output || StringIO.new
super()
end
def out(stream) # Ignore the requested output stream
super(stdoutput)
end
end
class Listener
include DRbUndumped
def initialize(timeout, socket_path)
@socket = File.expand_path(socket_path)
@mutex = Mutex.new
@active = false
@timeout = timeout
@handler = RailsFCGIHandler.new
@handler.extend DRbUndumped
message 'opening socket'
DRb.start_service("drbunix:#{@socket}", self)
message 'entering process loop'
@handler.process! self
end
def each_cgi(&cgi_block)
@cgi_block = cgi_block
message 'entering idle loop'
loop do
sleep @timeout rescue nil
die! unless @active
@active = false
end
end
def process(env, input)
message 'received request'
@mutex.synchronize do
@active = true
message 'creating input stream'
input_stream = StringIO.new(input)
message 'building CGI instance'
cgi = RemoteCGI.new(eval(env), input_stream)
message 'yielding to fcgi handler'
@cgi_block.call cgi
message 'yield finished -- sending output'
cgi.stdoutput.seek(0)
output = cgi.stdoutput.read
return output
end
end
def die!
message 'shutting down'
DRb.stop_service
FileUtils.rm_f @socket
Kernel.exit 0
end
end
socket_path = ARGV.shift
timeout = (ARGV.shift || 90).to_i
Listener.new(timeout, socket_path)

View file

@ -0,0 +1,69 @@
#!/usr/local/bin/ruby
require 'drb'
require 'thread'
def message(s)
$stderr.puts "tracker: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
end
class Tracker
include DRbUndumped
def initialize(instances, socket_path)
@instances = instances
@socket = File.expand_path(socket_path)
@active = false
@listeners = []
@instances.times { @listeners << Mutex.new }
message "using #{@listeners.length} listeners"
message "opening socket at #{@socket}"
@service = DRb.start_service("drbunix://#{@socket}", self)
end
def with_listener
message "listener requested"
mutex = has_lock = index = nil
3.times do
@listeners.each_with_index do |mutex, index|
has_lock = mutex.try_lock
break if has_lock
end
break if has_lock
sleep 0.05
end
if has_lock
message "obtained listener #{index}"
@active = true
begin yield index
ensure
mutex.unlock
message "released listener #{index}"
end
else
message "dropping request because no listeners are available!"
end
end
def background(check_interval = nil)
if check_interval
loop do
sleep check_interval
message "Idle for #{check_interval}, shutting down" unless @active
@active = false
Kernel.exit 0
end
else DRb.thread.join
end
end
end
socket_path = ARGV.shift
instances = ARGV.shift.to_i
t = Tracker.new(instances, socket_path)
t.background(ARGV.first ? ARGV.shift.to_i : 90)

View file

@ -0,0 +1,24 @@
if ARGV.empty?
puts "Usage: ./script/performance/benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ..."
exit 1
end
begin
N = Integer(ARGV.first)
ARGV.shift
rescue ArgumentError
N = 1
end
require RAILS_ROOT + '/config/environment'
require 'benchmark'
include Benchmark
# Don't include compilation in the benchmark
ARGV.each { |expression| eval(expression) }
bm(6) do |x|
ARGV.each_with_index do |expression, idx|
x.report("##{idx + 1}") { N.times { eval(expression) } }
end
end

View file

@ -0,0 +1,34 @@
if ARGV.empty?
$stderr.puts "Usage: ./script/performance/profiler 'Person.expensive_method(10)' [times]"
exit(1)
end
# Keep the expensive require out of the profile.
$stderr.puts 'Loading Rails...'
require RAILS_ROOT + '/config/environment'
# Define a method to profile.
if ARGV[1] and ARGV[1].to_i > 1
eval "def profile_me() #{ARGV[1]}.times { #{ARGV[0]} } end"
else
eval "def profile_me() #{ARGV[0]} end"
end
# Use the ruby-prof extension if available. Fall back to stdlib profiler.
begin
require 'prof'
$stderr.puts 'Using the ruby-prof extension.'
Prof.clock_mode = Prof::GETTIMEOFDAY
Prof.start
profile_me
results = Prof.stop
require 'rubyprof_ext'
Prof.print_profile(results, $stderr)
rescue LoadError
require 'profiler'
$stderr.puts 'Using the standard Ruby profiler.'
Profiler__.start_profile
profile_me
Profiler__.stop_profile
Profiler__.print_profile($stderr)
end

View file

@ -0,0 +1,871 @@
# Rails Plugin Manager.
#
# Listing available plugins:
#
# $ ./script/plugin list
# continuous_builder http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder
# asset_timestamping http://svn.aviditybytes.com/rails/plugins/asset_timestamping
# enumerations_mixin http://svn.protocool.com/rails/plugins/enumerations_mixin/trunk
# calculations http://techno-weenie.net/svn/projects/calculations/
# ...
#
# Installing plugins:
#
# $ ./script/plugin install continuous_builder asset_timestamping
#
# Finding Repositories:
#
# $ ./script/plugin discover
#
# Adding Repositories:
#
# $ ./script/plugin source http://svn.protocool.com/rails/plugins/
#
# How it works:
#
# * Maintains a list of subversion repositories that are assumed to have
# a plugin directory structure. Manage them with the (source, unsource,
# and sources commands)
#
# * The discover command scrapes the following page for things that
# look like subversion repositories with plugins:
# http://wiki.rubyonrails.org/rails/pages/Plugins
#
# * Unless you specify that you want to use svn, script/plugin uses plain old
# HTTP for downloads. The following bullets are true if you specify
# that you want to use svn.
#
# * If `vendor/plugins` is under subversion control, the script will
# modify the svn:externals property and perform an update. You can
# use normal subversion commands to keep the plugins up to date.
#
# * Or, if `vendor/plugins` is not under subversion control, the
# plugin is pulled via `svn checkout` or `svn export` but looks
# exactly the same.
#
# This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com)
# and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php)
$verbose = false
require 'open-uri'
require 'fileutils'
require 'tempfile'
include FileUtils
class RailsEnvironment
attr_reader :root
def initialize(dir)
@root = dir
end
def self.find(dir=nil)
dir ||= pwd
while dir.length > 1
return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb'))
dir = File.dirname(dir)
end
end
def self.default
@default ||= find
end
def self.default=(rails_env)
@default = rails_env
end
def install(name_uri_or_plugin)
if name_uri_or_plugin.is_a? String
if name_uri_or_plugin =~ /:\/\//
plugin = Plugin.new(name_uri_or_plugin)
else
plugin = Plugins[name_uri_or_plugin]
end
else
plugin = name_uri_or_plugin
end
unless plugin.nil?
plugin.install
else
puts "plugin not found: #{name_uri_or_plugin}"
end
end
def use_svn?
require 'active_support/core_ext/kernel'
silence_stderr {`svn --version` rescue nil}
!$?.nil? && $?.success?
end
def use_externals?
use_svn? && File.directory?("#{root}/vendor/plugins/.svn")
end
def use_checkout?
# this is a bit of a guess. we assume that if the rails environment
# is under subversion then they probably want the plugin checked out
# instead of exported. This can be overridden on the command line
File.directory?("#{root}/.svn")
end
def best_install_method
return :http unless use_svn?
case
when use_externals? then :externals
when use_checkout? then :checkout
else :export
end
end
def externals
return [] unless use_externals?
ext = `svn propget svn:externals "#{root}/vendor/plugins"`
ext.reject{ |line| line.strip == '' }.map do |line|
line.strip.split(/\s+/, 2)
end
end
def externals=(items)
unless items.is_a? String
items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
end
Tempfile.open("svn-set-prop") do |file|
file.write(items)
file.flush
system("svn propset -q svn:externals -F #{file.path} \"#{root}/vendor/plugins\"")
end
end
end
class Plugin
attr_reader :name, :uri
def initialize(uri, name=nil)
@uri = uri
guess_name(uri)
end
def to_s
"#{@name.ljust(30)}#{@uri}"
end
def installed?
File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \
or rails_env.externals.detect{ |name, repo| self.uri == repo }
end
def install(method=nil, options = {})
method ||= rails_env.best_install_method?
method = :export if method == :http and @uri =~ /svn:\/\/*/
uninstall if installed? and options[:force]
unless installed?
send("install_using_#{method}", options)
run_install_hook
else
puts "already installed: #{name} (#{uri}). pass --force to reinstall"
end
end
def uninstall
path = "#{rails_env.root}/vendor/plugins/#{name}"
if File.directory?(path)
puts "Removing 'vendor/plugins/#{name}'" if $verbose
rm_r path
else
puts "Plugin doesn't exist: #{path}"
end
# clean up svn:externals
externals = rails_env.externals
externals.reject!{|n,u| name == n or name == u}
rails_env.externals = externals
end
private
def run_install_hook
install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb"
load install_hook_file if File.exists? install_hook_file
end
def install_using_export(options = {})
svn_command :export, options
end
def install_using_checkout(options = {})
svn_command :checkout, options
end
def install_using_externals(options = {})
externals = rails_env.externals
externals.push([@name, uri])
rails_env.externals = externals
install_using_checkout(options)
end
def install_using_http(options = {})
root = rails_env.root
mkdir_p "#{root}/vendor/plugins"
Dir.chdir "#{root}/vendor/plugins"
puts "fetching from '#{uri}'" if $verbose
fetcher = RecursiveHTTPFetcher.new(uri)
fetcher.quiet = true if options[:quiet]
fetcher.fetch
end
def svn_command(cmd, options = {})
root = rails_env.root
mkdir_p "#{root}/vendor/plugins"
base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\""
base_cmd += ' -q' if options[:quiet] and not $verbose
base_cmd += " -r #{options[:revision]}" if options[:revision]
puts base_cmd if $verbose
system(base_cmd)
end
def guess_name(url)
@name = File.basename(url)
if @name == 'trunk' || @name.empty?
@name = File.basename(File.dirname(url))
end
end
def rails_env
@rails_env || RailsEnvironment.default
end
end
class Repositories
include Enumerable
def initialize(cache_file = File.join(find_home, ".rails-plugin-sources"))
@cache_file = File.expand_path(cache_file)
load!
end
def each(&block)
@repositories.each(&block)
end
def add(uri)
unless find{|repo| repo.uri == uri }
@repositories.push(Repository.new(uri)).last
end
end
def remove(uri)
@repositories.reject!{|repo| repo.uri == uri}
end
def exist?(uri)
@repositories.detect{|repo| repo.uri == uri }
end
def all
@repositories
end
def find_plugin(name)
@repositories.each do |repo|
repo.each do |plugin|
return plugin if plugin.name == name
end
end
return nil
end
def load!
contents = File.exist?(@cache_file) ? File.read(@cache_file) : defaults
contents = defaults if contents.empty?
@repositories = contents.split(/\n/).reject do |line|
line =~ /^\s*#/ or line =~ /^\s*$/
end.map { |source| Repository.new(source.strip) }
end
def save
File.open(@cache_file, 'w') do |f|
each do |repo|
f.write(repo.uri)
f.write("\n")
end
end
end
def defaults
<<-DEFAULTS
http://dev.rubyonrails.com/svn/rails/plugins/
DEFAULTS
end
def find_home
['HOME', 'USERPROFILE'].each do |homekey|
return ENV[homekey] if ENV[homekey]
end
if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
end
begin
File.expand_path("~")
rescue StandardError => ex
if File::ALT_SEPARATOR
"C:/"
else
"/"
end
end
end
def self.instance
@instance ||= Repositories.new
end
def self.each(&block)
self.instance.each(&block)
end
end
class Repository
include Enumerable
attr_reader :uri, :plugins
def initialize(uri)
@uri = uri.chomp('/') << "/"
@plugins = nil
end
def plugins
unless @plugins
if $verbose
puts "Discovering plugins in #{@uri}"
puts index
end
@plugins = index.reject{ |line| line !~ /\/$/ }
@plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
end
@plugins
end
def each(&block)
plugins.each(&block)
end
private
def index
@index ||= RecursiveHTTPFetcher.new(@uri).ls
end
end
# load default environment and parse arguments
require 'optparse'
module Commands
class Plugin
attr_reader :environment, :script_name, :sources
def initialize
@environment = RailsEnvironment.default
@rails_root = RailsEnvironment.default.root
@script_name = File.basename($0)
@sources = []
end
def environment=(value)
@environment = value
RailsEnvironment.default = value
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@script_name} [OPTIONS] command"
o.define_head "Rails plugin manager."
o.separator ""
o.separator "GENERAL OPTIONS"
o.on("-r", "--root=DIR", String,
"Set an explicit rails app directory.",
"Default: #{@rails_root}") { |@rails_root| self.environment = RailsEnvironment.new(@rails_root) }
o.on("-s", "--source=URL1,URL2", Array,
"Use the specified plugin repositories instead of the defaults.") { |@sources|}
o.on("-v", "--verbose", "Turn on verbose output.") { |$verbose| }
o.on("-h", "--help", "Show this help message.") { puts o; exit }
o.separator ""
o.separator "COMMANDS"
o.separator " discover Discover plugin repositories."
o.separator " list List available plugins."
o.separator " install Install plugin(s) from known repositories or URLs."
o.separator " update Update installed plugins."
o.separator " remove Uninstall plugins."
o.separator " source Add a plugin source repository."
o.separator " unsource Remove a plugin repository."
o.separator " sources List currently configured plugin repositories."
o.separator ""
o.separator "EXAMPLES"
o.separator " Install a plugin:"
o.separator " #{@script_name} install continuous_builder\n"
o.separator " Install a plugin from a subversion URL:"
o.separator " #{@script_name} install http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder\n"
o.separator " Install a plugin and add a svn:externals entry to vendor/plugins"
o.separator " #{@script_name} install -x continuous_builder\n"
o.separator " List all available plugins:"
o.separator " #{@script_name} list\n"
o.separator " List plugins in the specified repository:"
o.separator " #{@script_name} list --source=http://dev.rubyonrails.com/svn/rails/plugins/\n"
o.separator " Discover and prompt to add new repositories:"
o.separator " #{@script_name} discover\n"
o.separator " Discover new repositories but just list them, don't add anything:"
o.separator " #{@script_name} discover -l\n"
o.separator " Add a new repository to the source list:"
o.separator " #{@script_name} source http://dev.rubyonrails.com/svn/rails/plugins/\n"
o.separator " Remove a repository from the source list:"
o.separator " #{@script_name} unsource http://dev.rubyonrails.com/svn/rails/plugins/\n"
o.separator " Show currently configured repositories:"
o.separator " #{@script_name} sources\n"
end
end
def parse!(args=ARGV)
general, sub = split_args(args)
options.parse!(general)
command = general.shift
if command =~ /^(list|discover|install|source|unsource|sources|remove|update)$/
command = Commands.const_get(command.capitalize).new(self)
command.parse!(sub)
else
puts "Unknown command: #{command}"
puts options
exit 1
end
end
def split_args(args)
left = []
left << args.shift while args[0] and args[0] =~ /^-/
left << args.shift if args[0]
return [left, args]
end
def self.parse!(args=ARGV)
Plugin.new.parse!(args)
end
end
class List
def initialize(base_command)
@base_command = base_command
@sources = []
@local = false
@remote = true
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} list [OPTIONS] [PATTERN]"
o.define_head "List available plugins."
o.separator ""
o.separator "Options:"
o.separator ""
o.on( "-s", "--source=URL1,URL2", Array,
"Use the specified plugin repositories.") {|@sources|}
o.on( "--local",
"List locally installed plugins.") {|@local| @remote = false}
o.on( "--remote",
"List remotely availabled plugins. This is the default behavior",
"unless --local is provided.") {|@remote|}
end
end
def parse!(args)
options.order!(args)
unless @sources.empty?
@sources.map!{ |uri| Repository.new(uri) }
else
@sources = Repositories.instance.all
end
if @remote
@sources.map{|r| r.plugins}.flatten.each do |plugin|
if @local or !plugin.installed?
puts plugin.to_s
end
end
else
cd "#{@base_command.environment.root}/vendor/plugins"
Dir["*"].select{|p| File.directory?(p)}.each do |name|
puts name
end
end
end
end
class Sources
def initialize(base_command)
@base_command = base_command
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} sources [OPTIONS] [PATTERN]"
o.define_head "List configured plugin repositories."
o.separator ""
o.separator "Options:"
o.separator ""
o.on( "-c", "--check",
"Report status of repository.") { |@sources|}
end
end
def parse!(args)
options.parse!(args)
Repositories.each do |repo|
puts repo.uri
end
end
end
class Source
def initialize(base_command)
@base_command = base_command
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} source REPOSITORY"
o.define_head "Add a new repository."
end
end
def parse!(args)
options.parse!(args)
count = 0
args.each do |uri|
if Repositories.instance.add(uri)
puts "added: #{uri.ljust(50)}" if $verbose
count += 1
else
puts "failed: #{uri.ljust(50)}"
end
end
Repositories.instance.save
puts "Added #{count} repositories."
end
end
class Unsource
def initialize(base_command)
@base_command = base_command
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} source URI [URI [URI]...]"
o.define_head "Remove repositories from the default search list."
o.separator ""
o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
end
end
def parse!(args)
options.parse!(args)
count = 0
args.each do |uri|
if Repositories.instance.remove(uri)
count += 1
puts "removed: #{uri.ljust(50)}"
else
puts "failed: #{uri.ljust(50)}"
end
end
Repositories.instance.save
puts "Removed #{count} repositories."
end
end
class Discover
def initialize(base_command)
@base_command = base_command
@list = false
@prompt = true
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} discover URI [URI [URI]...]"
o.define_head "Discover repositories referenced on a page."
o.separator ""
o.separator "Options:"
o.separator ""
o.on( "-l", "--list",
"List but don't prompt or add discovered repositories.") { |@list| @prompt = !@list }
o.on( "-n", "--no-prompt",
"Add all new repositories without prompting.") { |v| @prompt = !v }
end
end
def parse!(args)
options.parse!(args)
args = ['http://wiki.rubyonrails.org/rails/pages/Plugins'] if args.empty?
args.each do |uri|
scrape(uri) do |repo_uri|
catch(:next_uri) do
if @prompt
begin
$stdout.print "Add #{repo_uri}? [Y/n] "
throw :next_uri if $stdin.gets !~ /^y?$/i
rescue Interrupt
$stdout.puts
exit 1
end
elsif @list
puts repo_uri
throw :next_uri
end
Repositories.instance.add(repo_uri)
puts "discovered: #{repo_uri}" if $verbose or !@prompt
end
end
end
Repositories.instance.save
end
def scrape(uri)
require 'open-uri'
puts "Scraping #{uri}" if $verbose
dupes = []
content = open(uri).each do |line|
if line =~ /<a[^>]*href=['"]([^'"]*)['"]/ or line =~ /(svn:\/\/[^<|\n]*)/
uri = $1
if uri =~ /\/plugins\// and uri !~ /\/browser\//
uri = extract_repository_uri(uri)
yield uri unless dupes.include?(uri) or Repositories.instance.exist?(uri)
dupes << uri
end
end
end
end
def extract_repository_uri(uri)
uri.match(/(svn|https?):.*\/plugins\//i)[0]
end
end
class Install
def initialize(base_command)
@base_command = base_command
@method = :http
@options = { :quiet => false, :revision => nil, :force => false }
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]"
o.define_head "Install one or more plugins."
o.separator ""
o.separator "Options:"
o.on( "-x", "--externals",
"Use svn:externals to grab the plugin.",
"Enables plugin updates and plugin versioning.") { |v| @method = :externals }
o.on( "-o", "--checkout",
"Use svn checkout to grab the plugin.",
"Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
o.on( "-q", "--quiet",
"Suppresses the output from installation.",
"Ignored if -v is passed (./script/plugin -v install ...)") { |v| @options[:quiet] = true }
o.on( "-r REVISION", "--revision REVISION",
"Checks out the given revision from subversion.",
"Ignored if subversion is not used.") { |v| @options[:revision] = v }
o.on( "-f", "--force",
"Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true }
o.separator ""
o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
o.separator "a plugin repository."
end
end
def determine_install_method
best = @base_command.environment.best_install_method
@method = :http if best == :http and @method == :export
case
when (best == :http and @method != :http)
msg = "Cannot install using subversion because `svn' cannot be found in your PATH"
when (best == :export and (@method != :export and @method != :http))
msg = "Cannot install using #{@method} because this project is not under subversion."
when (best != :externals and @method == :externals)
msg = "Cannot install using externals because vendor/plugins is not under subversion."
end
if msg
puts msg
exit 1
end
@method
end
def parse!(args)
options.parse!(args)
environment = @base_command.environment
install_method = determine_install_method
puts "Plugins will be installed using #{install_method}" if $verbose
args.each do |name|
if name =~ /\// then
::Plugin.new(name).install(install_method, @options)
else
plugin = Repositories.instance.find_plugin(name)
unless plugin.nil?
plugin.install(install_method, @options)
else
puts "Plugin not found: #{name}"
exit 1
end
end
end
end
end
class Update
def initialize(base_command)
@base_command = base_command
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
o.on( "-r REVISION", "--revision REVISION",
"Checks out the given revision from subversion.",
"Ignored if subversion is not used.") { |v| @revision = v }
o.define_head "Update plugins."
end
end
def parse!(args)
options.parse!(args)
root = @base_command.environment.root
cd root
args = Dir["vendor/plugins/*"].map do |f|
File.directory?("#{f}/.svn") ? File.basename(f) : nil
end.compact if args.empty?
cd "vendor/plugins"
args.each do |name|
if File.directory?(name)
puts "Updating plugin: #{name}"
system("svn #{$verbose ? '' : '-q'} up \"#{name}\" #{@revision ? "-r #{@revision}" : ''}")
else
puts "Plugin doesn't exist: #{name}"
end
end
end
end
class Remove
def initialize(base_command)
@base_command = base_command
end
def options
OptionParser.new do |o|
o.set_summary_indent(' ')
o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
o.define_head "Remove plugins."
end
end
def parse!(args)
options.parse!(args)
root = @base_command.environment.root
args.each do |name|
::Plugin.new(name).uninstall
end
end
end
end
class RecursiveHTTPFetcher
attr_accessor :quiet
def initialize(urls_to_fetch, cwd = ".")
@cwd = cwd
@urls_to_fetch = urls_to_fetch.to_a
@quiet = false
end
def ls
@urls_to_fetch.collect do |url|
if url =~ /^svn:\/\/.*/
`svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil
else
open(url) do |stream|
links("", stream.read)
end rescue nil
end
end.flatten
end
def push_d(dir)
@cwd = File.join(@cwd, dir)
FileUtils.mkdir_p(@cwd)
end
def pop_d
@cwd = File.dirname(@cwd)
end
def links(base_url, contents)
links = []
contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
link = link.sub(/href="/i, "")
next if link =~ /^http/i || link =~ /^\./
links << File.join(base_url, link)
end
links
end
def download(link)
puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
open(link) do |stream|
File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
file.write(stream.read)
end
end
end
def fetch(links = @urls_to_fetch)
links.each do |l|
(l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
end
end
def fetch_dir(url)
push_d(File.basename(url))
open(url) do |stream|
contents = stream.read
fetch(links(url, contents))
end
pop_d
end
end
Commands::Plugin.parse!

View file

@ -0,0 +1,130 @@
require 'optparse'
require 'net/http'
require 'uri'
if RUBY_PLATFORM =~ /mswin32/ then abort("Reaper is only for Unix") end
# Instances of this class represent a single running process. Processes may
# be queried by "keyword" to find those that meet a specific set of criteria.
class ProgramProcess
class << self
# Searches for all processes matching the given keywords, and then invokes
# a specific action on each of them. This is useful for (e.g.) reloading a
# set of processes:
#
# ProgramProcess.process_keywords(:reload, "basecamp")
def process_keywords(action, *keywords)
processes = keywords.collect { |keyword| find_by_keyword(keyword) }.flatten
if processes.empty?
puts "Couldn't find any process matching: #{keywords.join(" or ")}"
else
processes.each do |process|
puts "#{action.capitalize}ing #{process}"
process.send(action)
end
end
end
# Searches for all processes matching the given keyword:
#
# ProgramProcess.find_by_keyword("basecamp")
def find_by_keyword(keyword)
process_lines_with_keyword(keyword).split("\n").collect { |line|
next if line =~ /inq|ps axww|grep|spawn-fcgi|spawner|reaper/
pid, *command = line.split
new(pid, command.join(" "))
}.compact
end
private
def process_lines_with_keyword(keyword)
`ps axww -o 'pid command' | grep #{keyword}`
end
end
# Create a new ProgramProcess instance that represents the process with the
# given pid, running the given command.
def initialize(pid, command)
@pid, @command = pid, command
end
# Forces the (rails) application to reload by sending a +HUP+ signal to the
# process.
def reload
`kill -s HUP #{@pid}`
end
# Forces the (rails) application to gracefully terminate by sending a
# +TERM+ signal to the process.
def graceful
`kill -s TERM #{@pid}`
end
# Forces the (rails) application to terminate immediately by sending a -9
# signal to the process.
def kill
`kill -9 #{@pid}`
end
# Send a +USR1+ signal to the process.
def usr1
`kill -s USR1 #{@pid}`
end
# Force the (rails) application to restart by sending a +USR2+ signal to the
# process.
def restart
`kill -s USR2 #{@pid}`
end
def to_s #:nodoc:
"[#{@pid}] #{@command}"
end
end
OPTIONS = {
:action => "restart",
:dispatcher => File.expand_path(RAILS_ROOT + '/public/dispatch.fcgi')
}
ARGV.options do |opts|
opts.banner = "Usage: reaper [options]"
opts.separator ""
opts.on <<-EOF
Description:
The reaper is used to restart, reload, gracefully exit, and forcefully exit FCGI processes
running a Rails Dispatcher. This is commonly done when a new version of the application
is available, so the existing processes can be updated to use the latest code.
The reaper actions are:
* restart : Restarts the application by reloading both application and framework code
* reload : Only reloads the application, but not the framework (like the development environment)
* graceful: Marks all of the processes for exit after the next request
* kill : Forcefully exists all processes regardless of whether they're currently serving a request
Restart is the most common and default action.
Examples:
reaper # restarts the default dispatcher
reaper -a reload
reaper -a exit -d /my/special/dispatcher.fcgi
EOF
opts.on(" Options:")
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |v| OPTIONS[:action] = v }
opts.on("-d", "--dispatcher=path", "default: #{OPTIONS[:dispatcher]}", String) { |v| OPTIONS[:dispatcher] = v }
opts.separator ""
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
opts.parse!
end
ProgramProcess.process_keywords(OPTIONS[:action], OPTIONS[:dispatcher])

View file

@ -0,0 +1,94 @@
require 'optparse'
require 'socket'
def daemonize #:nodoc:
exit if fork # Parent exits, child continues.
Process.setsid # Become session leader.
exit if fork # Zap session leader. See [1].
Dir.chdir "/" # Release old working directory.
File.umask 0000 # Ensure sensible umask. Adjust as needed.
STDIN.reopen "/dev/null" # Free file descriptors and
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
end
def spawn(port)
print "Checking if something is already running on port #{port}..."
begin
srv = TCPServer.new('0.0.0.0', port)
srv.close
srv = nil
print "NO\n "
print "Starting FCGI on port: #{port}\n "
system("#{OPTIONS[:spawner]} -f #{OPTIONS[:dispatcher]} -p #{port}")
rescue
print "YES\n"
end
end
def spawn_all
OPTIONS[:instances].times { |i| spawn(OPTIONS[:port] + i) }
end
OPTIONS = {
:environment => "production",
:spawner => '/usr/bin/env spawn-fcgi',
:dispatcher => File.expand_path(RAILS_ROOT + '/public/dispatch.fcgi'),
:port => 8000,
:instances => 3,
:repeat => nil
}
ARGV.options do |opts|
opts.banner = "Usage: spawner [options]"
opts.separator ""
opts.on <<-EOF
Description:
The spawner is a wrapper for spawn-fcgi that makes it easier to start multiple FCGI
processes running the Rails dispatcher. The spawn-fcgi command is included with the lighttpd
web server, but can be used with both Apache and lighttpd (and any other web server supporting
externally managed FCGI processes).
You decide a starting port (default is 8000) and the number of FCGI process instances you'd
like to run. So if you pick 9100 and 3 instances, you'll start processes on 9100, 9101, and 9102.
By setting the repeat option, you get a protection loop, which will attempt to restart any FCGI processes
that might have been exited or outright crashed.
Examples:
spawner # starts instances on 8000, 8001, and 8002
spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109
spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds
EOF
opts.on(" Options:")
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |v| OPTIONS[:instances] = v }
opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |v| OPTIONS[:repeat] = v }
opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |v| OPTIONS[:environment] = v }
opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |v| OPTIONS[:spawner] = v }
opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
opts.separator ""
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
opts.parse!
end
ENV["RAILS_ENV"] = OPTIONS[:environment]
if OPTIONS[:repeat]
daemonize
trap("TERM") { exit }
loop do
spawn_all
sleep(OPTIONS[:repeat])
end
else
spawn_all
end

View file

@ -0,0 +1,57 @@
require 'optparse'
def daemonize #:nodoc:
exit if fork # Parent exits, child continues.
Process.setsid # Become session leader.
exit if fork # Zap session leader. See [1].
Dir.chdir "/" # Release old working directory.
File.umask 0000 # Ensure sensible umask. Adjust as needed.
STDIN.reopen "/dev/null" # Free file descriptors and
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
end
OPTIONS = {
:interval => 5.0,
:command => File.expand_path(RAILS_ROOT + '/script/process/spawner'),
:daemon => false
}
ARGV.options do |opts|
opts.banner = "Usage: spinner [options]"
opts.separator ""
opts.on <<-EOF
Description:
The spinner is a protection loop for the spawner, which will attempt to restart any FCGI processes
that might have been exited or outright crashed. It's a brute-force attempt that'll just try
to run the spawner every X number of seconds, so it does pose a light load on the server.
Examples:
spinner # attempts to run the spawner with default settings every second with output on the terminal
spinner -i 3 -d # only run the spawner every 3 seconds and detach from the terminal to become a daemon
spinner -c '/path/to/app/script/process/spawner -p 9000 -i 10' -d # using custom spawner
EOF
opts.on(" Options:")
opts.on("-c", "--command=path", String) { |v| OPTIONS[:command] = v }
opts.on("-i", "--interval=seconds", Float) { |v| OPTIONS[:interval] = v }
opts.on("-d", "--daemon") { |v| OPTIONS[:daemon] = v }
opts.separator ""
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
opts.parse!
end
daemonize if OPTIONS[:daemon]
trap(OPTIONS[:daemon] ? "TERM" : "INT") { exit }
loop do
system(OPTIONS[:command])
sleep(OPTIONS[:interval])
end

View file

@ -0,0 +1,27 @@
require 'optparse'
options = { :environment => (ENV['RAILS_ENV'] || "development").dup }
ARGV.options do |opts|
script_name = File.basename($0)
opts.banner = "Usage: runner 'puts Person.find(1).name' [options]"
opts.separator ""
opts.on("-e", "--environment=name", String,
"Specifies the environment for the runner to operate under (test/development/production).",
"Default: development") { |v| options[:environment] = v }
opts.separator ""
opts.on("-h", "--help",
"Show this help message.") { puts opts; exit }
opts.parse!
end
ENV["RAILS_ENV"] = options[:environment]
RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
require RAILS_ROOT + '/config/environment'
ARGV.empty? ? puts("Usage: runner 'code' [options]") : eval(ARGV.first)

View file

@ -0,0 +1,30 @@
require 'active_support'
require 'fileutils'
begin
require_library_or_gem 'fcgi'
rescue Exception
# FCGI not available
end
server = case ARGV.first
when "lighttpd"
ARGV.shift
when "webrick"
ARGV.shift
else
if RUBY_PLATFORM !~ /mswin/ && !silence_stderr { `lighttpd -version` }.blank? && defined?(FCGI)
"lighttpd"
else
"webrick"
end
end
if server == "webrick"
puts "=> Booting WEBrick..."
else
puts "=> Booting lighttpd (use 'script/server webrick' to force WEBrick)"
end
FileUtils.mkdir_p(%w( tmp/sessions tmp/cache tmp/sockets ))
require "commands/servers/#{server}"

View file

@ -0,0 +1,92 @@
require 'rbconfig'
unless RUBY_PLATFORM !~ /mswin/ && !silence_stderr { `lighttpd -version` }.blank?
puts "PROBLEM: Lighttpd is not available on your system (or not in your path)"
exit 1
end
unless defined?(FCGI)
puts "PROBLEM: Lighttpd requires that the FCGI Ruby bindings are installed on the system"
exit 1
end
require 'initializer'
configuration = Rails::Initializer.run(:initialize_logger).configuration
default_config_file = config_file = Pathname.new("#{RAILS_ROOT}/config/lighttpd.conf").cleanpath
require 'optparse'
detach = false
ARGV.options do |opt|
opt.on('-c', "--config=#{config_file}", 'Specify a different lighttpd config file.') { |path| config_file = path }
opt.on('-h', '--help', 'Show this message.') { puts opt; exit 0 }
opt.on('-d', '-d', 'Call with -d to detach') { detach = true; puts "=> Configuration in config/lighttpd.conf" }
opt.parse!
end
unless File.exist?(config_file)
if config_file != default_config_file
puts "=> #{config_file} not found."
exit 1
end
require 'fileutils'
source = File.expand_path(File.join(File.dirname(__FILE__),
"..", "..", "..", "configs", "lighttpd.conf"))
puts "=> #{config_file} not found, copying from #{source}"
FileUtils.cp(source, config_file)
end
config = IO.read(config_file)
default_port, default_ip = 3000, '0.0.0.0'
port = config.scan(/^\s*server.port\s*=\s*(\d+)/).first rescue default_port
ip = config.scan(/^\s*server.bind\s*=\s*"([^"]+)"/).first rescue default_ip
puts "=> Rails application started on http://#{ip || default_ip}:#{port || default_port}"
tail_thread = nil
if !detach
puts "=> Call with -d to detach"
puts "=> Ctrl-C to shutdown server (see config/lighttpd.conf for options)"
detach = false
cursor = File.size(configuration.log_path)
last_checked = Time.now
tail_thread = Thread.new do
File.open(configuration.log_path, 'r') do |f|
loop do
f.seek cursor
if f.mtime > last_checked
last_checked = f.mtime
contents = f.read
cursor += contents.length
print contents
end
sleep 1
end
end
end
end
trap(:INT) { exit }
begin
`rake tmp:sockets:clear` # Needed if lighttpd crashes or otherwise leaves FCGI sockets around
`lighttpd #{!detach ? "-D " : ""}-f #{config_file}`
ensure
unless detach
tail_thread.kill if tail_thread
puts 'Exiting'
# Ensure FCGI processes are reaped
silence_stream(STDOUT) do
ARGV.replace ['-a', 'kill']
require 'commands/process/reaper'
end
`rake tmp:sockets:clear` # Remove sockets on clean shutdown
end
end

View file

@ -0,0 +1,59 @@
require 'webrick'
require 'optparse'
OPTIONS = {
:port => 3000,
:ip => "0.0.0.0",
:environment => (ENV['RAILS_ENV'] || "development").dup,
:server_root => File.expand_path(RAILS_ROOT + "/public/"),
:server_type => WEBrick::SimpleServer,
:charset => "UTF-8",
:mime_types => WEBrick::HTTPUtils::DefaultMimeTypes
}
ARGV.options do |opts|
script_name = File.basename($0)
opts.banner = "Usage: ruby #{script_name} [options]"
opts.separator ""
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.",
"Default: 3000") { |v| OPTIONS[:port] = v }
opts.on("-b", "--binding=ip", String,
"Binds Rails to the specified ip.",
"Default: 0.0.0.0") { |v| OPTIONS[:ip] = v }
opts.on("-e", "--environment=name", String,
"Specifies the environment to run this server under (test/development/production).",
"Default: development") { |v| OPTIONS[:environment] = v }
opts.on("-m", "--mime-types=filename", String,
"Specifies an Apache style mime.types configuration file to be used for mime types",
"Default: none") { |mime_types_file| OPTIONS[:mime_types] = WEBrick::HTTPUtils::load_mime_types(mime_types_file) }
opts.on("-d", "--daemon",
"Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)."
) { OPTIONS[:server_type] = WEBrick::Daemon }
opts.on("-c", "--charset=charset", String,
"Set default charset for output.",
"Default: UTF-8") { |v| OPTIONS[:charset] = v }
opts.separator ""
opts.on("-h", "--help",
"Show this help message.") { puts opts; exit }
opts.parse!
end
ENV["RAILS_ENV"] = OPTIONS[:environment]
RAILS_ENV.replace(OPTIONS[:environment]) if defined?(RAILS_ENV)
require RAILS_ROOT + "/config/environment"
require 'webrick_server'
OPTIONS['working_directory'] = File.expand_path(RAILS_ROOT)
puts "=> Rails application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
puts "=> Ctrl-C to shutdown server; call with --help for options" if OPTIONS[:server_type] == WEBrick::SimpleServer
DispatchServlet.dispatch(OPTIONS)

View file

@ -0,0 +1,4 @@
require "#{RAILS_ROOT}/config/environment"
require 'rails_generator'
require 'rails_generator/scripts/update'
Rails::Generator::Scripts::Update.new.run(ARGV)