*/
$GLOBALS['_PEAR_Command_commandlist'] = array();
+/**
+ * Array of command objects
+ * @var array class => object
+ */
+$GLOBALS['_PEAR_Command_objects'] = array();
+
/**
* Which user interface class is being used.
* @var string class name
*/
$GLOBALS['_PEAR_Command_uiobject'] = null;
-/**
-* The options accepted by the commands
-* @var string the options
-*/
-$GLOBALS['_PEAR_Command_commandopts'] = '';
-
/**
* PEAR command class, a simple factory class for administrative
* commands.
* - DON'T OUTPUT ANYTHING! Return text for output instead.
*
* - DON'T USE HTML! The text you return will be used from both Gtk,
- * web and command-line interfaces, so for now keep everything to
- * plain text.
+ * web and command-line interfaces, so for now, keep everything to
+ * plain text. There may be a common (XML) markup format later.
*
* - DON'T USE EXIT OR DIE! Always use pear errors. From static
* classes do PEAR::raiseError(), from other classes do
/**
* Get the right object for executing a command.
*
- * @param object Instance of PEAR_Config object
- * @param string The name of the command
+ * @param string $command The name of the command
+ * @param object $config Instance of PEAR_Config object
*
* @return object the command object or a PEAR error
*
if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
PEAR_Command::registerCommands();
}
- if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
- $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
- $obj = &new $class(PEAR_Command::getFrontendObject(), $config);
- return $obj;
+ $class = @$GLOBALS['_PEAR_Command_commandlist'][$command];
+ if (empty($class)) {
+ return PEAR::raiseError("unknown command `$command'");
}
- return PEAR::raiseError("unknown command `$command'");
+ $ui = PEAR_Command::getFrontendObject();
+ $obj = &new $class($ui, $config);
+ return $obj;
}
/**
*/
function &getFrontendObject()
{
- global $_PEAR_Command_uiclass, $_PEAR_Command_uiobject;
- if (empty($_PEAR_Command_uiobject)) {
- $_PEAR_Command_uiobject = &new $_PEAR_Command_uiclass;
+ if (empty($GLOBALS['_PEAR_Command_uiobject'])) {
+ $GLOBALS['_PEAR_Command_uiobject'] = &new $GLOBALS['_PEAR_Command_uiclass'];
}
- return $_PEAR_Command_uiobject;
+ return $GLOBALS['_PEAR_Command_uiobject'];
}
/**
* Load current frontend class.
*
- * @param string Name of the frontend
+ * @param string $uiclass Name of class implementing the frontend
*
- * @return boolean TRUE if the frontend exists, otherwise FALSE.
+ * @return object the frontend object, or a PEAR error
*/
- function setFrontendClass($uiclass)
+ function &setFrontendClass($uiclass)
{
- $GLOBALS['_PEAR_Command_uiclass'] = $uiclass;
- $file = str_replace("_", "/", $uiclass) . '.php';
- include_once $file;
- return class_exists(strtolower($uiclass));
+ $file = str_replace('_', '/', $uiclass) . '.php';
+ @include_once $file;
+ if (class_exists(strtolower($uiclass))) {
+ $obj = &new $uiclass;
+ // quick test to see if this class implements a few of the most
+ // important frontend methods
+ if (method_exists($obj, 'displayLine') && method_exists($obj, 'userConfirm')) {
+ $GLOBALS['_PEAR_Command_uiobject'] = &$obj;
+ $GLOBALS['_PEAR_Command_uiclass'] = $uiclass;
+ return $obj;
+ } else {
+ return PEAR::raiseError("not a frontend class: $uiclass");
+ }
+ }
+ return PEAR::raiseError("no such class: $uiclass");
}
/**
* Set current frontend.
*
- * @param string Name of the frontend type
+ * @param string $uitype Name of the frontend type (for example "CLI")
*
- * @return boolean TRUE if the frontend exists, otherwise FALSE.
+ * @return object the frontend object, or a PEAR error
*/
function setFrontendType($uitype)
{
}
$dp = @opendir($dir);
if (empty($dp)) {
- return PEAR::raiseError("PEAR_Command::registerCommands: ".
- "opendir($dir) failed");
+ return PEAR::raiseError("registerCommands: opendir($dir) failed");
}
if (!$merge) {
$GLOBALS['_PEAR_Command_commandlist'] = array();
}
- $cmdopts = array();
while ($entry = readdir($dp)) {
- if ($entry{0} == '.' || substr($entry, -4) != '.php' ||
- $entry == 'Common.php')
- {
+ if ($entry{0} == '.' || substr($entry, -4) != '.php' || $entry == 'Common.php') {
continue;
}
$class = "PEAR_Command_".substr($entry, 0, -4);
$file = "$dir/$entry";
include_once $file;
// List of commands
- $implements = call_user_func(array($class, "getCommands"));
+ if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
+ $GLOBALS['_PEAR_Command_objects'][$class] = &new $class($ui, $config);
+ }
+ $implements = $GLOBALS['_PEAR_Command_objects'][$class]->getCommands();
foreach ($implements as $command => $desc) {
$GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
$GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc;
}
- // List of options accepted
- $cmdopts = array_merge($cmdopts, call_user_func(array($class, "getOptions")));
}
- $GLOBALS['_PEAR_Command_commandopts'] = implode('', $cmdopts);
return true;
}
}
/**
- * Get the list of currently supported options, and what
- * classes implement them.
+ * Compiles arguments for getopt.
*
- * @return array array option => implementing class
+ * @param string $command command to get optstring for
+ * @param string $short_args (reference) short getopt format
+ * @param array $long_args (reference) long getopt format
+ *
+ * @return void
*
* @access public
*/
- function getOptions()
+ function getGetoptArgs($command, &$short_args, &$long_args)
{
if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
PEAR_Command::registerCommands();
}
- return $GLOBALS['_PEAR_Command_commandopts'];
+ $class = @$GLOBALS['_PEAR_Command_commandlist'][$command];
+ if (empty($class)) {
+ return null;
+ }
+ $obj = &$GLOBALS['_PEAR_Command_objects'][$class];
+ return $obj->getGetoptArgs($command, $short_args, $long_args);
}
/**
/**
* Get help for command.
*
- * @param string Name of the command for which help should be
- * called.
+ * @param string $command Name of the command to return help for
*
* @access public
*/
{
$cmds = PEAR_Command::getCommands();
if (isset($cmds[$command])) {
- return call_user_func(array($cmds[$command], 'getHelp'), $command);
+ $class = $cmds[$command];
+ return $GLOBALS['_PEAR_Command_objects'][$class]->getHelp($command);
}
return false;
}
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
-// | Author: Stig Bakken <ssb@fast.no> |
+// | Author: Stig Sæther Bakken <ssb@fast.no> |
// +----------------------------------------------------------------------+
//
// $Id$
class PEAR_Command_Common extends PEAR
{
+ // {{{ properties
+
/**
* PEAR_Config object used to pass user system and configuration
* on when executing commands
*/
var $ui;
+ // }}}
+ // {{{ constructor
+
/**
* PEAR_Command_Common constructor.
*
$this->ui = &$ui;
}
- function getOptions()
- {
- return array();
- }
+ // }}}
+
+ // {{{ getHelp()
function getHelp($command)
{
return array(null, 'No help avaible yet');
}
+
+ // }}}
+ // {{{ getGetoptArgs()
+
+ function getGetoptArgs($command, &$short_args, &$long_args)
+ {
+ $short_args = "";
+ $long_args = array();
+ if (empty($this->commands[$command])) {
+ return;
+ }
+ reset($this->commands[$command]);
+ while (list($option, $info) = each($this->commands[$command]['options'])) {
+ $larg = $sarg = '';
+ if (isset($info['arg'])) {
+ if ($info['arg']{0} == '(') {
+ $larg = '==';
+ $sarg = '::';
+ $arg = substr($info['arg'], 1, -1);
+ } else {
+ $larg = '=';
+ $sarg = ':';
+ $arg = $info['arg'];
+ }
+ }
+ if (isset($info['shortopt'])) {
+ $short_args .= $info['shortopt'] . $sarg;
+ }
+ $long_args[] = $option . $larg;
+ }
+ }
+
+ // }}}
+ // {{{ run()
+
+ function run($command, $options, $params)
+ {
+ $func = @$this->commands[$command]['function'];
+ if (empty($func)) {
+ return $this->raiseError("unknown command `$command'");
+ }
+ return $this->$func($command, $options, $params);
+ }
+
+ // }}}
}
?>
\ No newline at end of file
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
-// | Author: Stig Bakken <ssb@fast.no> |
+// | Author: Stig Sæther Bakken <ssb@fast.no> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once "PEAR/Command/Common.php";
require_once "PEAR/Installer.php";
+require_once "Console/Getopt.php";
/**
* PEAR commands for installation or deinstallation/upgrading of
*/
class PEAR_Command_Install extends PEAR_Command_Common
{
+ // {{{ command definitions
+
+ var $commands = array(
+ 'install' => array(
+ 'summary' => 'Install Package',
+ 'function' => 'doInstall',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'will overwrite newer installed packages',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, install anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as installed',
+ ),
+ 'soft' => array(
+ 'shortopt' => 's',
+ 'doc' => 'soft install, fail silently, or upgrade if already installed',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ ),
+ 'doc' => 'Installs one or more PEAR packages. You can specify a package to
+install in four ways:
+
+"Package-1.0.tgz" : installs from a local file
+
+"http://example.com/Package-1.0.tgz" : installs from
+anywhere on the net.
+
+"package.xml" : installs the package described in
+package.xml. Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+"Package" : queries your configured server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+More than one package may be specified at once. It is ok to mix these
+four ways of specifying packages.
+'),
+ 'upgrade' => array(
+ 'summary' => 'Upgrade Package',
+ 'function' => 'doInstall',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'overwrite newer installed packages',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, upgrade anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as upgraded',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'request uncompressed files when downloading',
+ ),
+ ),
+ 'doc' => 'Upgrades one or more PEAR packages. See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+'),
+ 'uninstall' => array(
+ 'summary' => 'Un-install Package',
+ 'function' => 'doUninstall',
+ 'options' => array(
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, uninstall anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not remove files, only register the packages as not installed',
+ ),
+ ),
+ 'doc' => 'Upgrades one or more PEAR packages. See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+'),
+
+ );
+
+ // }}}
// {{{ constructor
/**
*/
function getCommands()
{
- return array('install' => 'Install Package',
- 'uninstall' => 'Uninstall Package',
- 'upgrade' => 'Upgrade Package');
+ $ret = array();
+ foreach (array_keys($this->commands) as $command) {
+ $ret[$command] = $this->commands[$command]['summary'];
+ }
+ return $ret;
}
+ // }}}
+ // {{{ getHelp()
+
function getHelp($command)
{
switch ($command) {
return $ret;
}
- // }}}
- // {{{ getOptions()
-
- function getOptions()
- {
- return array('f', 'n', 'r', 's', 'Z');
- }
-
// }}}
// {{{ run()
function run($command, $options, $params)
{
- $installer = &new PEAR_Installer($this->ui);
-
+ $this->installer = &new PEAR_Installer($ui);
+// return parent::run($command, $options, $params);
$failmsg = '';
- $opts = array();
- if (isset($options['f'])) {
- $opts['force'] = true;
- }
- if (isset($options['n'])) {
- $opts['nodeps'] = true;
- }
- if (isset($options['r'])) {
- $opts['register_only'] = true;
- }
- if (isset($options['s'])) {
- $opts['soft'] = true;
- }
- if (isset($options['Z'])) {
- $opts['nocompress'] = true;
- }
switch ($command) {
case 'upgrade':
- $opts['upgrade'] = true;
+ $options['upgrade'] = true;
// fall through
- case 'install': {
- if ($installer->install(@$params[0], $opts, $this->config)) {
- $this->ui->displayLine("$command ok");
- } else {
- $failmsg = "$command failed";
+ case 'install':
+ foreach ($params as $pkg) {
+ $bn = basename($pkg);
+ $info = $this->installer->install($pkg, $options, $this->config);
+ if (is_array($info)) {
+ $label = "$info[package] $info[version]";
+ $this->ui->displayLine("$command ok: $label");
+ } else {
+ $failmsg = "$command failed";
+ }
}
break;
- }
- case 'uninstall': {
- if ($installer->uninstall($params[0], $options)) {
- $this->ui->displayLine("uninstall ok");
- } else {
- $failmsg = "uninstall failed";
+ case 'uninstall':
+ foreach ($params as $pkg) {
+ if ($this->installer->uninstall($pkg, $options)) {
+ $this->ui->displayLine("uninstall ok");
+ } else {
+ $failmsg = "uninstall failed";
+ }
}
break;
- }
- default: {
+ default:
return false;
- }
}
if ($failmsg) {
return $this->raiseError($failmsg);
*
* @param $pkgfile path to the package file
*
- * @return bool true if successful, false if not
+ * @return array package info if successful, null if not
*/
function install($pkgfile, $options = array())
{
// recognized options:
- // - register_only : update registry but don't install files
+ // - register-only : update registry but don't install files
// - upgrade : upgrade existing install
// - soft : fail silently
//
if (empty($options['soft'])) {
$this->log(0, $error);
}
- return $this->raiseError('Dependencies failed');
+ return $this->raiseError("$pkgname: dependencies failed");
}
}
if (empty($options['force']) && !version_compare($v2, $v1, 'gt')) {
return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
}
- if (empty($options['register_only'])) {
+ if (empty($options['register-only'])) {
// when upgrading, remove old release's files first:
if (PEAR::isError($err = $this->_deletePackageFiles($pkgname))) {
return $this->raiseError($err);
// info from the package it self we want to access from _installFile
$this->pkginfo = $pkginfo;
- if (empty($options['register_only'])) {
+ if (empty($options['register-only'])) {
if (!is_dir($this->config->get('php_dir'))) {
return $this->raiseError("no script destination directory\n",
null, PEAR_ERROR_DIE);
} else {
$ret = $this->registry->updatePackage($pkgname, $this->pkginfo, false);
}
- return $ret;
+ if (!$ret) {
+ return null;
+ }
+ return $pkginfo;
}
// }}}
PEAR_Command::setFrontendType('CLI');
$all_commands = PEAR_Command::getCommands();
-$cmd_options = PEAR_Command::getOptions();
-$progname = basename(__FILE__);
$argv = Console_Getopt::readPHPArgv();
-array_shift($argv);
-$options = Console_Getopt::getopt($argv, "c:C:d:D:Gh?sSqu:v" . $cmd_options);
+$progname = basename(array_shift($argv));
+$options = Console_Getopt::getopt($argv, "c:C:d:D:Gh?sSqu:v");
if (PEAR::isError($options)) {
usage($options);
}
$opts = $options[0];
$fetype = 'CLI';
-foreach ($opts as $opt) {
- if ($opt[0] == 'G') {
- $fetype = 'Gtk';
+if ($progname == 'gpear' || $progname == 'pear-gtk') {
+ $fetype = 'Gtk';
+} else {
+ foreach ($opts as $opt) {
+ if ($opt[0] == 'G') {
+ $fetype = 'Gtk';
+ }
}
}
PEAR_Command::setFrontendType($fetype);
$config->store('user');
}
-$command = (isset($options[1][0])) ? $options[1][0] : null;
+$command = (isset($options[1][0])) ? array_shift($options[1]) : null;
if (empty($command) && ($store_user_config || $store_system_config)) {
exit;
if (PEAR::isError($cmd)) {
die($cmd->getMessage());
}
+
+ $short_args = $long_args = array();
+ PEAR_Command::getGetoptArgs($command, $short_args, $long_args);
+ if (PEAR::isError($tmp = Console_Getopt::getopt($params, $short_args, $long_args))) {
+ return $this->raiseError($tmp);
+ }
+ list($tmpopt, $params) = $tmp;
+ $options = array();
+ foreach ($tmpopt as $foo => $tmp2) {
+ list($opt, $value) = $tmp2;
+ if ($value === null) {
+ $value = true;
+ }
+ if (strlen($opt) == 1) {
+ foreach ($this->commands[$command]['options'] as $o => $d) {
+ if (@$d['shortopt'] == $opt) {
+ $options[$o] = $value;
+ }
+ }
+ } else {
+ if (substr($opt, 0, 2) == '--') {
+ $options[substr($opt, 2)] = $value;
+ }
+ }
+ }
+
- $cmdargs = array_slice($options[1], 1);
- $ok = $cmd->run($command, $cmdopts, $cmdargs);
+
+ $ok = $cmd->run($command, $options[1]);
if ($ok === false) {
PEAR::raiseError("unknown command `$command'");
}
" -u foo unset `foo' in the user configuration\n".
" -h, -? display help/usage (this message)\n";
} elseif ($help = PEAR_Command::getHelp($command)) {
+ if (is_string($help)) {
+ $help = preg_replace('/{config\s+([^\}]+)}/e', "\$config->get('\1')", $help);
+ return "Usage : $help";
+ }
return "Usage : $progname $command {$help[0]}\n{$help[1]}";
}
return "No such command";