Хранилища Subversion ant

Редакция

Редакция 69 | Содержимое файла | Сравнить с предыдущей | Последнее изменение | Открыть журнал | RSS

Редакция Автор № строки Строка
69 alex-w 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.107 2008/04/11 01:16:40 dufuz 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.2
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'], $channel);
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, true, false, false, $chan->getName());
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, true, false, false, $chan->getName());
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, false, false, $chan->getName());
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, false, false, $chan->getName());
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, $chan->getName());
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
?>