mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
202 lines
6.1 KiB
Ruby
202 lines
6.1 KiB
Ruby
![]() |
require 'singleton'
|
||
|
require 'optparse'
|
||
|
require 'pluginfactory'
|
||
|
|
||
|
|
||
|
module Mongrel
|
||
|
module Command
|
||
|
# A Command pattern implementation used to create the set of command available to the user
|
||
|
# from Mongrel. The script uses objects which implement this interface to do the
|
||
|
# user's bidding.
|
||
|
#
|
||
|
# Implementing a command is fairly easy. Refer to some of the stock commands in the
|
||
|
# lib/mongrel/command directory for examples.
|
||
|
class Command
|
||
|
include PluginFactory
|
||
|
|
||
|
attr_reader :valid, :done_validating
|
||
|
|
||
|
# Called by the implemented command to set the options for that command.
|
||
|
# Every option has a short and long version, a description, a variable to
|
||
|
# set, and a default value. No exceptions.
|
||
|
def options(opts)
|
||
|
# process the given options array
|
||
|
opts.each do |short, long, help, variable, default|
|
||
|
self.instance_variable_set(variable, default)
|
||
|
@opt.on(short, long, help) do |arg|
|
||
|
self.instance_variable_set(variable, arg)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Called by the subclass to setup the command and parse the argv arguments.
|
||
|
# The call is destructive on argv since it uses the OptionParser#parse! function.
|
||
|
def initialize(argv)
|
||
|
@opt = OptionParser.new
|
||
|
@valid = true
|
||
|
# this is retarded, but it has to be done this way because -h and -v exit
|
||
|
@done_validating = false
|
||
|
|
||
|
configure
|
||
|
|
||
|
# I need to add my own -h definition to prevent the -h by default from exiting.
|
||
|
@opt.on_tail("-h", "--help", "Show this message") do
|
||
|
@done_validating = true
|
||
|
puts @opt
|
||
|
end
|
||
|
|
||
|
# I need to add my own -v definition to prevent the -h from exiting by default as well.
|
||
|
@opt.on_tail("--version", "Show version") do
|
||
|
@done_validating = true
|
||
|
puts "No version yet."
|
||
|
end
|
||
|
|
||
|
@opt.parse! argv
|
||
|
end
|
||
|
|
||
|
# Tells the PluginFactory where to look for additional commands. By default
|
||
|
# it's just a "mongrel" directory wherever we are located.
|
||
|
def self.derivativeDirs
|
||
|
return ["mongrel"]
|
||
|
end
|
||
|
|
||
|
# Returns true/false depending on whether the command is configured properly.
|
||
|
def validate
|
||
|
return @valid
|
||
|
end
|
||
|
|
||
|
# Returns a help message. Defaults to OptionParser#help which should be good.
|
||
|
def help
|
||
|
@opt.help
|
||
|
end
|
||
|
|
||
|
# Runs the command doing it's job. You should implement this otherwise it will
|
||
|
# throw a NotImplementedError as a reminder.
|
||
|
def run
|
||
|
raise NotImplementedError
|
||
|
end
|
||
|
|
||
|
|
||
|
# Validates the given expression is true and prints the message if not, exiting.
|
||
|
def valid?(exp, message)
|
||
|
if not @done_validating and (not exp)
|
||
|
STDERR.puts message
|
||
|
@valid = false
|
||
|
@done_validating = true
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Validates that a file exists and if not displays the message
|
||
|
def valid_exists?(file, message)
|
||
|
valid?(file != nil && File.exist?(file), message)
|
||
|
end
|
||
|
|
||
|
|
||
|
# Validates that the file is a file and not a directory or something else.
|
||
|
def valid_file?(file, message)
|
||
|
valid?(file != nil && File.file?(file), message)
|
||
|
end
|
||
|
|
||
|
# Validates that the given directory exists
|
||
|
def valid_dir?(file, message)
|
||
|
valid?(file != nil && File.directory?(file), message)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
# A Singleton class that manages all of the available commands
|
||
|
# and handles running them.
|
||
|
class Registry
|
||
|
include Singleton
|
||
|
|
||
|
# Builds a list of possible commands from the Command derivates list
|
||
|
def commands
|
||
|
list = Command.derivatives()
|
||
|
match = Regexp.new("(.*::.*)|(.*command.*)", Regexp::IGNORECASE)
|
||
|
|
||
|
results = []
|
||
|
list.keys.each do |key|
|
||
|
results << key unless match.match(key.to_s)
|
||
|
end
|
||
|
|
||
|
return results.sort
|
||
|
end
|
||
|
|
||
|
# Prints a list of available commands.
|
||
|
def print_command_list
|
||
|
puts "Available commands are:\n"
|
||
|
|
||
|
self.commands.each do |name|
|
||
|
puts " - #{name}\n"
|
||
|
end
|
||
|
|
||
|
puts "Each command takes -h as an option to get help."
|
||
|
|
||
|
end
|
||
|
|
||
|
|
||
|
# Runs the args against the first argument as the command name.
|
||
|
# If it has any errors it returns a false, otherwise it return true.
|
||
|
def run(args)
|
||
|
# find the command and change the program's name to reflect it
|
||
|
cmd_name = args.shift
|
||
|
$0 = "#{cmd_name}"
|
||
|
|
||
|
if cmd_name == "?" or cmd_name == "help"
|
||
|
print_command_list
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
# command exists, set it up and validate it
|
||
|
begin
|
||
|
command = Command.create(cmd_name, args)
|
||
|
rescue FactoryError
|
||
|
STDERR.puts :command, "INVALID COMMAND."
|
||
|
print_command_list
|
||
|
return
|
||
|
end
|
||
|
|
||
|
# Normally the command is NOT valid right after being created
|
||
|
# but sometimes (like with -h or -v) there's no further processing
|
||
|
# needed so the command is already valid so we can skip it.
|
||
|
if not command.done_validating
|
||
|
if not command.validate
|
||
|
STDERR.puts :command, "#{cmd_name} reported an error. Use -h to get help."
|
||
|
return false
|
||
|
else
|
||
|
command.run
|
||
|
end
|
||
|
end
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
# Runs the command like normal, but redirects $stdout and $stderr to the
|
||
|
# requested log file (which should be a file like object opened by you).
|
||
|
# It also marks the start and end times in the log file.
|
||
|
def run_redirect(log, args)
|
||
|
res = false
|
||
|
|
||
|
begin
|
||
|
oldstdout = $stdout
|
||
|
oldstderr = $stderr
|
||
|
|
||
|
log.write ">>>>>> #{Time.now}\n"
|
||
|
$stdout = log
|
||
|
$stderr = log
|
||
|
|
||
|
res = run(args)
|
||
|
|
||
|
log.write "<<<<<< #{Time.now}\n"
|
||
|
|
||
|
ensure
|
||
|
$stdout = oldstdout
|
||
|
$stderr = oldstderr
|
||
|
return res
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|