diff options
author | zedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9> | 2006-02-12 01:38:04 +0000 |
---|---|---|
committer | zedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9> | 2006-02-12 01:38:04 +0000 |
commit | 996d1046659b9d5991ce42f89bb5e9a0356f0cfd (patch) | |
tree | 1dad6bbb0e6a26a51fe1e61c12b487d6275b99ac /lib/mongrel/command.rb | |
parent | 3a5dfe36b81d50db2c41ebe0b7bb99bb5ca8b738 (diff) | |
download | unicorn-996d1046659b9d5991ce42f89bb5e9a0356f0cfd.tar.gz |
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@31 19e92222-5c0b-0410-8929-a290d50e31e9
Diffstat (limited to 'lib/mongrel/command.rb')
-rw-r--r-- | lib/mongrel/command.rb | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/lib/mongrel/command.rb b/lib/mongrel/command.rb new file mode 100644 index 0000000..9d73dad --- /dev/null +++ b/lib/mongrel/command.rb @@ -0,0 +1,201 @@ +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 + |