Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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