Хранилища Subversion ant

Редакция

К новейшей редакции | Содержимое файла | Последнее изменение | Открыть журнал | RSS

Редакция Автор № строки Строка
69 alex-w 1
<?php
2
/**
3
 * PEAR_REST_10
4
 *
5
 * PHP versions 4 and 5
6
 *
7
 * LICENSE: This source file is subject to version 3.0 of the PHP license
8
 * that is available through the world-wide-web at the following URI:
9
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
10
 * the PHP License and are unable to obtain it through the web, please
11
 * send a note to license@php.net so we can mail you a copy immediately.
12
 *
13
 * @category   pear
14
 * @package    PEAR
15
 * @author     Greg Beaver <cellog@php.net>
16
 * @copyright  1997-2008 The PHP Group
17
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
18
 * @version    CVS: $Id: 10.php,v 1.53 2008/04/11 01:16:40 dufuz Exp $
19
 * @link       http://pear.php.net/package/PEAR
20
 * @since      File available since Release 1.4.0a12
21
 */
22
 
23
/**
24
 * For downloading REST xml/txt files
25
 */
26
require_once 'PEAR/REST.php';
27
 
28
/**
29
 * Implement REST 1.0
30
 *
31
 * @category   pear
32
 * @package    PEAR
33
 * @author     Greg Beaver <cellog@php.net>
34
 * @copyright  1997-2008 The PHP Group
35
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
36
 * @version    Release: 1.7.2
37
 * @link       http://pear.php.net/package/PEAR
38
 * @since      Class available since Release 1.4.0a12
39
 */
40
class PEAR_REST_10
41
{
42
    /**
43
     * @var PEAR_REST
44
     */
45
    var $_rest;
46
    function PEAR_REST_10($config, $options = array())
47
    {
48
        $this->_rest = &new PEAR_REST($config, $options);
49
    }
50
 
51
    /**
52
     * Retrieve information about a remote package to be downloaded from a REST server
53
     *
54
     * @param string $base The uri to prepend to all REST calls
55
     * @param array $packageinfo an array of format:
56
     * <pre>
57
     *  array(
58
     *   'package' => 'packagename',
59
     *   'channel' => 'channelname',
60
     *  ['state' => 'alpha' (or valid state),]
61
     *  -or-
62
     *  ['version' => '1.whatever']
63
     * </pre>
64
     * @param string $prefstate Current preferred_state config variable value
65
     * @param bool $installed the installed version of this package to compare against
66
     * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
67
     */
68
    function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
69
    {
70
        $channel = $packageinfo['channel'];
71
        $package = $packageinfo['package'];
72
        $states = $this->betterStates($prefstate, true);
73
        if (!$states) {
74
            return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
75
        }
76
        $state   = isset($packageinfo['state'])   ? $packageinfo['state']   : null;
77
        $version = isset($packageinfo['version']) ? $packageinfo['version'] : null;
78
        $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel);
79
        if (PEAR::isError($info)) {
80
            return PEAR::raiseError('No releases available for package "' .
81
                $channel . '/' . $package . '"');
82
        }
83
        if (!isset($info['r'])) {
84
            return false;
85
        }
86
        $release = $found = false;
87
        if (!is_array($info['r']) || !isset($info['r'][0])) {
88
            $info['r'] = array($info['r']);
89
        }
90
        foreach ($info['r'] as $release) {
91
            if (!isset($this->_rest->_options['force']) && ($installed &&
92
                  version_compare($release['v'], $installed, '<'))) {
93
                continue;
94
            }
95
            if (isset($state)) {
96
                // try our preferred state first
97
                if ($release['s'] == $state) {
98
                    $found = true;
99
                    break;
100
                }
101
                // see if there is something newer and more stable
102
                // bug #7221
103
                if (in_array($release['s'], $this->betterStates($state), true)) {
104
                    $found = true;
105
                    break;
106
                }
107
            } elseif (isset($version)) {
108
                if ($release['v'] == $version) {
109
                    $found = true;
110
                    break;
111
                }
112
            } else {
113
                if (in_array($release['s'], $states)) {
114
                    $found = true;
115
                    break;
116
                }
117
            }
118
        }
119
        return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
120
    }
121
 
122
    function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
123
                               $prefstate = 'stable', $installed = false, $channel = false)
124
    {
125
        $channel = $dependency['channel'];
126
        $package = $dependency['name'];
127
        $states = $this->betterStates($prefstate, true);
128
        if (!$states) {
129
            return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
130
        }
131
        $state   = isset($dependency['state'])   ? $dependency['state']   : null;
132
        $version = isset($dependency['version']) ? $dependency['version'] : null;
133
        $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel);
134
        if (PEAR::isError($info)) {
135
            return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
136
                . '" dependency "' . $channel . '/' . $package . '" has no releases');
137
        }
138
        if (!is_array($info) || !isset($info['r'])) {
139
            return false;
140
        }
141
        $exclude = array();
142
        $min = $max = $recommended = false;
143
        if ($xsdversion == '1.0') {
144
            switch ($dependency['rel']) {
145
                case 'ge' :
146
                    $min = $dependency['version'];
147
                break;
148
                case 'gt' :
149
                    $min = $dependency['version'];
150
                    $exclude = array($dependency['version']);
151
                break;
152
                case 'eq' :
153
                    $recommended = $dependency['version'];
154
                break;
155
                case 'lt' :
156
                    $max = $dependency['version'];
157
                    $exclude = array($dependency['version']);
158
                break;
159
                case 'le' :
160
                    $max = $dependency['version'];
161
                break;
162
                case 'ne' :
163
                    $exclude = array($dependency['version']);
164
                break;
165
            }
166
        } else {
167
            $min = isset($dependency['min']) ? $dependency['min'] : false;
168
            $max = isset($dependency['max']) ? $dependency['max'] : false;
169
            $recommended = isset($dependency['recommended']) ?
170
                $dependency['recommended'] : false;
171
            if (isset($dependency['exclude'])) {
172
                if (!isset($dependency['exclude'][0])) {
173
                    $exclude = array($dependency['exclude']);
174
                }
175
            }
176
        }
177
        $release = $found = false;
178
        if (!is_array($info['r']) || !isset($info['r'][0])) {
179
            $info['r'] = array($info['r']);
180
        }
181
        foreach ($info['r'] as $release) {
182
            if (!isset($this->_rest->_options['force']) && ($installed &&
183
                  version_compare($release['v'], $installed, '<'))) {
184
                continue;
185
            }
186
            if (in_array($release['v'], $exclude)) { // skip excluded versions
187
                continue;
188
            }
189
            // allow newer releases to say "I'm OK with the dependent package"
190
            if ($xsdversion == '2.0' && isset($release['co'])) {
191
                if (!is_array($release['co']) || !isset($release['co'][0])) {
192
                    $release['co'] = array($release['co']);
193
                }
194
                foreach ($release['co'] as $entry) {
195
                    if (isset($entry['x']) && !is_array($entry['x'])) {
196
                        $entry['x'] = array($entry['x']);
197
                    } elseif (!isset($entry['x'])) {
198
                        $entry['x'] = array();
199
                    }
200
                    if ($entry['c'] == $deppackage['channel'] &&
201
                          strtolower($entry['p']) == strtolower($deppackage['package']) &&
202
                          version_compare($deppackage['version'], $entry['min'], '>=') &&
203
                          version_compare($deppackage['version'], $entry['max'], '<=') &&
204
                          !in_array($release['v'], $entry['x'])) {
205
                        $recommended = $release['v'];
206
                        break;
207
                    }
208
                }
209
            }
210
            if ($recommended) {
211
                if ($release['v'] != $recommended) { // if we want a specific
212
                    // version, then skip all others
213
                    continue;
214
                } else {
215
                    if (!in_array($release['s'], $states)) {
216
                        // the stability is too low, but we must return the
217
                        // recommended version if possible
218
                        return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
219
                    }
220
                }
221
            }
222
            if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
223
                continue;
224
            }
225
            if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
226
                continue;
227
            }
228
            if ($installed && version_compare($release['v'], $installed, '<')) {
229
                continue;
230
            }
231
            if (in_array($release['s'], $states)) { // if in the preferred state...
232
                $found = true; // ... then use it
233
                break;
234
            }
235
        }
236
        return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
237
    }
238
 
239
    /**
240
     * Take raw data and return the array needed for processing a download URL
241
     *
242
     * @param string $base REST base uri
243
     * @param string $package Package name
244
     * @param array $release an array of format array('v' => version, 's' => state)
245
     *                       describing the release to download
246
     * @param array $info list of all releases as defined by allreleases.xml
247
     * @param bool|null $found determines whether the release was found or this is the next
248
     *                    best alternative.  If null, then versions were skipped because
249
     *                    of PHP dependency
250
     * @return array|PEAR_Error
251
     * @access private
252
     */
253
    function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false)
254
    {
255
        if (!$found) {
256
            $release = $info['r'][0];
257
        }
258
        $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . strtolower($package) . '/' .
259
            'info.xml', false, false, $channel);
260
        if (PEAR::isError($pinfo)) {
261
            return PEAR::raiseError('Package "' . $package .
262
                '" does not have REST info xml available');
263
        }
264
        $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
265
            $release['v'] . '.xml', false, false, $channel);
266
        if (PEAR::isError($releaseinfo)) {
267
            return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
268
                '" does not have REST xml available');
269
        }
270
        $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
271
            'deps.' . $release['v'] . '.txt', false, true, $channel);
272
        if (PEAR::isError($packagexml)) {
273
            return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
274
                '" does not have REST dependency information available');
275
        }
276
        $packagexml = unserialize($packagexml);
277
        if (!$packagexml) {
278
            $packagexml = array();
279
        }
280
        $allinfo = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
281
            '/allreleases.xml', false, false, $channel);
282
        if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) {
283
            $allinfo['r'] = array($allinfo['r']);
284
        }
285
        $compatible = false;
286
        foreach ($allinfo['r'] as $release) {
287
            if ($release['v'] != $releaseinfo['v']) {
288
                continue;
289
            }
290
            if (!isset($release['co'])) {
291
                break;
292
            }
293
            $compatible = array();
294
            if (!is_array($release['co']) || !isset($release['co'][0])) {
295
                $release['co'] = array($release['co']);
296
            }
297
            foreach ($release['co'] as $entry) {
298
                $comp = array();
299
                $comp['name'] = $entry['p'];
300
                $comp['channel'] = $entry['c'];
301
                $comp['min'] = $entry['min'];
302
                $comp['max'] = $entry['max'];
303
                if (isset($entry['x']) && !is_array($entry['x'])) {
304
                    $comp['exclude'] = $entry['x'];
305
                }
306
                $compatible[] = $comp;
307
            }
308
            if (count($compatible) == 1) {
309
                $compatible = $compatible[0];
310
            }
311
            break;
312
        }
313
        if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
314
            if (is_array($pinfo['dp'])) {
315
                $deprecated = array('channel' => (string) $pinfo['dc'],
316
                                    'package' => trim($pinfo['dp']['_content']));
317
            } else {
318
                $deprecated = array('channel' => (string) $pinfo['dc'],
319
                                    'package' => trim($pinfo['dp']));
320
            }
321
        } else {
322
            $deprecated = false;
323
        }
324
        if ($found) {
325
            return
326
                array('version' => $releaseinfo['v'],
327
                      'info' => $packagexml,
328
                      'package' => $releaseinfo['p']['_content'],
329
                      'stability' => $releaseinfo['st'],
330
                      'url' => $releaseinfo['g'],
331
                      'compatible' => $compatible,
332
                      'deprecated' => $deprecated,
333
                );
334
        } else {
335
            return
336
                array('version' => $releaseinfo['v'],
337
                      'package' => $releaseinfo['p']['_content'],
338
                      'stability' => $releaseinfo['st'],
339
                      'info' => $packagexml,
340
                      'compatible' => $compatible,
341
                      'deprecated' => $deprecated,
342
                      'php' => $phpversion
343
                );
344
        }
345
    }
346
 
347
    function listPackages($base, $channel = false)
348
    {
349
        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
350
        if (PEAR::isError($packagelist)) {
351
            return $packagelist;
352
        }
353
        if (!is_array($packagelist) || !isset($packagelist['p'])) {
354
            return array();
355
        }
356
        if (!is_array($packagelist['p'])) {
357
            $packagelist['p'] = array($packagelist['p']);
358
        }
359
        return $packagelist['p'];
360
    }
361
 
362
    /**
363
     * List all categories of a REST server
364
     *
365
     * @param string $base base URL of the server
366
     * @return array of categorynames
367
     */
368
    function listCategories($base, $channel = false)
369
    {
370
        $categories = array();
371
 
372
        // c/categories.xml does not exist;
373
        // check for every package its category manually
374
        // This is SLOOOWWWW : ///
375
        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
376
        if (PEAR::isError($packagelist)) {
377
            return $packagelist;
378
        }
379
        if (!is_array($packagelist) || !isset($packagelist['p'])) {
380
            $ret = array();
381
            return $ret;
382
        }
383
        if (!is_array($packagelist['p'])) {
384
            $packagelist['p'] = array($packagelist['p']);
385
        }
386
 
387
        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
388
        foreach ($packagelist['p'] as $package) {
389
                $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
390
                if (PEAR::isError($inf)) {
391
                    PEAR::popErrorHandling();
392
                    return $inf;
393
                }
394
                $cat = $inf['ca']['_content'];
395
                if (!isset($categories[$cat])) {
396
                    $categories[$cat] = $inf['ca'];
397
                }
398
        }
399
        return array_values($categories);
400
    }
401
 
402
    /**
403
     * List a category of a REST server
404
     *
405
     * @param string $base base URL of the server
406
     * @param string $category name of the category
407
     * @param boolean $info also download full package info
408
     * @return array of packagenames
409
     */
410
    function listCategory($base, $category, $info = false, $channel = false)
411
    {
412
        // gives '404 Not Found' error when category doesn't exist
413
        $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel);
414
        if (PEAR::isError($packagelist)) {
415
            return $packagelist;
416
        }
417
        if (!is_array($packagelist) || !isset($packagelist['p'])) {
418
            return array();
419
        }
420
        if (!is_array($packagelist['p']) ||
421
            !isset($packagelist['p'][0])) { // only 1 pkg
422
            $packagelist = array($packagelist['p']);
423
        } else {
424
            $packagelist = $packagelist['p'];
425
        }
426
 
427
        if ($info == true) {
428
            // get individual package info
429
            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
430
            foreach ($packagelist as $i => $packageitem) {
431
                $url = sprintf('%s'.'r/%s/latest.txt',
432
                        $base,
433
                        strtolower($packageitem['_content']));
434
                $version = $this->_rest->retrieveData($url, false, false, $channel);
435
                if (PEAR::isError($version)) {
436
                    break; // skipit
437
                }
438
                $url = sprintf('%s'.'r/%s/%s.xml',
439
                        $base,
440
                        strtolower($packageitem['_content']),
441
                        $version);
442
                $info = $this->_rest->retrieveData($url, false, false, $channel);
443
                if (PEAR::isError($info)) {
444
                    break; // skipit
445
                }
446
                $packagelist[$i]['info'] = $info;
447
            }
448
            PEAR::popErrorHandling();
449
        }
450
 
451
        return $packagelist;
452
    }
453
 
454
 
455
    function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
456
    {
457
        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
458
        if (PEAR::isError($packagelist)) {
459
            return $packagelist;
460
        }
461
        if ($this->_rest->config->get('verbose') > 0) {
462
            $ui = &PEAR_Frontend::singleton();
463
            $ui->log('Retrieving data...0%', false);
464
        }
465
        $ret = array();
466
        if (!is_array($packagelist) || !isset($packagelist['p'])) {
467
            return $ret;
468
        }
469
        if (!is_array($packagelist['p'])) {
470
            $packagelist['p'] = array($packagelist['p']);
471
        }
472
 
473
        // only search-packagename = quicksearch !
474
        if ($searchpackage && (!$searchsummary || empty($searchpackage))) {
475
            $newpackagelist = array();
476
            foreach ($packagelist['p'] as $package) {
477
                if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) {
478
                    $newpackagelist[] = $package;
479
                }
480
            }
481
            $packagelist['p'] = $newpackagelist;
482
        }
483
        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
484
        $next = .1;
485
        foreach ($packagelist['p'] as $progress => $package) {
486
            if ($this->_rest->config->get('verbose') > 0) {
487
                if ($progress / count($packagelist['p']) >= $next) {
488
                    if ($next == .5) {
489
                        $ui->log('50%', false);
490
                    } else {
491
                        $ui->log('.', false);
492
                    }
493
                    $next += .1;
494
                }
495
            }
496
            if ($basic) { // remote-list command
497
                if ($dostable) {
498
                    $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
499
                        '/stable.txt', false, false, $channel);
500
                } else {
501
                    $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
502
                        '/latest.txt', false, false, $channel);
503
                }
504
                if (PEAR::isError($latest)) {
505
                    $latest = false;
506
                }
507
                $info = array('stable' => $latest);
508
            } else { // list-all command
509
                $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
510
                if (PEAR::isError($inf)) {
511
                    PEAR::popErrorHandling();
512
                    return $inf;
513
                }
514
                if ($searchpackage) {
515
                    $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false);
516
                    if (!$found && !(isset($searchsummary) && !empty($searchsummary)
517
                        && (stristr($inf['s'], $searchsummary) !== false
518
                            || stristr($inf['d'], $searchsummary) !== false)))
519
                    {
520
                        continue;
521
                    };
522
                }
523
                $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
524
                    '/allreleases.xml', false, false, $channel);
525
                if (PEAR::isError($releases)) {
526
                    continue;
527
                }
528
                if (!isset($releases['r'][0])) {
529
                    $releases['r'] = array($releases['r']);
530
                }
531
                unset($latest);
532
                unset($unstable);
533
                unset($stable);
534
                unset($state);
535
                foreach ($releases['r'] as $release) {
536
                    if (!isset($latest)) {
537
                        if ($dostable && $release['s'] == 'stable') {
538
                            $latest = $release['v'];
539
                            $state = 'stable';
540
                        }
541
                        if (!$dostable) {
542
                            $latest = $release['v'];
543
                            $state = $release['s'];
544
                        }
545
                    }
546
                    if (!isset($stable) && $release['s'] == 'stable') {
547
                        $stable = $release['v'];
548
                        if (!isset($unstable)) {
549
                            $unstable = $stable;
550
                        }
551
                    }
552
                    if (!isset($unstable) && $release['s'] != 'stable') {
553
                        $latest = $unstable = $release['v'];
554
                        $state = $release['s'];
555
                    }
556
                    if (isset($latest) && !isset($state)) {
557
                        $state = $release['s'];
558
                    }
559
                    if (isset($latest) && isset($stable) && isset($unstable)) {
560
                        break;
561
                    }
562
                }
563
                $deps = array();
564
                if (!isset($unstable)) {
565
                    $unstable = false;
566
                    $state = 'stable';
567
                    if (isset($stable)) {
568
                        $latest = $unstable = $stable;
569
                    }
570
                } else {
571
                    $latest = $unstable;
572
                }
573
                if (!isset($latest)) {
574
                    $latest = false;
575
                }
576
                if ($latest) {
577
                    $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
578
                        $latest . '.txt', false, false, $channel);
579
                    if (!PEAR::isError($d)) {
580
                        $d = unserialize($d);
581
                        if ($d) {
582
                            if (isset($d['required'])) {
583
                                if (!class_exists('PEAR_PackageFile_v2')) {
584
                                    require_once 'PEAR/PackageFile/v2.php';
585
                                }
586
                                if (!isset($pf)) {
587
                                    $pf = new PEAR_PackageFile_v2;
588
                                }
589
                                $pf->setDeps($d);
590
                                $tdeps = $pf->getDeps();
591
                            } else {
592
                                $tdeps = $d;
593
                            }
594
                            foreach ($tdeps as $dep) {
595
                                if ($dep['type'] !== 'pkg') {
596
                                    continue;
597
                                }
598
                                $deps[] = $dep;
599
                            }
600
                        }
601
                    }
602
                }
603
                if (!isset($stable)) {
604
                    $stable = '-n/a-';
605
                }
606
                if (!$searchpackage) {
607
                    $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' =>
608
                        $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
609
                        'unstable' => $unstable, 'state' => $state);
610
                } else {
611
                    $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' =>
612
                        $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
613
                        'unstable' => $unstable, 'state' => $state);
614
                }
615
            }
616
            $ret[$package] = $info;
617
        }
618
        PEAR::popErrorHandling();
619
        return $ret;
620
    }
621
 
622
    function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
623
    {
624
        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
625
        if (PEAR::isError($packagelist)) {
626
            return $packagelist;
627
        }
628
        $ret = array();
629
        if (!is_array($packagelist) || !isset($packagelist['p'])) {
630
            return $ret;
631
        }
632
        if (!is_array($packagelist['p'])) {
633
            $packagelist['p'] = array($packagelist['p']);
634
        }
635
        foreach ($packagelist['p'] as $package) {
636
            if (!isset($installed[strtolower($package)])) {
637
                continue;
638
            }
639
            $inst_version = $reg->packageInfo($package, 'version', $channel);
640
            $inst_state = $reg->packageInfo($package, 'release_state', $channel);
641
            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
642
            $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
643
                '/allreleases.xml', false, false, $channel);
644
            PEAR::popErrorHandling();
645
            if (PEAR::isError($info)) {
646
                continue; // no remote releases
647
            }
648
            if (!isset($info['r'])) {
649
                continue;
650
            }
651
            $found = false;
652
            $release = false;
653
            if (!is_array($info['r']) || !isset($info['r'][0])) {
654
                $info['r'] = array($info['r']);
655
            }
656
            // $info['r'] is sorted by version number
657
            foreach ($info['r'] as $release) {
658
                if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
659
                    // not newer than the one installed
660
                    break;
661
                }
662
 
663
                // new version > installed version
664
                if (!$pref_state) {
665
                    // every state is a good state
666
                    $found = true;
667
                    break;
668
                } else {
669
                    $new_state = $release['s'];
670
                    // if new state >= installed state: go
671
                    if (in_array($new_state, $this->betterStates($inst_state, true))) {
672
                        $found = true;
673
                        break;
674
                    } else {
675
                        // only allow to lower the state of package,
676
                        // if new state >= preferred state: go
677
                        if (in_array($new_state, $this->betterStates($pref_state, true))) {
678
                            $found = true;
679
                            break;
680
                        }
681
                    }
682
                }
683
            }
684
            if (!$found) {
685
                continue;
686
            }
687
            $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
688
                $release['v'] . '.xml', false, false, $channel);
689
            if (PEAR::isError($relinfo)) {
690
                return $relinfo;
691
            }
692
            $ret[$package] = array(
693
                    'version' => $release['v'],
694
                    'state' => $release['s'],
695
                    'filesize' => $relinfo['f'],
696
                );
697
        }
698
        return $ret;
699
    }
700
 
701
    function packageInfo($base, $package, $channel = false)
702
    {
703
        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
704
        $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
705
        if (PEAR::isError($pinfo)) {
706
            PEAR::popErrorHandling();
707
            return PEAR::raiseError('Unknown package: "' . $package . '" (Debug: ' .
708
                $pinfo->getMessage() . ')');
709
        }
710
        $releases = array();
711
        $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
712
            '/allreleases.xml', false, false, $channel);
713
        if (!PEAR::isError($allreleases)) {
714
            if (!class_exists('PEAR_PackageFile_v2')) {
715
                require_once 'PEAR/PackageFile/v2.php';
716
            }
717
            if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) {
718
                $allreleases['r'] = array($allreleases['r']);
719
            }
720
            $pf = new PEAR_PackageFile_v2;
721
            foreach ($allreleases['r'] as $release) {
722
                $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
723
                    $release['v'] . '.txt', false, false, $channel);
724
                if (PEAR::isError($ds)) {
725
                    continue;
726
                }
727
                if (!isset($latest)) {
728
                    $latest = $release['v'];
729
                }
730
                $pf->setDeps(unserialize($ds));
731
                $ds = $pf->getDeps();
732
                $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package)
733
                    . '/' . $release['v'] . '.xml', false, false, $channel);
734
                if (PEAR::isError($info)) {
735
                    continue;
736
                }
737
                $releases[$release['v']] = array(
738
                    'doneby' => $info['m'],
739
                    'license' => $info['l'],
740
                    'summary' => $info['s'],
741
                    'description' => $info['d'],
742
                    'releasedate' => $info['da'],
743
                    'releasenotes' => $info['n'],
744
                    'state' => $release['s'],
745
                    'deps' => $ds ? $ds : array(),
746
                );
747
            }
748
        } else {
749
            $latest = '';
750
        }
751
        PEAR::popErrorHandling();
752
        if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
753
            if (is_array($pinfo['dp'])) {
754
                $deprecated = array('channel' => (string) $pinfo['dc'],
755
                                    'package' => trim($pinfo['dp']['_content']));
756
            } else {
757
                $deprecated = array('channel' => (string) $pinfo['dc'],
758
                                    'package' => trim($pinfo['dp']));
759
            }
760
        } else {
761
            $deprecated = false;
762
        }
763
        return array(
764
            'name' => $pinfo['n'],
765
            'channel' => $pinfo['c'],
766
            'category' => $pinfo['ca']['_content'],
767
            'stable' => $latest,
768
            'license' => $pinfo['l'],
769
            'summary' => $pinfo['s'],
770
            'description' => $pinfo['d'],
771
            'releases' => $releases,
772
            'deprecated' => $deprecated,
773
            );
774
    }
775
 
776
    /**
777
     * Return an array containing all of the states that are more stable than
778
     * or equal to the passed in state
779
     *
780
     * @param string Release state
781
     * @param boolean Determines whether to include $state in the list
782
     * @return false|array False if $state is not a valid release state
783
     */
784
    function betterStates($state, $include = false)
785
    {
786
        static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
787
        $i = array_search($state, $states);
788
        if ($i === false) {
789
            return false;
790
        }
791
        if ($include) {
792
            $i--;
793
        }
794
        return array_slice($states, $i + 1);
795
    }
796
}
797
?>