diff --git a/pear/PEAR/Command.php b/pear/PEAR/Command.php index 6127a970996..08d5d5235b1 100644 --- a/pear/PEAR/Command.php +++ b/pear/PEAR/Command.php @@ -27,6 +27,12 @@ require_once "PEAR.php"; */ $GLOBALS['_PEAR_Command_commandlist'] = array(); +/** + * List of shortcuts to common commands. + * @var array shortcut => command + */ +$GLOBALS['_PEAR_Command_shortcuts'] = array(); + /** * Array of command objects * @var array class => object @@ -105,6 +111,9 @@ class PEAR_Command if (empty($GLOBALS['_PEAR_Command_commandlist'])) { PEAR_Command::registerCommands(); } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } $class = @$GLOBALS['_PEAR_Command_commandlist'][$command]; if (empty($class)) { return PEAR::raiseError("unknown command `$command'"); @@ -211,6 +220,10 @@ class PEAR_Command $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc; } + $shortcuts = $GLOBALS['_PEAR_Command_objects'][$class]->getShortcuts(); + foreach ($shortcuts as $shortcut => $command) { + $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; + } } return true; } @@ -231,6 +244,21 @@ class PEAR_Command return $GLOBALS['_PEAR_Command_commandlist']; } + /** + * Get the list of command shortcuts. + * + * @return array shortcut => command + * + * @access public + */ + function getShortcuts() + { + if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_shortcuts']; + } + /** * Compiles arguments for getopt. * diff --git a/pear/PEAR/Command/Auth.php b/pear/PEAR/Command/Auth.php index 2681787ed97..1035a1a2de8 100644 --- a/pear/PEAR/Command/Auth.php +++ b/pear/PEAR/Command/Auth.php @@ -31,22 +31,26 @@ class PEAR_Command_Auth extends PEAR_Command_Common var $commands = array( 'login' => array( 'summary' => 'Connects and authenticates to remote server', + 'shortcut' => 'li', 'function' => 'doLogin', 'options' => array(), - 'doc' => 'To use remote functions in the installer that require any kind of -privileges, you need to log in first. The username and password you -enter here will be stored in your per-user PEAR configuration -(~/.pearrc on Unix-like systems). After logging in, your username and -password will be sent along in subsequent operations on the remote server.', + 'doc' => ' +Log in to the remote server. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server.', ), 'logout' => array( 'summary' => 'Logs out from the remote server', + 'shortcut' => 'lo', 'function' => 'doLogout', 'options' => array(), - 'doc' => 'Logs out from the remote server. -This command does not actually connect to the remote -server, it only deletes the stored username and password from your -user configuration.', + 'doc' => ' +Logs out from the remote server. This command does not actually +connect to the remote server, it only deletes the stored username and +password from your user configuration.', ) ); diff --git a/pear/PEAR/Command/Common.php b/pear/PEAR/Command/Common.php index 7579e37d0b0..e57d2796990 100644 --- a/pear/PEAR/Command/Common.php +++ b/pear/PEAR/Command/Common.php @@ -71,6 +71,25 @@ class PEAR_Command_Common extends PEAR return $ret; } + // }}} + // {{{ getShortcuts() + + /** + * Return a list of all the command shortcuts defined by this class. + * @return array shortcut => command + * @access public + */ + function getShortcuts() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + if (isset($this->commands[$command]['shortcut'])) { + $ret[$this->commands[$command]['shortcut']] = $command; + } + } + return $ret; + } + // }}} // {{{ getOptions() @@ -151,10 +170,34 @@ class PEAR_Command_Common extends PEAR if (isset($this->commands[$command]['options']) && count($this->commands[$command]['options'])) { - $help = "Accepted options:\n"; - // XXX Add long options + $help = "Options:\n"; foreach ($this->commands[$command]['options'] as $k => $v) { - $help .= " -" . $v['shortopt'] . " " . $v['doc'] . "\n"; + if (isset($v['shortopt'])) { + $s = $v['shortopt']; + if (@$s{1} == ':') { + $argname = ''; + $optional = false; + if (@$s{2} == ':') { + $optional = true; + $argname = substr($s, 3); + } else { + $argname = substr($s, 2); + } + if (empty($argname)) { + $argname = 'arg'; + } + if ($optional) { + $help .= " -$s [$argname], --{$k}[=$argname]\n"; + } else { + $help .= " -$s $argname, --$k=$argname\n"; + } + } else { + $help .= " -$s, --$k\n"; + } + } else { + $help .= " --$k\n"; + } + $help .= " $v[doc]\n"; } return $help; } @@ -168,7 +211,17 @@ class PEAR_Command_Common extends PEAR { $func = @$this->commands[$command]['function']; if (empty($func)) { - return $this->raiseError("unknown command `$command'"); + // look for shortcuts + foreach (array_keys($this->commands) as $cmd) { + if (@$this->commands[$cmd]['shortcut'] == $command) { + $command = $cmd; + $func = @$this->commands[$command]['function']; + if (empty($func)) { + return $this->raiseError("unknown command `$command'"); + } + break; + } + } } return $this->$func($command, $options, $params); } diff --git a/pear/PEAR/Command/Config.php b/pear/PEAR/Command/Config.php index 2775a306e9f..fd919c95848 100644 --- a/pear/PEAR/Command/Config.php +++ b/pear/PEAR/Command/Config.php @@ -32,14 +32,18 @@ class PEAR_Command_Config extends PEAR_Command_Common var $commands = array( 'config-show' => array( 'summary' => 'Show All Settings', + 'function' => 'doConfigShow', + 'shortcut' => 'csh', 'options' => array(), - 'doc' => 'Displays all configuration values. An optional argument + 'doc' => ' +Displays all configuration values. An optional argument may be used to tell which configuration layer to display. Valid configuration layers are "user", "system" and "default". ', ), 'config-get' => array( 'summary' => 'Show One Setting', + 'function' => 'doConfigGet', 'options' => array(), 'doc' => 'Displays the value of one configuration parameter. The first argument is the name of the parameter, an optional second argument @@ -51,6 +55,7 @@ just specified. ), 'config-set' => array( 'summary' => 'Change Setting', + 'function' => 'doConfigSet', 'options' => array(), 'doc' => 'Sets the value of one configuration parameter. The first argument is the name of the parameter, the second argument is the new value. @@ -72,74 +77,75 @@ in. The default layer is "user". parent::PEAR_Command_Common($ui, $config); } - function run($command, $options, $params) + function doConfigShow($command, $options, $params) { - $cf = &$this->config; + // $params[0] -> the layer + if ($error = $this->_checkLayer(@$params[0])) { + $failmsg .= $error; + break; + } + $keys = $this->config->getKeys(); + sort($keys); + $this->ui->startTable(array('caption' => 'Configuration:')); + foreach ($keys as $key) { + $type = $this->config->getType($key); + $value = $this->config->get($key, @$params[0]); + if ($type == 'password' && $value) { + $value = '********'; + } elseif ($key == 'umask') { + $value = sprintf("%03o", $value); + } + if ($value === null || $value === '') { + $value = ''; + } elseif ($value === false) { + $value = 'false'; + } elseif ($value === true) { + $value = 'true'; + } + $this->ui->tableRow(array($key, $value)); + } + $this->ui->endTable(); + return true; + } + + function doConfigGet($command, $options, $params) + { + // $params[0] -> the parameter + // $params[1] -> the layer + if ($error = $this->_checkLayer(@$params[1])) { + $failmsg .= $error; + break; + } + if (sizeof($params) < 1 || sizeof($params) > 2) { + $failmsg .= "config-get expects 1 or 2 parameters"; + } elseif (sizeof($params) == 1) { + $this->ui->displayLine("$params[0] = " . $this->config->get($params[0])); + } else { + $this->ui->displayLine("($params[1])$params[0] = " . + $this->config->get($params[0], $params[1])); + } + return true; + } + + function doConfigSet($command, $options, $params) + { + // $param[0] -> a parameter to set + // $param[1] -> the value for the parameter + // $param[2] -> the layer $failmsg = ''; - switch ($command) { - case 'config-show': { - // $params[0] -> the layer - if ($error = $this->_checkLayer(@$params[0])) { - $failmsg .= $error; - break; - } - $keys = $cf->getKeys(); - sort($keys); - $this->ui->startTable(array('caption' => 'Configuration:')); - foreach ($keys as $key) { - $type = $cf->getType($key); - $value = $cf->get($key, @$params[0]); - if ($type == 'password' && $value) { - $value = '********'; - } - if (empty($value)) { - $value = ''; - } - $this->ui->tableRow(array($key, $value)); - } - $this->ui->endTable(); - break; - } - case 'config-get': { - // $params[0] -> the parameter - // $params[1] -> the layer - if ($error = $this->_checkLayer(@$params[1])) { - $failmsg .= $error; - break; - } - if (sizeof($params) < 1 || sizeof($params) > 2) { - $failmsg .= "config-get expects 1 or 2 parameters. Try \"help config-get\" for help"; - } elseif (sizeof($params) == 1) { - $this->ui->displayLine("$params[0] = " . $cf->get($params[0])); - } else { - $this->ui->displayLine("($params[1])$params[0] = " . - $cf->get($params[0], $params[1])); - } - break; - } - case 'config-set': { - // $param[0] -> a parameter to set - // $param[1] -> the value for the parameter - // $param[2] -> the layer - if (sizeof($params) < 2 || sizeof($params) > 3) { - $failmsg .= "config-set expects 2 or 3 parameters. Try \"help config-set\" for help"; - break; - } - if ($error = $this->_checkLayer(@$params[2])) { - $failmsg .= $error; - break; - } - if (!call_user_func_array(array(&$cf, 'set'), $params)) - { - $failmsg = "config-set (" . implode(", ", $params) . ") failed"; - } else { - $cf->store(); - } - break; - } - default: { - return false; - } + if (sizeof($params) < 2 || sizeof($params) > 3) { + $failmsg .= "config-set expects 2 or 3 parameters"; + break; + } + if ($error = $this->_checkLayer(@$params[2])) { + $failmsg .= $error; + break; + } + if (!call_user_func_array(array(&$this->config, 'set'), $params)) + { + $failmsg = "config-set (" . implode(", ", $params) . ") failed"; + } else { + $this->config->store(); } if ($failmsg) { return $this->raiseError($failmsg); diff --git a/pear/PEAR/Command/Install.php b/pear/PEAR/Command/Install.php index 8ba84db3431..18e4a21303e 100644 --- a/pear/PEAR/Command/Install.php +++ b/pear/PEAR/Command/Install.php @@ -57,7 +57,8 @@ class PEAR_Command_Install extends PEAR_Command_Common 'doc' => 'request uncompressed files when downloading', ), ), - 'doc' => 'Installs one or more PEAR packages. You can specify a package to + '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 @@ -97,7 +98,8 @@ four ways of specifying packages. 'doc' => 'request uncompressed files when downloading', ), ), - 'doc' => 'Upgrades one or more PEAR packages. See documentation for the + '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 @@ -119,14 +121,9 @@ More than one package may be specified at once. '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. + 'doc' => ' ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. '), ); @@ -145,52 +142,46 @@ More than one package may be specified at once. } // }}} - // {{{ run() - function run($command, $options, $params) + function doInstall($command, $options, $params) { - $this->installer = &new PEAR_Installer($ui); -// return parent::run($command, $options, $params); - $failmsg = ''; - switch ($command) { - case 'upgrade': - $options['upgrade'] = true; - // fall through - case 'install': - foreach ($params as $pkg) { - $bn = basename($pkg); - $info = $this->installer->install($pkg, $options, $this->config); - if (is_array($info)) { - if ($this->config->get('verbose') > 0) { - $label = "$info[package] $info[version]"; - $this->ui->displayLine("$command ok: $label"); - } - } else { - $failmsg = "$command failed"; - } - } - break; - case 'uninstall': - foreach ($params as $pkg) { - if ($this->installer->uninstall($pkg, $options)) { - if ($this->config->get('verbose') > 0) { - $this->ui->displayLine("uninstall ok"); - } - } else { - $failmsg = "uninstall failed"; - } - } - break; - default: - return false; + if (empty($this->installer)) { + $this->installer = &new PEAR_Installer($ui); } - if ($failmsg) { - return $this->raiseError($failmsg); + if ($command == 'upgrade') { + $options[$command] = true; + } + foreach ($params as $pkg) { + $bn = basename($pkg); + $info = $this->installer->install($pkg, $options, $this->config); + if (is_array($info)) { + if ($this->config->get('verbose') > 0) { + $label = "$info[package] $info[version]"; + $this->ui->displayLine("$command ok: $label"); + } + } else { + return $this->raiseError("$command failed"); + } + } + } + + function doUninstall($command, $options, $params) + { + if (empty($this->installer)) { + $this->installer = &new PEAR_Installer($ui); + } + foreach ($params as $pkg) { + if ($this->installer->uninstall($pkg, $options)) { + if ($this->config->get('verbose') > 0) { + $this->ui->displayLine("uninstall ok"); + } + } else { + return $this->raiseError("uninstall failed"); + } } return true; } - // }}} } ?> \ No newline at end of file diff --git a/pear/PEAR/Command/Package.php b/pear/PEAR/Command/Package.php index 24c42a5c3fc..28f36da624e 100644 --- a/pear/PEAR/Command/Package.php +++ b/pear/PEAR/Command/Package.php @@ -37,32 +37,40 @@ class PEAR_Command_Package extends PEAR_Command_Common 'doc' => 'Print the name of the packaged file.', ), ), - 'doc' => 'Creates a PEAR package from its description file (usually -called package.xml). + 'doc' => '[descfile] +Creates a PEAR package from its description file (usually called +package.xml). ' ), 'package-info' => array( 'summary' => 'Display information about a package file', 'function' => 'doPackageInfo', + 'shortcut' => 'pi', 'options' => array(), - 'doc' => 'Extracts information from a package file and displays it. + 'doc' => ' +Extracts information from a package file and displays it. ', ), 'package-list' => array( 'summary' => 'List Files in Package', 'function' => 'doPackageList', + 'shortcut' => 'pl', 'options' => array(), - 'doc' => '', + 'doc' => ' +', ), 'package-validate' => array( 'summary' => 'Validate Package Consistency', 'function' => 'doPackageValidate', + 'shortcut' => 'pv', 'options' => array(), - 'doc' => '', + 'doc' => ' +', ), 'cvstag' => array( 'summary' => 'Set CVS Release Tag', 'function' => 'doCvsTag', + 'shortcut' => 'ct', 'options' => array( 'quiet' => array( 'shortopt' => 'q', @@ -74,20 +82,28 @@ called package.xml). ), 'slide' => array( 'shortopt' => 'F', - 'doc' => 'Move tag if it exists', + 'doc' => 'Move (slide) tag if it exists', ), 'delete' => array( 'shortopt' => 'd', - 'doc' => 'Remote tag', + 'doc' => 'Remove tag', ), ), - 'doc' => '', + 'doc' => ' +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. +', ), 'run-tests' => array( 'summary' => 'Run Regression Tests', 'function' => 'doRunTests', + 'shortcut' => 'rt', 'options' => array(), - 'doc' => '', + 'doc' => '[testfile|dir ...] +Run regression tests with PHP\'s regression testing script (run-tests.php).', ), ); diff --git a/pear/PEAR/Command/Registry.php b/pear/PEAR/Command/Registry.php index fa6114cecea..58f74cdfc10 100644 --- a/pear/PEAR/Command/Registry.php +++ b/pear/PEAR/Command/Registry.php @@ -26,18 +26,23 @@ require_once 'PEAR/Config.php'; class PEAR_Command_Registry extends PEAR_Command_Common { var $commands = array( - 'list-installed' => array( + 'list' => array( 'summary' => 'List Installed Packages', - 'function' => 'doListInstalled', + 'function' => 'doList', 'options' => array(), - 'doc' => 'List the PEAR packages installed in your php_dir ({config php_dir)). + 'doc' => '[package] +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir)). With a parameter, it +lists the files in that package. ', ), 'shell-test' => array( 'summary' => 'Shell Script Test', + 'shortcut' => 'stest', 'function' => 'doShellTest', 'options' => array(), - 'doc' => 'Tests if a package is installed in the system. Will exit(1) if it is not. + 'doc' => ' [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. The version comparison operator. One of: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne The version to compare with @@ -54,28 +59,84 @@ class PEAR_Command_Registry extends PEAR_Command_Common parent::PEAR_Command_Common($ui, $config); } - function doListInstalled($command, $options, $params) + function doList($command, $options, $params) { $reg = new PEAR_Registry($this->config->get('php_dir')); - $installed = $reg->packageInfo(); - $i = $j = 0; - $this->ui->startTable( - array('caption' => 'Installed packages:', - 'border' => true)); - foreach ($installed as $package) { - if ($i++ % 20 == 0) { - $this->ui->tableRow( - array('Package', 'Version', 'State'), - array('bold' => true)); + if (sizeof($params) == 0) { + $installed = $reg->packageInfo(); + $i = $j = 0; + $this->ui->startTable( + array('caption' => 'Installed packages:', + 'border' => true)); + foreach ($installed as $package) { + if ($i++ % 20 == 0) { + $this->ui->tableRow( + array('Package', 'Version', 'State'), + array('bold' => true)); + } + $this->ui->tableRow(array($package['package'], + $package['version'], + @$package['release_state'])); } - $this->ui->tableRow(array($package['package'], - $package['version'], - @$package['release_state'])); + if ($i == 0) { + $this->ui->tableRow(array('(no packages installed)')); + } + $this->ui->endTable(); + } else { + if (file_exists($params[0]) && !is_dir($params[0])) { + include_once "PEAR/Common.php"; + $obj = &new PEAR_Common; + $info = $obj->infoFromAny($params[0]); + $headings = array('Package File', 'Install Path'); + $installed = false; + } else { + $info = $reg->packageInfo($params[0]); + $headings = array('Type', 'Install Path'); + $installed = true; + } + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $list =$info['filelist']; + $caption = 'Contents of ' . basename($params[0]); + $this->ui->startTable(array('caption' => $caption, + 'border' => true)); + $this->ui->tableRow($headings, array('bold' => true)); + foreach ($list as $file => $att) { + if (isset($att['baseinstalldir'])) { + $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR . + $file; + } else { + $dest = $file; + } + switch ($att['role']) { + case 'test': + $dest = '-- will not be installed --'; break; + case 'doc': + $dest = $this->config->get('doc_dir') . DIRECTORY_SEPARATOR . + $dest; + break; + case 'php': + default: + $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR . + $dest; + } + $dest = preg_replace('!/+!', '/', $dest); + $file = preg_replace('!/+!', '/', $file); + $opts = array(0 => array('wrap' => 23), + 1 => array('wrap' => 45) + ); + if ($installed) { + $this->ui->tableRow(array($att['role'], $dest), null, $opts); + } else { + $this->ui->tableRow(array($file, $dest), null, $opts); + } + } + $this->ui->endTable(); + + } - if ($i == 0) { - $this->ui->tableRow(array('(no packages installed yet)')); - } - $this->ui->endTable(); return true; } diff --git a/pear/PEAR/Command/Remote.php b/pear/PEAR/Command/Remote.php index a0cd152ec5a..fb4fe201d1b 100644 --- a/pear/PEAR/Command/Remote.php +++ b/pear/PEAR/Command/Remote.php @@ -28,25 +28,42 @@ class PEAR_Command_Remote extends PEAR_Command_Common // {{{ command definitions var $commands = array( - 'remote-package-info' => array( + 'info-remote' => array( 'summary' => 'Information About Remote Packages', - 'function' => 'doRemotePackageInfo', + 'function' => 'doInfoRemote', 'options' => array(), + 'doc' => ' +Get details on a package from the server.', ), 'list-upgrades' => array( 'summary' => 'List Available Upgrades', 'function' => 'doListUpgrades', 'options' => array(), + 'doc' => ' +List releases on the server of packages you have installed where +a newer version is available with the same release state (stable etc.).' ), - 'list-remote-packages' => array( + 'list-remote' => array( 'summary' => 'List Remote Packages', - 'function' => 'doListRemotePackages', + 'function' => 'doListRemote', 'options' => array(), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', ), 'download' => array( 'summary' => 'Download Package', 'function' => 'doDownload', - 'options' => array(), + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'download an uncompressed (.tar) file', + ), + ), + 'doc' => '{package|package-version} +Download a package tarball. The file will be named as suggested by the +server, for example if you download the DB package and the latest stable +version of DB is 1.2, the downloaded file will be DB-1.2.tgz.', ), ); @@ -65,16 +82,17 @@ class PEAR_Command_Remote extends PEAR_Command_Common // }}} - // {{{ remote-package-info + // {{{ info-remote - function doRemotePackageInfo($command, $options, $params) + function doInfoRemote($command, $options, $params) { + return false; // coming soon } // }}} - // {{{ list-remote-packages + // {{{ list-remote - function doListRemotePackages($command, $options, $params) + function doListRemote($command, $options, $params) { $r = new PEAR_Remote($this->config); $available = $r->call('package.listAll', true); diff --git a/pear/scripts/pear.in b/pear/scripts/pear.in index 70a16084d71..6a374f1f30f 100644 --- a/pear/scripts/pear.in +++ b/pear/scripts/pear.in @@ -129,13 +129,15 @@ if (empty($command) && ($store_user_config || $store_system_config)) { if ($fetype == 'Gtk') { Gtk::main(); } else do { - if (empty($all_commands[$command]) || $command == 'help') { + if ($command == 'help') { usage(null, @$options[1][0]); } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); $cmd = PEAR_Command::factory($command, $config); + PEAR::popErrorHandling(); if (PEAR::isError($cmd)) { - die($cmd->getMessage()); + usage(null, @$options[1][0]); } $short_args = $long_args = null; @@ -175,7 +177,6 @@ function usage($error = null, $helpsubject = null) { global $progname, $all_commands; $stderr = fopen('php://stderr', 'w'); - fputs($stderr, "\n"); if (PEAR::isError($error)) { fputs($stderr, $error->getMessage() . "\n"); } elseif ($error !== null) { @@ -217,11 +218,18 @@ function cmdHelp($command) " -S store system configuration\n". " -u foo unset `foo' in the user configuration\n". " -h, -? display help/usage (this message)\n"; + } elseif ($command == "shortcuts") { + $sc = PEAR_Command::getShortcuts(); + $ret = "Shortcuts:\n"; + foreach ($sc as $s => $c) { + $ret .= sprintf(" %-8s %s\n", $s, $c); + } + return $ret; } elseif ($help = PEAR_Command::getHelp($command)) { if (is_string($help)) { - return "$help\n"; + return "pear $command [options] $help\n"; } - return "{$help[0]}\n{$help[1]}"; + return "pear $command [options] $help[0]\n$help[1]"; } return "No such command"; }