home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / tmp / PEAR-1.7.1 / PEAR / Command / Remote.php < prev    next >
Encoding:
PHP Script  |  2008-02-15  |  31.0 KB  |  813 lines

  1. <?php
  2. /**
  3.  * PEAR_Command_Remote (remote-info, list-upgrades, remote-list, search, list-all, download,
  4.  * clear-cache commands)
  5.  *
  6.  * PHP versions 4 and 5
  7.  *
  8.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  9.  * that is available through the world-wide-web at the following URI:
  10.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  11.  * the PHP License and are unable to obtain it through the web, please
  12.  * send a note to license@php.net so we can mail you a copy immediately.
  13.  *
  14.  * @category   pear
  15.  * @package    PEAR
  16.  * @author     Stig Bakken <ssb@php.net>
  17.  * @author     Greg Beaver <cellog@php.net>
  18.  * @copyright  1997-2008 The PHP Group
  19.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  20.  * @version    CVS: $Id: Remote.php,v 1.106 2008/01/03 20:26:36 cellog Exp $
  21.  * @link       http://pear.php.net/package/PEAR
  22.  * @since      File available since Release 0.1
  23.  */
  24.  
  25. /**
  26.  * base class
  27.  */
  28. require_once 'PEAR/Command/Common.php';
  29. require_once 'PEAR/REST.php';
  30.  
  31. /**
  32.  * PEAR commands for remote server querying
  33.  *
  34.  * @category   pear
  35.  * @package    PEAR
  36.  * @author     Stig Bakken <ssb@php.net>
  37.  * @author     Greg Beaver <cellog@php.net>
  38.  * @copyright  1997-2008 The PHP Group
  39.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  40.  * @version    Release: 1.7.1
  41.  * @link       http://pear.php.net/package/PEAR
  42.  * @since      Class available since Release 0.1
  43.  */
  44. class PEAR_Command_Remote extends PEAR_Command_Common
  45. {
  46.     // {{{ command definitions
  47.  
  48.     var $commands = array(
  49.         'remote-info' => array(
  50.             'summary' => 'Information About Remote Packages',
  51.             'function' => 'doRemoteInfo',
  52.             'shortcut' => 'ri',
  53.             'options' => array(),
  54.             'doc' => '<package>
  55. Get details on a package from the server.',
  56.             ),
  57.         'list-upgrades' => array(
  58.             'summary' => 'List Available Upgrades',
  59.             'function' => 'doListUpgrades',
  60.             'shortcut' => 'lu',
  61.             'options' => array(
  62.                 'channelinfo' => array(
  63.                     'shortopt' => 'i',
  64.                     'doc' => 'output fully channel-aware data, even on failure',
  65.                     ),
  66.             ),
  67.             'doc' => '[preferred_state]
  68. List releases on the server of packages you have installed where
  69. a newer version is available with the same release state (stable etc.)
  70. or the state passed as the second parameter.'
  71.             ),
  72.         'remote-list' => array(
  73.             'summary' => 'List Remote Packages',
  74.             'function' => 'doRemoteList',
  75.             'shortcut' => 'rl',
  76.             'options' => array(
  77.                 'channel' =>
  78.                     array(
  79.                     'shortopt' => 'c',
  80.                     'doc' => 'specify a channel other than the default channel',
  81.                     'arg' => 'CHAN',
  82.                     )
  83.                 ),
  84.             'doc' => '
  85. Lists the packages available on the configured server along with the
  86. latest stable release of each package.',
  87.             ),
  88.         'search' => array(
  89.             'summary' => 'Search remote package database',
  90.             'function' => 'doSearch',
  91.             'shortcut' => 'sp',
  92.             'options' => array(
  93.                 'channel' =>
  94.                     array(
  95.                     'shortopt' => 'c',
  96.                     'doc' => 'specify a channel other than the default channel',
  97.                     'arg' => 'CHAN',
  98.                     ),
  99.                 'allchannels' => array(
  100.                     'shortopt' => 'a',
  101.                     'doc' => 'search packages from all known channels',
  102.                     ),
  103.                 'channelinfo' => array(
  104.                     'shortopt' => 'i',
  105.                     'doc' => 'output fully channel-aware data, even on failure',
  106.                     ),
  107.                 ),
  108.             'doc' => '[packagename] [packageinfo]
  109. Lists all packages which match the search parameters.  The first
  110. parameter is a fragment of a packagename.  The default channel
  111. will be used unless explicitly overridden.  The second parameter
  112. will be used to match any portion of the summary/description',
  113.             ),
  114.         'list-all' => array(
  115.             'summary' => 'List All Packages',
  116.             'function' => 'doListAll',
  117.             'shortcut' => 'la',
  118.             'options' => array(
  119.                 'channel' =>
  120.                     array(
  121.                     'shortopt' => 'c',
  122.                     'doc' => 'specify a channel other than the default channel',
  123.                     'arg' => 'CHAN',
  124.                     ),
  125.                 'channelinfo' => array(
  126.                     'shortopt' => 'i',
  127.                     'doc' => 'output fully channel-aware data, even on failure',
  128.                     ),
  129.                 ),
  130.             'doc' => '
  131. Lists the packages available on the configured server along with the
  132. latest stable release of each package.',
  133.             ),
  134.         'download' => array(
  135.             'summary' => 'Download Package',
  136.             'function' => 'doDownload',
  137.             'shortcut' => 'd',
  138.             'options' => array(
  139.                 'nocompress' => array(
  140.                     'shortopt' => 'Z',
  141.                     'doc' => 'download an uncompressed (.tar) file',
  142.                     ),
  143.                 ),
  144.             'doc' => '<package>...
  145. Download package tarballs.  The files will be named as suggested by the
  146. server, for example if you download the DB package and the latest stable
  147. version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.',
  148.             ),
  149.         'clear-cache' => array(
  150.             'summary' => 'Clear Web Services Cache',
  151.             'function' => 'doClearCache',
  152.             'shortcut' => 'cc',
  153.             'options' => array(),
  154.             'doc' => '
  155. Clear the XML-RPC/REST cache.  See also the cache_ttl configuration
  156. parameter.
  157. ',
  158.             ),
  159.         );
  160.  
  161.     // }}}
  162.     // {{{ constructor
  163.  
  164.     /**
  165.      * PEAR_Command_Remote constructor.
  166.      *
  167.      * @access public
  168.      */
  169.     function PEAR_Command_Remote(&$ui, &$config)
  170.     {
  171.         parent::PEAR_Command_Common($ui, $config);
  172.     }
  173.  
  174.     // }}}
  175.  
  176.     function _checkChannelForStatus($channel, $chan)
  177.     {
  178.         if (PEAR::isError($chan)) {
  179.             $this->raiseError($chan);
  180.         }
  181.         if (!is_a($chan, 'PEAR_ChannelFile')) {
  182.             return $this->raiseError('Internal corruption error: invalid channel "' .
  183.                 $channel . '"');
  184.         }
  185.         $rest = new PEAR_REST($this->config);
  186.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  187.         $mirror = $this->config->get('preferred_mirror', null,
  188.                                      $channel);
  189.         $a = $rest->downloadHttp('http://' . $channel .
  190.             '/channel.xml', $chan->lastModified());
  191.         PEAR::staticPopErrorHandling();
  192.         if (!PEAR::isError($a) && $a) {
  193.             $this->ui->outputData('WARNING: channel "' . $channel . '" has ' .
  194.                 'updated its protocols, use "channel-update ' . $channel .
  195.                 '" to update');
  196.         }
  197.     }
  198.  
  199.     // {{{ doRemoteInfo()
  200.  
  201.     function doRemoteInfo($command, $options, $params)
  202.     {
  203.         if (sizeof($params) != 1) {
  204.             return $this->raiseError("$command expects one param: the remote package name");
  205.         }
  206.         $savechannel = $channel = $this->config->get('default_channel');
  207.         $reg = &$this->config->getRegistry();
  208.         $package = $params[0];
  209.         $parsed = $reg->parsePackageName($package, $channel);
  210.         if (PEAR::isError($parsed)) {
  211.             return $this->raiseError('Invalid package name "' . $package . '"');
  212.         }
  213.         
  214.         $channel = $parsed['channel'];
  215.         $this->config->set('default_channel', $channel);
  216.         $chan = $reg->getChannel($channel);
  217.         if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  218.             return $e;
  219.         }
  220.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  221.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  222.             $rest = &$this->config->getREST('1.0', array());
  223.             $info = $rest->packageInfo($base, $parsed['package']);
  224.         } else {
  225.             $r = &$this->config->getRemote();
  226.             $info = $r->call('package.info', $parsed['package']);
  227.         }
  228.         if (PEAR::isError($info)) {
  229.             $this->config->set('default_channel', $savechannel);
  230.             return $this->raiseError($info);
  231.         }
  232.         if (!isset($info['name'])) {
  233.             return $this->raiseError('No remote package "' . $package . '" was found');
  234.         }
  235.  
  236.         $installed = $reg->packageInfo($info['name'], null, $channel);
  237.         $info['installed'] = $installed['version'] ? $installed['version'] : '- no -';
  238.         if (is_array($info['installed'])) {
  239.             $info['installed'] = $info['installed']['release'];
  240.         }
  241.  
  242.         $this->ui->outputData($info, $command);
  243.         $this->config->set('default_channel', $savechannel);
  244.  
  245.         return true;
  246.     }
  247.  
  248.     // }}}
  249.     // {{{ doRemoteList()
  250.  
  251.     function doRemoteList($command, $options, $params)
  252.     {
  253.         $savechannel = $channel = $this->config->get('default_channel');
  254.         $reg = &$this->config->getRegistry();
  255.         if (isset($options['channel'])) {
  256.             $channel = $options['channel'];
  257.             if ($reg->channelExists($channel)) {
  258.                 $this->config->set('default_channel', $channel);
  259.             } else {
  260.                 return $this->raiseError('Channel "' . $channel . '" does not exist');
  261.             }
  262.         }
  263.         $chan = $reg->getChannel($channel);
  264.         if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  265.             return $e;
  266.         }
  267.         $list_options = false;
  268.         if ($this->config->get('preferred_state') == 'stable') {
  269.             $list_options = true;
  270.         }
  271.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  272.               $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
  273.             // use faster list-all if available
  274.             $rest = &$this->config->getREST('1.1', array());
  275.             $available = $rest->listAll($base, $list_options);
  276.         } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  277.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  278.             $rest = &$this->config->getREST('1.0', array());
  279.             $available = $rest->listAll($base, $list_options);
  280.         } else {
  281.             $r = &$this->config->getRemote();
  282.             if ($channel == 'pear.php.net') {
  283.                 // hack because of poor pearweb design
  284.                 $available = $r->call('package.listAll', true, $list_options, false);
  285.             } else {
  286.                 $available = $r->call('package.listAll', true, $list_options);
  287.             }
  288.         }
  289.         if (PEAR::isError($available)) {
  290.             $this->config->set('default_channel', $savechannel);
  291.             return $this->raiseError($available);
  292.         }
  293.         $i = $j = 0;
  294.         $data = array(
  295.             'caption' => 'Channel ' . $channel . ' Available packages:',
  296.             'border' => true,
  297.             'headline' => array('Package', 'Version'),
  298.             'channel' => $channel
  299.             );
  300.         if (count($available)==0) {
  301.             $data = '(no packages available yet)';
  302.         } else {
  303.             foreach ($available as $name => $info) {
  304.                 $data['data'][] = array($name, (isset($info['stable']) && $info['stable'])
  305.                     ? $info['stable'] : '-n/a-');
  306.             }
  307.         }
  308.         $this->ui->outputData($data, $command);
  309.         $this->config->set('default_channel', $savechannel);
  310.         return true;
  311.     }
  312.  
  313.     // }}}
  314.     // {{{ doListAll()
  315.  
  316.     function doListAll($command, $options, $params)
  317.     {
  318.         $savechannel = $channel = $this->config->get('default_channel');
  319.         $reg = &$this->config->getRegistry();
  320.         if (isset($options['channel'])) {
  321.             $channel = $options['channel'];
  322.             if ($reg->channelExists($channel)) {
  323.                 $this->config->set('default_channel', $channel);
  324.             } else {
  325.                 return $this->raiseError("Channel \"$channel\" does not exist");
  326.             }
  327.         }
  328.         $list_options = false;
  329.         if ($this->config->get('preferred_state') == 'stable') {
  330.             $list_options = true;
  331.         }
  332.         $chan = $reg->getChannel($channel);
  333.         if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  334.             return $e;
  335.         }
  336.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  337.               $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
  338.             // use faster list-all if available
  339.             $rest = &$this->config->getREST('1.1', array());
  340.             $available = $rest->listAll($base, $list_options, false);
  341.         } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  342.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  343.             $rest = &$this->config->getREST('1.0', array());
  344.             $available = $rest->listAll($base, $list_options, false);
  345.         } else {
  346.             $r = &$this->config->getRemote();
  347.             if ($channel == 'pear.php.net') {
  348.                 // hack because of poor pearweb design
  349.                 $available = $r->call('package.listAll', true, $list_options, false);
  350.             } else {
  351.                 $available = $r->call('package.listAll', true, $list_options);
  352.             }
  353.         }
  354.         if (PEAR::isError($available)) {
  355.             $this->config->set('default_channel', $savechannel);
  356.             return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")');
  357.         }
  358.         $data = array(
  359.             'caption' => 'All packages [Channel ' . $channel . ']:',
  360.             'border' => true,
  361.             'headline' => array('Package', 'Latest', 'Local'),
  362.             'channel' => $channel,
  363.             );
  364.         if (isset($options['channelinfo'])) {
  365.             // add full channelinfo
  366.             $data['caption'] = 'Channel ' . $channel . ' All packages:';
  367.             $data['headline'] = array('Channel', 'Package', 'Latest', 'Local',
  368.                 'Description', 'Dependencies');
  369.         }
  370.         $local_pkgs = $reg->listPackages($channel);
  371.  
  372.         foreach ($available as $name => $info) {
  373.             $installed = $reg->packageInfo($name, null, $channel);
  374.             if (is_array($installed['version'])) {
  375.                 $installed['version'] = $installed['version']['release'];
  376.             }
  377.             $desc = $info['summary'];
  378.             if (isset($params[$name])) {
  379.                 $desc .= "\n\n".$info['description'];
  380.             }
  381.             if (isset($options['mode']))
  382.             {
  383.                 if ($options['mode'] == 'installed' && !isset($installed['version'])) {
  384.                     continue;
  385.                 }
  386.                 if ($options['mode'] == 'notinstalled' && isset($installed['version'])) {
  387.                     continue;
  388.                 }
  389.                 if ($options['mode'] == 'upgrades'
  390.                       && (!isset($installed['version']) || version_compare($installed['version'],
  391.                       $info['stable'], '>='))) {
  392.                     continue;
  393.                 }
  394.             }
  395.             $pos = array_search(strtolower($name), $local_pkgs);
  396.             if ($pos !== false) {
  397.                 unset($local_pkgs[$pos]);
  398.             }
  399.  
  400.             if (isset($info['stable']) && !$info['stable']) {
  401.                 $info['stable'] = null;
  402.             }
  403.  
  404.             if (isset($options['channelinfo'])) {
  405.                 // add full channelinfo
  406.                 if ($info['stable'] === $info['unstable']) {
  407.                     $state = $info['state'];
  408.                 } else {
  409.                     $state = 'stable';
  410.                 }
  411.                 $latest = $info['stable'].' ('.$state.')';
  412.                 $local = '';
  413.                 if (isset($installed['version'])) {
  414.                     $inst_state = $reg->packageInfo($name, 'release_state', $channel);
  415.                     $local = $installed['version'].' ('.$inst_state.')';
  416.                 }
  417.                 
  418.                 $packageinfo = array(
  419.                     $channel,
  420.                     $name,
  421.                     $latest,
  422.                     $local,
  423.                     isset($desc) ? $desc : null,
  424.                     isset($info['deps']) ? $info['deps'] : null,
  425.                 );
  426.             } else {
  427.                 $packageinfo = array(
  428.                     $reg->channelAlias($channel) . '/' . $name,
  429.                     isset($info['stable']) ? $info['stable'] : null,
  430.                     isset($installed['version']) ? $installed['version'] : null,
  431.                     isset($desc) ? $desc : null,
  432.                     isset($info['deps']) ? $info['deps'] : null,
  433.                 );
  434.             }
  435.             $data['data'][$info['category']][] = $packageinfo;
  436.         }
  437.  
  438.         if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) {
  439.             $this->config->set('default_channel', $savechannel);
  440.             $this->ui->outputData($data, $command);
  441.             return true;
  442.         }
  443.         foreach ($local_pkgs as $name) {
  444.             $info = &$reg->getPackage($name, $channel);
  445.             $data['data']['Local'][] = array(
  446.                 $reg->channelAlias($channel) . '/' . $info->getPackage(),
  447.                 '',
  448.                 $info->getVersion(),
  449.                 $info->getSummary(),
  450.                 $info->getDeps()
  451.                 );
  452.         }
  453.  
  454.         $this->config->set('default_channel', $savechannel);
  455.         $this->ui->outputData($data, $command);
  456.         return true;
  457.     }
  458.  
  459.     // }}}
  460.     // {{{ doSearch()
  461.  
  462.     function doSearch($command, $options, $params)
  463.     {
  464.         if ((!isset($params[0]) || empty($params[0]))
  465.             && (!isset($params[1]) || empty($params[1])))
  466.         {
  467.             return $this->raiseError('no valid search string supplied');
  468.         };
  469.  
  470.         $channelinfo = isset($options['channelinfo']);
  471.         $reg = &$this->config->getRegistry();
  472.         if (isset($options['allchannels'])) {
  473.             // search all channels
  474.             unset($options['allchannels']);
  475.             $channels = $reg->getChannels();
  476.             $errors = array();
  477.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  478.             foreach ($channels as $channel) {
  479.                 if ($channel->getName() != '__uri') {
  480.                     $options['channel'] = $channel->getName();
  481.                     $ret = $this->doSearch($command, $options, $params);
  482.                     if (PEAR::isError($ret)) {
  483.                         $errors[] = $ret;
  484.                     }
  485.                 }
  486.             }
  487.             PEAR::staticPopErrorHandling();
  488.             if (count($errors) !== 0) {
  489.                 // for now, only give first error
  490.                 return PEAR::raiseError($errors[0]);
  491.             }
  492.  
  493.             return true;
  494.         }
  495.  
  496.         $savechannel = $channel = $this->config->get('default_channel');
  497.         $package = $params[0];
  498.         $summary = isset($params[1]) ? $params[1] : false;
  499.         if (isset($options['channel'])) {
  500.             $reg = &$this->config->getRegistry();
  501.             $channel = $options['channel'];
  502.             if ($reg->channelExists($channel)) {
  503.                 $this->config->set('default_channel', $channel);
  504.             } else {
  505.                 return $this->raiseError('Channel "' . $channel . '" does not exist');
  506.             }
  507.         }
  508.         $chan = $reg->getChannel($channel);
  509.         if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  510.             return $e;
  511.         }
  512.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  513.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  514.             $rest = &$this->config->getREST('1.0', array());
  515.             $available = $rest->listAll($base, false, false, $package, $summary);
  516.         } else {
  517.             $r = &$this->config->getRemote();
  518.             $available = $r->call('package.search', $package, $summary, true, 
  519.                 $this->config->get('preferred_state') == 'stable', true);
  520.         }
  521.         if (PEAR::isError($available)) {
  522.             $this->config->set('default_channel', $savechannel);
  523.             return $this->raiseError($available);
  524.         }
  525.         if (!$available && !$channelinfo) {
  526.             // clean exit when not found, no error !
  527.             $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.';
  528.             $this->ui->outputData($data);
  529.             $this->config->set('default_channel', $channel);
  530.             return true;
  531.         }
  532.         if ($channelinfo) {
  533.             $data = array(
  534.                 'caption' => 'Matched packages, channel ' . $channel . ':',
  535.                 'border' => true,
  536.                 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'),
  537.                 'channel' => $channel
  538.                 );
  539.         } else {
  540.             $data = array(
  541.                 'caption' => 'Matched packages, channel ' . $channel . ':',
  542.                 'border' => true,
  543.                 'headline' => array('Package', 'Stable/(Latest)', 'Local'),
  544.                 'channel' => $channel
  545.                 );
  546.         }
  547.  
  548.         if (!$available && $channelinfo) {
  549.             unset($data['headline']);
  550.             $data['data'] = 'No packages found that match pattern "' . $package . '".';
  551.             $available = array();
  552.         }
  553.         foreach ($available as $name => $info) {
  554.             $installed = $reg->packageInfo($name, null, $channel);
  555.             $desc = $info['summary'];
  556.             if (isset($params[$name]))
  557.                 $desc .= "\n\n".$info['description'];
  558.  
  559.             if (!isset($info['stable']) || !$info['stable']) {
  560.                 $version_remote = 'none';
  561.             } else {
  562.                 if ($info['unstable']) {
  563.                     $version_remote = $info['unstable'];
  564.                 } else {
  565.                     $version_remote = $info['stable'];
  566.                 }
  567.                 $version_remote .= ' ('.$info['state'].')';
  568.             }
  569.             $version = is_array($installed['version']) ? $installed['version']['release'] :
  570.                 $installed['version'];
  571.             if ($channelinfo) {
  572.                 $packageinfo = array(
  573.                     $channel,
  574.                     $name,
  575.                     $version_remote,
  576.                     $version,
  577.                     $desc,
  578.                 );
  579.             } else {
  580.                 $packageinfo = array(
  581.                     $name,
  582.                     $version_remote,
  583.                     $version,
  584.                     $desc,
  585.                 );
  586.             }
  587.             $data['data'][$info['category']][] = $packageinfo;
  588.         }
  589.         $this->ui->outputData($data, $command);
  590.         $this->config->set('default_channel', $channel);
  591.         return true;
  592.     }
  593.  
  594.     // }}}
  595.     function &getDownloader($options)
  596.     {
  597.         if (!class_exists('PEAR_Downloader')) {
  598.             require_once 'PEAR/Downloader.php';
  599.         }
  600.         $a = &new PEAR_Downloader($this->ui, $options, $this->config);
  601.         return $a;
  602.     }
  603.     // {{{ doDownload()
  604.  
  605.     function doDownload($command, $options, $params)
  606.     {
  607.         // make certain that dependencies are ignored
  608.         $options['downloadonly'] = 1;
  609.  
  610.         // eliminate error messages for preferred_state-related errors
  611.         /* TODO: Should be an option, but until now download does respect
  612.            prefered state */
  613.         /* $options['ignorepreferred_state'] = 1; */
  614.         // eliminate error messages for preferred_state-related errors
  615.  
  616.         $downloader = &$this->getDownloader($options);
  617.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  618.         $e = $downloader->setDownloadDir(getcwd());
  619.         PEAR::staticPopErrorHandling();
  620.         if (PEAR::isError($e)) {
  621.             return $this->raiseError('Current directory is not writeable, cannot download');
  622.         }
  623.         $errors = array();
  624.         $downloaded = array();
  625.         $err = $downloader->download($params);
  626.         if (PEAR::isError($err)) {
  627.             return $err;
  628.         }
  629.         $errors = $downloader->getErrorMsgs();
  630.         if (count($errors)) {
  631.             foreach ($errors as $error) {
  632.                 $this->ui->outputData($error);
  633.             }
  634.             return $this->raiseError("$command failed");
  635.         }
  636.         $downloaded = $downloader->getDownloadedPackages();
  637.         foreach ($downloaded as $pkg) {
  638.             $this->ui->outputData("File $pkg[file] downloaded", $command);
  639.         }
  640.         return true;
  641.     }
  642.  
  643.     function downloadCallback($msg, $params = null)
  644.     {
  645.         if ($msg == 'done') {
  646.             $this->bytes_downloaded = $params;
  647.         }
  648.     }
  649.  
  650.     // }}}
  651.     // {{{ doListUpgrades()
  652.  
  653.     function doListUpgrades($command, $options, $params)
  654.     {
  655.         require_once 'PEAR/Common.php';
  656.         if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) {
  657.             return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"');
  658.         }
  659.         $savechannel = $channel = $this->config->get('default_channel');
  660.         $reg = &$this->config->getRegistry();
  661.         foreach ($reg->listChannels() as $channel) {
  662.             $inst = array_flip($reg->listPackages($channel));
  663.             if (!count($inst)) {
  664.                 continue;
  665.             }
  666.             if ($channel == '__uri') {
  667.                 continue;
  668.             }
  669.             $this->config->set('default_channel', $channel);
  670.             if (empty($params[0])) {
  671.                 $state = $this->config->get('preferred_state');
  672.             } else {
  673.                 $state = $params[0];
  674.             }
  675.             $caption = $channel . ' Available Upgrades';
  676.             $chan = $reg->getChannel($channel);
  677.             if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  678.                 return $e;
  679.             }
  680.             if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  681.                   $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  682.                 $rest = &$this->config->getREST('1.0', array());
  683.                 if (empty($state) || $state == 'any') {
  684.                     $state = false;
  685.                 } else {
  686.                     $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
  687.                 }
  688.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  689.                 $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg);
  690.                 PEAR::staticPopErrorHandling();
  691.             } else {
  692.                 $remote = &$this->config->getRemote();
  693.                 $remote->pushErrorHandling(PEAR_ERROR_RETURN);
  694.                 if (empty($state) || $state == 'any') {
  695.                     $latest = $remote->call("package.listLatestReleases");
  696.                 } else {
  697.                     $latest = $remote->call("package.listLatestReleases", $state);
  698.                     $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
  699.                 }
  700.                 $remote->popErrorHandling();
  701.             }
  702.             if (PEAR::isError($latest)) {
  703.                 $this->ui->outputData($latest->getMessage());
  704.                 continue;
  705.             }
  706.             $caption .= ':';
  707.             if (PEAR::isError($latest)) {
  708.                 $this->config->set('default_channel', $savechannel);
  709.                 return $latest;
  710.             }
  711.             $data = array(
  712.                 'caption' => $caption,
  713.                 'border' => 1,
  714.                 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'),
  715.                 'channel' => $channel
  716.                 );
  717.             foreach ((array)$latest as $pkg => $info) {
  718.                 $package = strtolower($pkg);
  719.                 if (!isset($inst[$package])) {
  720.                     // skip packages we don't have installed
  721.                     continue;
  722.                 }
  723.                 extract($info);
  724.                 $inst_version = $reg->packageInfo($package, 'version', $channel);
  725.                 $inst_state   = $reg->packageInfo($package, 'release_state', $channel);
  726.                 if (version_compare("$version", "$inst_version", "le")) {
  727.                     // installed version is up-to-date
  728.                     continue;
  729.                 }
  730.                 if ($filesize >= 20480) {
  731.                     $filesize += 1024 - ($filesize % 1024);
  732.                     $fs = sprintf("%dkB", $filesize / 1024);
  733.                 } elseif ($filesize > 0) {
  734.                     $filesize += 103 - ($filesize % 103);
  735.                     $fs = sprintf("%.1fkB", $filesize / 1024.0);
  736.                 } else {
  737.                     $fs = "  -"; // XXX center instead
  738.                 }
  739.                 $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs);
  740.             }
  741.             if (isset($options['channelinfo'])) {
  742.                 if (empty($data['data'])) {
  743.                     unset($data['headline']);
  744.                     if (count($inst) == 0) {
  745.                         $data['data'] = '(no packages installed)';
  746.                     } else {
  747.                         $data['data'] = '(no upgrades available)';
  748.                     }
  749.                 }
  750.                 $this->ui->outputData($data, $command);
  751.             } else {
  752.                 if (empty($data['data'])) {
  753.                     $this->ui->outputData('Channel ' . $channel . ': No upgrades available');
  754.                 } else {
  755.                     $this->ui->outputData($data, $command);
  756.                 }
  757.             }
  758.         }
  759.         $this->config->set('default_channel', $savechannel);
  760.         return true;
  761.     }
  762.  
  763.     // }}}
  764.     // {{{ doClearCache()
  765.  
  766.     function doClearCache($command, $options, $params)
  767.     {
  768.         $cache_dir = $this->config->get('cache_dir');
  769.         $verbose = $this->config->get('verbose');
  770.         $output = '';
  771.         if (!file_exists($cache_dir) || !is_dir($cache_dir)) {
  772.             return $this->raiseError("$cache_dir does not exist or is not a directory");
  773.         }
  774.         if (!($dp = @opendir($cache_dir))) {
  775.             return $this->raiseError("opendir($cache_dir) failed: $php_errormsg");
  776.         }
  777.         if ($verbose >= 1) {
  778.             $output .= "reading directory $cache_dir\n";
  779.         }
  780.         $num = 0;
  781.         while ($ent = readdir($dp)) {
  782.             if (preg_match('/^xmlrpc_cache_[a-z0-9]{32}\\z/', $ent) ||
  783.                   preg_match('/rest.cache(file|id)\\z/', $ent)) {
  784.                 $path = $cache_dir . DIRECTORY_SEPARATOR . $ent;
  785.                 if (file_exists($path)) {
  786.                     $ok = @unlink($path);
  787.                 } else {
  788.                     $ok = false;
  789.                     $php_errormsg = '';
  790.                 }
  791.                 if ($ok) {
  792.                     if ($verbose >= 2) {
  793.                         $output .= "deleted $path\n";
  794.                     }
  795.                     $num++;
  796.                 } elseif ($verbose >= 1) {
  797.                     $output .= "failed to delete $path $php_errormsg\n";
  798.                 }
  799.             }
  800.         }
  801.         closedir($dp);
  802.         if ($verbose >= 1) {
  803.             $output .= "$num cache entries cleared\n";
  804.         }
  805.         $this->ui->outputData(rtrim($output), $command);
  806.         return $num;
  807.     }
  808.  
  809.     // }}}
  810. }
  811.  
  812. ?>
  813.