getOptionList() as $opt) $defaults[$opt->destination] = $opt->default; $defaults = array_merge($defaults, $options); return $klass->execute($args, $defaults); } /** * A simple method that runs a ManagementUtility. */ public static function execute_from_command_line($argv=null) { $utility = new ManagementUtility($argv); $utility->execute(); } /** * Include any default options that all commands should accept here * so that ManagementUtility can handle them before searching for * user commands. */ public static function handle_default_options($options) { if (!empty($options['settings'])) putenv("BJORK_SETTINGS_MODULE={$options['settings']}"); if (!empty($options['includepath'])) set_include_path(get_include_path() . PATH_SEPARATOR . $options['includepath']); } } } namespace bjork\core\management { use strutils; use optparse\OptionParser, optparse\SystemExit, optparse\Values; use bjork\core\management, bjork\core\management\base, bjork\core\management\base\BaseCommand; class ImportError extends \Exception {} /** * An option parser that doesn't raise any errors on unknown options. * * This is needed because the --settings and --includepath options affect * the commands (and thus the options) that are available to the user. */ class LaxOptionParser extends OptionParser { function error($msg) {} function quit($status=0, $msg=null) { if ($msg) fwrite(STDERR, $msg); throw new \Exception($status); } /** * Output nothing. * * The lax options are included in the normal option parser, so under * normal usage, we don't need to print the lax options. */ function printHelp($file=null) {} /** * Output the basic options available to every command. * * This just redirects to the default print_help() behavior. */ function printLaxHelp() { parent::printHelp(); } function processArgs(&$largs, &$rargs, Values $values) { while (!empty($rargs)) { $arg = $rargs[0]; try { if (substr($arg, 0, 2) == '--' && strlen($arg) > 2) { $this->processLongOpt($rargs, $values); } else if (substr($arg, 0, 1) == '-' && strlen($arg) > 1) { $this->processShortOpts($rargs, $values); } else { array_shift($rargs); throw new \Exception(); } } catch (\Exception $e) { $largs[] = $arg; } } } } /** * A ManagementUtility has a number of commands, which can be manipulated * by editing the self.commands dictionary. */ class ManagementUtility { var $argv, $prog_name; function __construct($argv=null) { if (null === $argv) $argv = $_SERVER['argv']; $this->argv = $argv; $this->prog_name = basename($this->argv[0]); } /** * Returns the script's main help text, as a string. */ function getMainHelpText($commands_only=false) { if ($commands_only) { $usage = array_keys(management::get_commands()); sort($usage); } else { $usage = array( '', "Type '{$this->prog_name} help ' for help on a ". 'specific subcommand.', '', 'Available subcommands:', ); $commands_dict = array(); foreach (management::get_commands() as $name => $app) { if ($app == 'bjork\core') { $app = 'bjork'; } else { $parts = strutils::rpartition($app, '\\'); $app = array_pop($parts); } $commands_dict[$app][] = $name; } foreach ($commands_dict as $app => $commands) { $usage[] = ''; $usage[] = "[{$app}]"; sort($commands); foreach ($commands as $name) { $usage[] = " {$name}"; } } } return implode("\n", $usage); } /** * Tries to fetch the given subcommand, printing a message with the * appropriate command called from the command line (usually * "bjork-admin.php" or "manage.php") if it can't be found. */ function fetchCommand($subcommand) { $commands = management::get_commands(); if (!array_key_exists($subcommand, $commands)) { fwrite(STDERR, "Unknown command: {$subcommand}\n". "Type '{$this->prog_name} help' for usage.\n"); exit(1); } $app_name = $commands[$subcommand]; if ($app_name instanceof BaseCommand) // If the command is already loaded, use it directly. $klass = $app_name; else $klass = management::load_command_class($app_name, $subcommand); return $klass; } /** * Given the command-line arguments, this figures out which subcommand is * being run, creates a parser appropriate to that command, and runs it. */ function execute() { $parser = new LaxOptionParser(array( 'usage' => '%prog subcommand [options] [args]', 'version' => management::get_version(), 'option_list' => BaseCommand::getDefaultOptionList() )); $options = array(); $args = array(); try { list($options, $args) = $parser->parseArgs($this->argv); management::handle_default_options($options); } catch (\Exception $e) { // Ignore any option errors at this point. } try { $subcommand = $this->argv[1]; } catch (\ErrorException $e) { $subcommand = 'help'; // Display help if no arguments were given. } if ($subcommand == 'help') { if (count($args) <= 2) { $parser->printLaxHelp(); fwrite(STDOUT, $this->getMainHelpText() . "\n"); } else if ($args[2] == '--commands') { fwrite(STDOUT, $this->getMainHelpText(true) . "\n"); } else { $this->fetchCommand($args[2])->printHelp($this->prog_name, $args[2]); } } else if ($subcommand == 'version') { fwrite(STDOUT, $parser->getVersion() . "\n"); } else if (array_slice($this->argv, 1) === array('--version')) { // LaxOptionParser already takes care of printing the version. } else if (in_array(array_slice($this->argv, 1), array(array('--help'), array('-h')))) { $parser->printLaxHelp(); fwrite(STDOUT, $this->getMainHelpText() . "\n"); } else { $this->fetchCommand($subcommand)->runFromArgv($this->argv); } } } }