Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

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