Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

This implements the Caspar CLI

Instead of modules (in TBG-world), Caspar handles things in
terms of namespaces. A cli directory should exist in the module's
directory, if that module is to have CLI commands. The namespace
of CLI command classes in that directory should be \module\cli,
and then cli commands are accessed in terms of module:command.

This does mean modules are used, but we access modules in terms of
the namespace, instead of using a modules table. It is anticipated
that module authors will use other namespaces, i.e. \module\foo
for their own work.

Everything is pretty much automatic now - there is no need to
explicitly state that CLI commands are available. Simply creating
the 'cli' directory is sufficient to get the CLI looking for
commands, any files of the form Grub.class.php, containing a class
\module\cli\Grub inheriting from \caspar\core\CliCommand will be
picked up and be automatically usable.

Core CLI commands go in the caspar\core\cli directory and the class
shall be \caspar\cli\Grub. In both cases, Grub is some unique
identifier within that namespace (and directory) for the command
but is not necessarily the command name, that can be specified
within the command.

Not implemented: authentication for CLI commands (should
authenticate automatically from the POSIX data, needs modifications
within the User object)
  • Loading branch information...
commit a84062c4c70dc5fe5c2121681f902710ebb1d230 1 parent a4fff17
@lsproc lsproc authored
View
114 caspar/bin/caspar
@@ -1,120 +1,112 @@
#!/usr/bin/php
<?php
- // Define The Bug Genie paths and related constants
- define('TBG_CLI', true);
+ // Define Caspar paths and related constants
+ define('CSP_CLI', true);
- defined('DS') || define('DS', DIRECTORY_SEPARATOR);
- defined('THEBUGGENIE_PATH') || define ('THEBUGGENIE_PATH', dirname(realpath(__FILE__)) . DS);
- defined('THEBUGGENIE_CORE_PATH') || define('THEBUGGENIE_CORE_PATH', THEBUGGENIE_PATH . 'core' . DS);
+ // This code requires PHP 5.3 or newer, so if we don't have it - complain
+ if (PHP_VERSION_ID < 50300) die('This software requires PHP 5.3.0 or newer, but you have an older version. Please upgrade');
- if( !defined('THEBUGGENIE_CONFIG_PATH'))
- {
- if(file_exists(getenv('HOME') . DS . '.remote_server'))
- define('THEBUGGENIE_CONFIG_PATH', getenv('HOME') . DS);
- else
- define('THEBUGGENIE_CONFIG_PATH', THEBUGGENIE_PATH);
- }
-
- defined('THEBUGGENIE_MODULES_PATH') || define('THEBUGGENIE_MODULES_PATH', THEBUGGENIE_PATH . 'modules' . DS);
- defined('THEBUGGENIE_PUBLIC_FOLDER_NAME') || define('THEBUGGENIE_PUBLIC_FOLDER_NAME', '');
+ // Set standard constants needed elsewhere
+ defined('DS') || define('DS', DIRECTORY_SEPARATOR);
+ defined('CASPAR_PATH') || define('CASPAR_PATH', realpath(getcwd() . DS) . DS . 'caspar' . DS);
try
{
// Include the "engine" script, which initializes and sets up stuff
- require THEBUGGENIE_PATH . 'core/tbg_engine.inc.php';
+ require CASPAR_PATH . 'bootstrap.inc.php';
}
catch (Exception $e)
{
- TBGCliCommand::cli_echo("An error occured when trying to initialize the command line client:\n", 'white', 'bold');
- TBGCliCommand::cli_echo($e->getMessage() . "\n", 'red', 'bold');
+ caspar\core\CliCommand::cli_echo("An error occured when trying to initialize the command line client:\n", 'white', 'bold');
+ caspar\core\CliCommand::cli_echo($e->getMessage() . "\n", 'red', 'bold');
die();
}
// Set up all available search paths for cli commands
$command_paths = array();
- $command_paths['main'] = THEBUGGENIE_PATH . 'modules' . DS . 'main' . DS . 'classes' . DS . 'cli' . DS;
- $command_paths['remote'] = THEBUGGENIE_PATH . 'modules' . DS . 'remote' . DS . 'classes' . DS . 'cli' . DS;
- foreach (TBGContext::getModules() as $module_name => $module)
+ $command_paths['caspar'] = CASPAR_CORE_PATH . 'cli' . DS;
+
+ $iterator = new \DirectoryIterator(CASPAR_MODULES_PATH);
+ foreach ($iterator as $fileinfo)
{
- $module_cli_path = THEBUGGENIE_PATH . 'modules' . DS . $module_name . DS . 'classes' . DS . 'cli' . DS;
- if (file_exists($module_cli_path))
+ if ($fileinfo->isDir())
{
- $command_paths[$module_name] = $module_cli_path;
+ if (file_exists($fileinfo->getPathname() . DS . 'cli'))
+ {
+ $command_paths[$fileinfo->getFilename()] = $fileinfo->getPathname() . DS . 'cli';
+ }
}
}
// Set up all cli commands
- $commands = array('main' => array());
- foreach ($command_paths as $module_name => $command_path)
+ foreach ($command_paths as $namespace_name => $command_path)
{
- TBGContext::addAutoloaderClasspath($command_path);
+ caspar\core\Caspar::autoloadNamespace($namespace_name.'\\cli', $command_path);
$_path_handle = opendir($command_path);
while ($command_class_file = readdir($_path_handle))
{
if (($classname = substr($command_class_file, 0, strpos($command_class_file, '.'))) != '')
{
- $module = (TBGContext::isModuleLoaded($module_name)) ? TBGContext::getModule($module_name) : null;
- $command = new $classname($module);
- if ($command instanceof TBGCliCommand)
+ $finalname = $namespace_name.'\\cli\\'.$classname;
+
+ $command = new $finalname($namespace_name);
+ if ($command instanceof caspar\core\CliCommand)
{
- $commands[$module_name][$command->getCommandName()] = $command;
+ $commands[$namespace_name][$command->getCommandName()] = $command;
foreach ($command->getCommandAliases() as $alias)
{
- $commands[$module_name][$alias] = $command;
+ $commands[$namespace_name][$alias] = $command;
}
}
}
}
}
- TBGCliCommand::setAvailableCommands($commands);
+ caspar\core\CliCommand::setAvailableCommands($commands);
if ($argc < 2)
{
// Show usage if no parameters are provided
- TBGCliCommand::cli_echo("The Bug Genie command line tool\n\n");
- TBGCliCommand::cli_echo("Usage: ", 'white', 'bold');
- TBGCliCommand::cli_echo(TBGCliCommand::getCommandLineName() . " [");
- TBGCliCommand::cli_echo('command', 'green', 'bold');
- TBGCliCommand::cli_echo("]\n");
- TBGCliCommand::cli_echo("Type " . TBGCliCommand::getCommandLineName() . ' ');
- TBGCliCommand::cli_echo('help', 'green', 'bold');
- TBGCliCommand::cli_echo(" for more information.\n\n");
+ caspar\core\CliCommand::cli_echo("Caspar command line tool\n\n");
+ caspar\core\CliCommand::cli_echo("Usage: ", 'white', 'bold');
+ caspar\core\CliCommand::cli_echo(caspar\core\CliCommand::getCommandLineName() . " [");
+ caspar\core\CliCommand::cli_echo('command', 'green', 'bold');
+ caspar\core\CliCommand::cli_echo("]\n");
+ caspar\core\CliCommand::cli_echo("Type " . caspar\core\CliCommand::getCommandLineName() . ' ');
+ caspar\core\CliCommand::cli_echo('help', 'green', 'bold');
+ caspar\core\CliCommand::cli_echo(" for more information.\n\n");
}
else
{
// Process arguments and invoke command if available
try
{
- TBGCliCommand::processArguments();
- $module_command = explode(':', $argv[1]);
- $module_name = (count($module_command) == 2) ? $module_command[0] : 'main';
- $command = (count($module_command) == 2) ? $module_command[1] : $module_command[0];
+ caspar\core\CliCommand::processArguments();
+ $namespace_command = explode(":", $argv[1]);
+ $namespace_name = (count($namespace_command) == 2) ? $namespace_command[0] : 'caspar';
+ $command = (count($namespace_command) == 2) ? $namespace_command[1] : $namespace_command[0];
- TBGContext::reinitializeI18n();
-
- if (array_key_exists($module_name, $commands) && array_key_exists($command, $commands[$module_name]))
+ if (array_key_exists($namespace_name, $commands) && array_key_exists($command, $commands[$namespace_name]))
{
- $class = $commands[$module_name][$command];
- TBGContext::setCLIRouting($module_name, $command);
+ $class = $commands[$namespace_name][$command];
$class->execute();
}
else
{
- TBGCliCommand::cli_echo("\n");
- TBGCliCommand::cli_echo("Unknown command\n", 'red', 'bold');
- TBGCliCommand::cli_echo("Type " . TBGCliCommand::getCommandLineName() . ' ');
- TBGCliCommand::cli_echo('help', 'green', 'bold');
- TBGCliCommand::cli_echo(" for more information about the cli tool.\n\n");
+ caspar\core\CliCommand::cli_echo("\n");
+ caspar\core\CliCommand::cli_echo("Unknown command\n", 'red', 'bold');
+ caspar\core\CliCommand::cli_echo("Type " . caspar\core\CliCommand::getCommandLineName() . ' ');
+ caspar\core\CliCommand::cli_echo('help', 'green', 'bold');
+ caspar\core\CliCommand::cli_echo(" for more information about the cli tool.\n\n");
}
}
catch (Exception $e)
{
- TBGCliCommand::cli_echo("\n");
- TBGCliCommand::cli_echo("The following error occured:\n", 'red', 'bold');
- TBGCliCommand::cli_echo($e->getMessage()."\n\n", 'red');
- TBGCliCommand::cli_echo("Type " . TBGCliCommand::getCommandLineName() . ' ');
- TBGCliCommand::cli_echo('help', 'green', 'bold');
- TBGCliCommand::cli_echo(" for more information about the cli tool.\n\n");
+ caspar\core\CliCommand::cli_echo("\n");
+ caspar\core\CliCommand::cli_echo("The following error occured:\n", 'red', 'bold');
+ caspar\core\CliCommand::cli_echo($e->getMessage()."\n\n", 'red');
+ caspar\core\CliCommand::cli_echo("Type " . caspar\core\CliCommand::getCommandLineName() . ' ');
+ caspar\core\CliCommand::cli_echo('help', 'green', 'bold');
+ caspar\core\CliCommand::cli_echo(" for more information about the cli tool.\n\n");
}
}
View
28 caspar/core/Caspar.class.php
@@ -201,7 +201,6 @@ public static function autoload($classname)
$classpath = (count($orig_class_details)) ? join(DS, $orig_class_details) . DS : '';
$basepath = $namespaces[$namespace];
$filename = $basepath . DS . $classpath . $classname_element . '.class.php';
- $filename_alternate = $basepath . DS . $classpath . "classes" . DS . $classname_element . ".class.php";
break;
}
array_pop($class_details);
@@ -222,6 +221,7 @@ public static function autoload($classname)
require $filename_alternate;
return;
}
+
}
/**
@@ -235,20 +235,6 @@ public static function getClasspaths()
}
/**
- * Setup the routing object with CLI parameters
- *
- * @param string $module
- * @param string $action
- */
- public static function setCLIRouting($module, $action)
- {
- self::$_routing->setCurrentRouteModule($module);
- self::$_routing->setCurrentRouteAction($action);
- self::$_routing->setCurrentRouteName('cli');
- self::$_routing->setCurrentRouteCSRFenabled(false);
- }
-
- /**
* Returns the routing object
*
* @return Routing
@@ -959,15 +945,15 @@ protected static function cliError($title, $exception)
*/
public static function exceptionHandler($exception)
{
- if (self::getRequest() instanceof Request && self::getRequest()->isAjaxCall()) {
- self::getResponse()->ajaxResponseText(404, $exception->getMessage());
- }
-
- self::getResponse()->cleanBuffer();
-
if (self::isCLI()) {
self::cliError($exception->getMessage(), $exception);
} else {
+ if (self::getRequest() instanceof Request && self::getRequest()->isAjaxCall()) {
+ self::getResponse()->ajaxResponseText(404, $exception->getMessage());
+ }
+
+ self::getResponse()->cleanBuffer();
+
require CASPAR_PATH . 'templates' . DS . 'error.php';
}
die();
View
14 caspar/core/CliCommand.class.php
@@ -35,13 +35,13 @@
protected $_optional_arguments = array();
- protected $_module = null;
+ protected $_namespace = null;
abstract protected function do_execute();
- final public function __construct($module = null)
+ final public function __construct($namespace = null)
{
- $this->_module = $module;
+ $this->_namespace = $namespace;
$this->_setup();
}
@@ -53,13 +53,13 @@
}
/**
- * Return the associated module for this command if any
+ * Return the associated namespace for this command, this will likely correlate to a module
*
- * @return TBGModule
+ * @return string
*/
- final protected function getModule()
+ final protected function getNamespace()
{
- return $this->_module;
+ return $this->_namespace;
}
public function getDescription()
View
150 caspar/core/cli/CliHelp.class.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace caspar\cli;
+
+ /**
+ * CLI command class, caspar -> help
+ *
+ * @author Daniel Andre Eikeland <zegenie@zegeniestudios.net>
+ * @version 1.0
+ * @license http://www.opensource.org/licenses/mozilla1.1.php Mozilla Public License 1.1 (MPL 1.1)
+ * @package caspar
+ * @subpackage cli
+ */
+
+ /**
+ * CLI command class, caspar -> help
+ *
+ * @package caspar
+ * @subpackage cli
+ */
+ class CliHelp extends \caspar\core\CliCommand
+ {
+
+ protected function _setup()
+ {
+ $this->_command_name = 'help';
+ $this->_description = "Prints out help information";
+ $this->addOptionalArgument('command', "Show help for the command specified");
+ }
+
+ public function do_execute()
+ {
+ $this->cliEcho("Caspar CLI help\n", 'white', 'bold');
+
+ if ($this->hasProvidedArgument('command'))
+ {
+ $namespace_command = explode(":", $this->getProvidedArgument('command'));
+ $namespace_name = (count($namespace_command) == 2) ? $namespace_command[0] : 'caspar';
+ $command = (count($namespace_command) == 2) ? $namespace_command[1] : $namespace_command[0];
+
+ $commands = self::getAvailableCommands();
+
+ if (array_key_exists($namespace_name, $commands) && array_key_exists($command, $commands[$namespace_name]))
+ {
+ $this->cliEcho("\n");
+ $class = $commands[$namespace_name][$command];
+ $this->cliEcho("Usage: ", 'white', 'bold');
+ $this->cliEcho(self::getCommandLineName() . " ");
+ if ($namespace_name != 'caspar')
+ {
+ $this->cliEcho($namespace_name.':', 'green', 'bold');
+ }
+ $this->cliEcho($class->getCommandName() . " ", 'green', 'bold');
+
+ $hasArguments = false;
+ foreach ($class->getRequiredArguments() as $argument => $description)
+ {
+ $this->cliEcho($argument . ' ', 'magenta', 'bold');
+ $hasArguments = true;
+ }
+ foreach ($class->getOptionalArguments() as $argument => $description)
+ {
+ $this->cliEcho('[' . $argument . '] ', 'magenta');
+ $hasArguments = true;
+ }
+ $this->cliEcho("\n");
+ $this->cliEcho($class->getDescription(), 'white', 'bold');
+ $this->cliEcho("\n\n");
+
+ if ($hasArguments)
+ {
+ $this->cliEcho("Argument descriptions:\n", 'white', 'bold');
+ foreach ($class->getRequiredArguments() as $argument => $description)
+ {
+ $this->cliEcho(" {$argument}", 'magenta', 'bold');
+ if ($description != '')
+ {
+ $this->cliEcho(" - {$description}");
+ }
+ else
+ {
+ $this->cliEcho(" - No description provided");
+ }
+ $this->cliEcho("\n");
+ }
+ foreach ($class->getOptionalArguments() as $argument => $description)
+ {
+ $this->cliEcho(" [{$argument}]", 'magenta');
+ if ($description != '')
+ {
+ $this->cliEcho(" - {$description}");
+ }
+ else
+ {
+ $this->cliEcho(" - No description provided");
+ }
+ $this->cliEcho("\n");
+ }
+ $this->cliEcho("\n");
+ $this->cliEcho("Parameters must be passed either in the order described above\nor in the following format:\n");
+ $this->cliEcho("--parameter_name=value", 'magenta');
+ $this->cliEcho("\n\n");
+ }
+ }
+ else
+ {
+ $this->cliEcho("\n");
+ $this->cliEcho("Unknown command\n", 'red', 'bold');
+ $this->cliEcho("Type " . self::getCommandLineName() . ' ', 'white', 'bold');
+ $this->cliEcho('help', 'green', 'bold');
+ $this->cliEcho(" for more information about the cli tool.\n\n");
+ }
+ }
+ else
+ {
+ $this->cliEcho("Below is a list of available commands:\n");
+ $this->cliEcho("Type ");
+ $this->cliEcho(self::getCommandLineName() . ' ', 'white', 'bold');
+ $this->cliEcho('help', 'green', 'bold');
+ $this->cliEcho(' command', 'magenta');
+ $this->cliEcho(" for more information about a specific command.\n\n");
+ $commands = $this->getAvailableCommands();
+
+ foreach ($commands as $namespace_name => $namespace_commands)
+ {
+ if ($namespace_name != 'caspar' && count($namespace_commands) > 0)
+ {
+ $this->cliEcho("\n{$namespace_name}:\n", 'green', 'bold');
+ }
+ ksort($namespace_commands, SORT_STRING);
+ foreach ($namespace_commands as $command_name => $command)
+ {
+ if ($namespace_name != 'caspar') $this->cliEcho(" ");
+ $this->cliEcho("{$command_name}", 'green', 'bold');
+ $this->cliEcho(" - {$command->getDescription()}\n");
+ }
+
+ if (count($commands) > 1 && $namespace_name == 'remote')
+ {
+ $this->cliEcho("\nModule commands, use ");
+ $this->cliEcho("module_name:command_name", 'green');
+ $this->cliEcho(" to run:");
+ }
+ }
+
+ $this->cliEcho("\n");
+ }
+ }
+
+ }
View
2  public/index.php
@@ -6,7 +6,7 @@
// Set standard constants needed elsewhere
defined('DS') || define('DS', DIRECTORY_SEPARATOR);
defined('CASPAR_PATH') || define('CASPAR_PATH', realpath(getcwd() . DS . '..' . DS) . DS . 'caspar' . DS);
- defined('THEBUGGENIE_SESSION_NAME') || define('CASPAR_SESSION_NAME', 'THEBUGGENIE');
+ defined('CASPAR_SESSION_NAME') || define('CASPAR_SESSION_NAME', 'CASPAR');
// Include the "engine" script, which initializes and sets up stuff
require CASPAR_PATH . 'bootstrap.inc.php';
Please sign in to comment.
Something went wrong with that request. Please try again.