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_Downloader_Package
4
 *
5
 * PHP versions 4 and 5
6
 *
7
 * @category   pear
8
 * @package    PEAR
9
 * @author     Greg Beaver <cellog@php.net>
187 mathias 10
 * @copyright  1997-2009 The Authors
11
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
94 jpm 12
 * @link       http://pear.php.net/package/PEAR
13
 * @since      File available since Release 1.4.0a1
14
 */
187 mathias 15
 
94 jpm 16
/**
17
 * Error code when parameter initialization fails because no releases
18
 * exist within preferred_state, but releases do exist
19
 */
20
define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
21
/**
187 mathias 22
 * Error code when parameter initialization fails because no releases
23
 * exist that will work with the existing PHP version
24
 */
25
define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
26
 
27
/**
94 jpm 28
 * Coordinates download parameters and manages their dependencies
29
 * prior to downloading them.
30
 *
31
 * Input can come from three sources:
32
 *
33
 * - local files (archives or package.xml)
34
 * - remote files (downloadable urls)
35
 * - abstract package names
36
 *
37
 * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
38
 * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
39
 * format returned of dependencies is slightly different from that used in package.xml.
40
 *
41
 * This class hides the differences between these elements, and makes automatic
42
 * dependency resolution a piece of cake.  It also manages conflicts when
43
 * two classes depend on incompatible dependencies, or differing versions of the same
44
 * package dependency.  In addition, download will not be attempted if the php version is
45
 * not supported, PEAR installer version is not supported, or non-PECL extensions are not
46
 * installed.
47
 * @category   pear
48
 * @package    PEAR
49
 * @author     Greg Beaver <cellog@php.net>
187 mathias 50
 * @copyright  1997-2009 The Authors
51
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
52
 * @version    Release: 1.10.1
94 jpm 53
 * @link       http://pear.php.net/package/PEAR
54
 * @since      Class available since Release 1.4.0a1
55
 */
56
class PEAR_Downloader_Package
57
{
58
    /**
59
     * @var PEAR_Downloader
60
     */
61
    var $_downloader;
62
    /**
63
     * @var PEAR_Config
64
     */
65
    var $_config;
66
    /**
67
     * @var PEAR_Registry
68
     */
69
    var $_registry;
70
    /**
71
     * Used to implement packagingroot properly
72
     * @var PEAR_Registry
73
     */
74
    var $_installRegistry;
75
    /**
76
     * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
77
     */
78
    var $_packagefile;
79
    /**
80
     * @var array
81
     */
82
    var $_parsedname;
83
    /**
84
     * @var array
85
     */
86
    var $_downloadURL;
87
    /**
88
     * @var array
89
     */
90
    var $_downloadDeps = array();
91
    /**
92
     * @var boolean
93
     */
94
    var $_valid = false;
95
    /**
96
     * @var boolean
97
     */
98
    var $_analyzed = false;
99
    /**
100
     * if this or a parent package was invoked with Package-state, this is set to the
101
     * state variable.
102
     *
103
     * This allows temporary reassignment of preferred_state for a parent package and all of
104
     * its dependencies.
105
     * @var string|false
106
     */
107
    var $_explicitState = false;
108
    /**
109
     * If this package is invoked with Package#group, this variable will be true
110
     */
111
    var $_explicitGroup = false;
112
    /**
187 mathias 113
     * Package type local|url
94 jpm 114
     * @var string
115
     */
116
    var $_type;
117
    /**
118
     * Contents of package.xml, if downloaded from a remote channel
119
     * @var string|false
120
     * @access private
121
     */
122
    var $_rawpackagefile;
123
    /**
124
     * @var boolean
125
     * @access private
126
     */
127
    var $_validated = false;
128
 
129
    /**
130
     * @param PEAR_Downloader
131
     */
187 mathias 132
    function __construct(&$downloader)
94 jpm 133
    {
134
        $this->_downloader = &$downloader;
135
        $this->_config = &$this->_downloader->config;
136
        $this->_registry = &$this->_config->getRegistry();
137
        $options = $downloader->getOptions();
138
        if (isset($options['packagingroot'])) {
139
            $this->_config->setInstallRoot($options['packagingroot']);
140
            $this->_installRegistry = &$this->_config->getRegistry();
141
            $this->_config->setInstallRoot(false);
142
        } else {
143
            $this->_installRegistry = &$this->_registry;
144
        }
145
        $this->_valid = $this->_analyzed = false;
146
    }
147
 
148
    /**
149
     * Parse the input and determine whether this is a local file, a remote uri, or an
150
     * abstract package name.
151
     *
152
     * This is the heart of the PEAR_Downloader_Package(), and is used in
153
     * {@link PEAR_Downloader::download()}
154
     * @param string
155
     * @return bool|PEAR_Error
156
     */
157
    function initialize($param)
158
    {
159
        $origErr = $this->_fromFile($param);
187 mathias 160
        if ($this->_valid) {
161
            return true;
162
        }
163
 
164
        $options = $this->_downloader->getOptions();
165
        if (isset($options['offline'])) {
166
            if (PEAR::isError($origErr) && !isset($options['soft'])) {
167
                foreach ($origErr->getUserInfo() as $userInfo) {
168
                    if (isset($userInfo['message'])) {
169
                        $this->_downloader->log(0, $userInfo['message']);
94 jpm 170
                    }
171
                }
187 mathias 172
 
173
                $this->_downloader->log(0, $origErr->getMessage());
94 jpm 174
            }
187 mathias 175
 
176
            return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
177
        }
178
 
179
        $err = $this->_fromUrl($param);
180
        if (PEAR::isError($err) || !$this->_valid) {
181
            if ($this->_type == 'url') {
182
                if (PEAR::isError($err) && !isset($options['soft'])) {
183
                    $this->_downloader->log(0, $err->getMessage());
184
                }
185
 
186
                return PEAR::raiseError("Invalid or missing remote package file");
187
            }
188
 
189
            $err = $this->_fromString($param);
94 jpm 190
            if (PEAR::isError($err) || !$this->_valid) {
187 mathias 191
                if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
192
                    return false; // instruct the downloader to silently skip
94 jpm 193
                }
187 mathias 194
 
195
                if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) {
196
                    if (is_array($origErr->getUserInfo())) {
197
                        foreach ($origErr->getUserInfo() as $err) {
198
                            if (is_array($err)) {
199
                                $err = $err['message'];
94 jpm 200
                            }
187 mathias 201
 
202
                            if (!isset($options['soft'])) {
203
                                $this->_downloader->log(0, $err);
204
                            }
94 jpm 205
                        }
206
                    }
187 mathias 207
 
208
                    if (!isset($options['soft'])) {
209
                        $this->_downloader->log(0, $origErr->getMessage());
94 jpm 210
                    }
187 mathias 211
 
94 jpm 212
                    if (is_array($param)) {
213
                        $param = $this->_registry->parsedPackageNameToString($param, true);
214
                    }
187 mathias 215
 
216
                    if (!isset($options['soft'])) {
217
                        $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
218
                    }
219
 
220
                    // Passing no message back - already logged above
221
                    return PEAR::raiseError();
94 jpm 222
                }
187 mathias 223
 
224
                if (PEAR::isError($err) && !isset($options['soft'])) {
225
                    $this->_downloader->log(0, $err->getMessage());
226
                }
227
 
228
                if (is_array($param)) {
229
                    $param = $this->_registry->parsedPackageNameToString($param, true);
230
                }
231
 
232
                if (!isset($options['soft'])) {
233
                    $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
234
                }
235
 
236
                // Passing no message back - already logged above
237
                return PEAR::raiseError();
94 jpm 238
            }
239
        }
187 mathias 240
 
94 jpm 241
        return true;
242
    }
243
 
244
    /**
245
     * Retrieve any non-local packages
246
     * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
247
     */
248
    function &download()
249
    {
250
        if (isset($this->_packagefile)) {
251
            return $this->_packagefile;
252
        }
187 mathias 253
 
94 jpm 254
        if (isset($this->_downloadURL['url'])) {
255
            $this->_isvalid = false;
256
            $info = $this->getParsedPackage();
257
            foreach ($info as $i => $p) {
258
                $info[$i] = strtolower($p);
259
            }
187 mathias 260
 
94 jpm 261
            $err = $this->_fromUrl($this->_downloadURL['url'],
262
                $this->_registry->parsedPackageNameToString($this->_parsedname, true));
263
            $newinfo = $this->getParsedPackage();
264
            foreach ($newinfo as $i => $p) {
265
                $newinfo[$i] = strtolower($p);
266
            }
187 mathias 267
 
94 jpm 268
            if ($info != $newinfo) {
269
                do {
187 mathias 270
                    if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') {
271
                        $info['channel'] = 'pear.php.net';
94 jpm 272
                        if ($info == $newinfo) {
273
                            // skip the channel check if a pecl package says it's a PEAR package
274
                            break;
275
                        }
276
                    }
187 mathias 277
                    if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') {
278
                        $info['channel'] = 'pecl.php.net';
279
                        if ($info == $newinfo) {
280
                            // skip the channel check if a pecl package says it's a PEAR package
281
                            break;
282
                        }
283
                    }
284
 
94 jpm 285
                    return PEAR::raiseError('CRITICAL ERROR: We are ' .
286
                        $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
287
                        'downloaded claims to be ' .
288
                        $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
289
                } while (false);
290
            }
187 mathias 291
 
94 jpm 292
            if (PEAR::isError($err) || !$this->_valid) {
293
                return $err;
294
            }
295
        }
187 mathias 296
 
94 jpm 297
        $this->_type = 'local';
298
        return $this->_packagefile;
299
    }
300
 
301
    function &getPackageFile()
302
    {
303
        return $this->_packagefile;
304
    }
305
 
306
    function &getDownloader()
307
    {
308
        return $this->_downloader;
309
    }
310
 
187 mathias 311
    function getType()
94 jpm 312
    {
313
        return $this->_type;
314
    }
315
 
316
    /**
317
     * Like {@link initialize()}, but operates on a dependency
318
     */
319
    function fromDepURL($dep)
320
    {
321
        $this->_downloadURL = $dep;
322
        if (isset($dep['uri'])) {
323
            $options = $this->_downloader->getOptions();
324
            if (!extension_loaded("zlib") || isset($options['nocompress'])) {
325
                $ext = '.tar';
326
            } else {
327
                $ext = '.tgz';
328
            }
187 mathias 329
 
94 jpm 330
            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
331
            $err = $this->_fromUrl($dep['uri'] . $ext);
332
            PEAR::popErrorHandling();
333
            if (PEAR::isError($err)) {
334
                if (!isset($options['soft'])) {
335
                    $this->_downloader->log(0, $err->getMessage());
336
                }
187 mathias 337
 
94 jpm 338
                return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
339
                    'cannot download');
340
            }
341
        } else {
342
            $this->_parsedname =
343
                array(
344
                    'package' => $dep['info']->getPackage(),
345
                    'channel' => $dep['info']->getChannel(),
346
                    'version' => $dep['version']
347
                );
348
            if (!isset($dep['nodefault'])) {
349
                $this->_parsedname['group'] = 'default'; // download the default dependency group
350
                $this->_explicitGroup = false;
351
            }
187 mathias 352
 
94 jpm 353
            $this->_rawpackagefile = $dep['raw'];
354
        }
355
    }
356
 
357
    function detectDependencies($params)
358
    {
359
        $options = $this->_downloader->getOptions();
360
        if (isset($options['downloadonly'])) {
361
            return;
362
        }
187 mathias 363
 
94 jpm 364
        if (isset($options['offline'])) {
365
            $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
366
            return;
367
        }
187 mathias 368
 
94 jpm 369
        $pname = $this->getParsedPackage();
370
        if (!$pname) {
371
            return;
372
        }
187 mathias 373
 
94 jpm 374
        $deps = $this->getDeps();
375
        if (!$deps) {
376
            return;
377
        }
187 mathias 378
 
94 jpm 379
        if (isset($deps['required'])) { // package.xml 2.0
380
            return $this->_detect2($deps, $pname, $options, $params);
381
        }
187 mathias 382
 
383
        return $this->_detect1($deps, $pname, $options, $params);
94 jpm 384
    }
385
 
386
    function setValidated()
387
    {
388
        $this->_validated = true;
389
    }
390
 
391
    function alreadyValidated()
392
    {
393
        return $this->_validated;
394
    }
395
 
396
    /**
397
     * Remove packages to be downloaded that are already installed
398
     * @param array of PEAR_Downloader_Package objects
399
     */
187 mathias 400
    public static function removeInstalled(&$params)
94 jpm 401
    {
402
        if (!isset($params[0])) {
403
            return;
404
        }
187 mathias 405
 
94 jpm 406
        $options = $params[0]->_downloader->getOptions();
407
        if (!isset($options['downloadonly'])) {
408
            foreach ($params as $i => $param) {
187 mathias 409
                $package = $param->getPackage();
410
                $channel = $param->getChannel();
94 jpm 411
                // remove self if already installed with this version
412
                // this does not need any pecl magic - we only remove exact matches
187 mathias 413
                if ($param->_installRegistry->packageExists($package, $channel)) {
414
                    $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel);
415
                    if (version_compare($packageVersion, $param->getVersion(), '==')) {
416
                        if (!isset($options['force']) && !isset($options['packagingroot'])) {
94 jpm 417
                            $info = $param->getParsedPackage();
418
                            unset($info['version']);
419
                            unset($info['state']);
420
                            if (!isset($options['soft'])) {
421
                                $param->_downloader->log(1, 'Skipping package "' .
422
                                    $param->getShortName() .
187 mathias 423
                                    '", already installed as version ' . $packageVersion);
94 jpm 424
                            }
425
                            $params[$i] = false;
426
                        }
427
                    } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
187 mathias 428
                          !isset($options['soft']) && !isset($options['packagingroot'])) {
94 jpm 429
                        $info = $param->getParsedPackage();
430
                        $param->_downloader->log(1, 'Skipping package "' .
431
                            $param->getShortName() .
187 mathias 432
                            '", already installed as version ' . $packageVersion);
94 jpm 433
                        $params[$i] = false;
434
                    }
435
                }
436
            }
437
        }
187 mathias 438
 
94 jpm 439
        PEAR_Downloader_Package::removeDuplicates($params);
440
    }
441
 
442
    function _detect2($deps, $pname, $options, $params)
443
    {
444
        $this->_downloadDeps = array();
445
        $groupnotfound = false;
446
        foreach (array('package', 'subpackage') as $packagetype) {
447
            // get required dependency group
448
            if (isset($deps['required'][$packagetype])) {
449
                if (isset($deps['required'][$packagetype][0])) {
450
                    foreach ($deps['required'][$packagetype] as $dep) {
451
                        if (isset($dep['conflicts'])) {
452
                            // skip any package that this package conflicts with
453
                            continue;
454
                        }
455
                        $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
456
                        if (is_array($ret)) {
457
                            $this->_downloadDeps[] = $ret;
187 mathias 458
                        } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
459
                            $this->_downloader->log(0, $ret->getMessage());
94 jpm 460
                        }
461
                    }
462
                } else {
463
                    $dep = $deps['required'][$packagetype];
464
                    if (!isset($dep['conflicts'])) {
465
                        // skip any package that this package conflicts with
466
                        $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
467
                        if (is_array($ret)) {
468
                            $this->_downloadDeps[] = $ret;
187 mathias 469
                        } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
470
                            $this->_downloader->log(0, $ret->getMessage());
94 jpm 471
                        }
472
                    }
473
                }
474
            }
187 mathias 475
 
94 jpm 476
            // get optional dependency group, if any
477
            if (isset($deps['optional'][$packagetype])) {
478
                $skipnames = array();
479
                if (!isset($deps['optional'][$packagetype][0])) {
480
                    $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
481
                }
187 mathias 482
 
94 jpm 483
                foreach ($deps['optional'][$packagetype] as $dep) {
484
                    $skip = false;
485
                    if (!isset($options['alldeps'])) {
486
                        $dep['package'] = $dep['name'];
487
                        if (!isset($options['soft'])) {
488
                            $this->_downloader->log(3, 'Notice: package "' .
489
                              $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
490
                                    true) . '" optional dependency "' .
491
                                $this->_registry->parsedPackageNameToString(array('package' =>
492
                                    $dep['name'], 'channel' => 'pear.php.net'), true) .
493
                                '" will not be automatically downloaded');
494
                        }
495
                        $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
496
                        $skip = true;
497
                        unset($dep['package']);
498
                    }
187 mathias 499
 
500
                    $ret = $this->_detect2Dep($dep, $pname, 'optional', $params);
501
                    if (PEAR::isError($ret) && !isset($options['soft'])) {
502
                        $this->_downloader->log(0, $ret->getMessage());
503
                    }
504
 
505
                    if (!$ret) {
94 jpm 506
                        $dep['package'] = $dep['name'];
507
                        $skip = count($skipnames) ?
508
                            $skipnames[count($skipnames) - 1] : '';
509
                        if ($skip ==
510
                              $this->_registry->parsedPackageNameToString($dep, true)) {
511
                            array_pop($skipnames);
512
                        }
513
                    }
187 mathias 514
 
94 jpm 515
                    if (!$skip && is_array($ret)) {
516
                        $this->_downloadDeps[] = $ret;
517
                    }
518
                }
187 mathias 519
 
94 jpm 520
                if (count($skipnames)) {
521
                    if (!isset($options['soft'])) {
522
                        $this->_downloader->log(1, 'Did not download optional dependencies: ' .
523
                            implode(', ', $skipnames) .
524
                            ', use --alldeps to download automatically');
525
                    }
526
                }
527
            }
187 mathias 528
 
94 jpm 529
            // get requested dependency group, if any
530
            $groupname = $this->getGroup();
187 mathias 531
            $explicit  = $this->_explicitGroup;
94 jpm 532
            if (!$groupname) {
187 mathias 533
                if (!$this->canDefault()) {
94 jpm 534
                    continue;
535
                }
187 mathias 536
 
537
                $groupname = 'default'; // try the default dependency group
94 jpm 538
            }
187 mathias 539
 
94 jpm 540
            if ($groupnotfound) {
541
                continue;
542
            }
187 mathias 543
 
94 jpm 544
            if (isset($deps['group'])) {
545
                if (isset($deps['group']['attribs'])) {
546
                    if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
547
                        $group = $deps['group'];
548
                    } elseif ($explicit) {
549
                        if (!isset($options['soft'])) {
550
                            $this->_downloader->log(0, 'Warning: package "' .
551
                                $this->_registry->parsedPackageNameToString($pname, true) .
552
                                '" has no dependency ' . 'group named "' . $groupname . '"');
553
                        }
187 mathias 554
 
94 jpm 555
                        $groupnotfound = true;
556
                        continue;
557
                    }
558
                } else {
559
                    $found = false;
560
                    foreach ($deps['group'] as $group) {
561
                        if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
562
                            $found = true;
563
                            break;
564
                        }
565
                    }
187 mathias 566
 
94 jpm 567
                    if (!$found) {
568
                        if ($explicit) {
569
                            if (!isset($options['soft'])) {
570
                                $this->_downloader->log(0, 'Warning: package "' .
571
                                    $this->_registry->parsedPackageNameToString($pname, true) .
572
                                    '" has no dependency ' . 'group named "' . $groupname . '"');
573
                            }
574
                        }
187 mathias 575
 
94 jpm 576
                        $groupnotfound = true;
577
                        continue;
578
                    }
579
                }
580
            }
187 mathias 581
 
582
            if (isset($group) && isset($group[$packagetype])) {
583
                if (isset($group[$packagetype][0])) {
584
                    foreach ($group[$packagetype] as $dep) {
585
                        $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
94 jpm 586
                            $group['attribs']['name'] . '"', $params);
587
                        if (is_array($ret)) {
588
                            $this->_downloadDeps[] = $ret;
187 mathias 589
                        } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
590
                            $this->_downloader->log(0, $ret->getMessage());
94 jpm 591
                        }
592
                    }
187 mathias 593
                } else {
594
                    $ret = $this->_detect2Dep($group[$packagetype], $pname,
595
                        'dependency group "' .
596
                        $group['attribs']['name'] . '"', $params);
597
                    if (is_array($ret)) {
598
                        $this->_downloadDeps[] = $ret;
599
                    } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
600
                        $this->_downloader->log(0, $ret->getMessage());
601
                    }
94 jpm 602
                }
603
            }
604
        }
605
    }
606
 
607
    function _detect2Dep($dep, $pname, $group, $params)
608
    {
609
        if (isset($dep['conflicts'])) {
610
            return true;
611
        }
187 mathias 612
 
94 jpm 613
        $options = $this->_downloader->getOptions();
614
        if (isset($dep['uri'])) {
615
            return array('uri' => $dep['uri'], 'dep' => $dep);;
616
        }
187 mathias 617
 
94 jpm 618
        $testdep = $dep;
619
        $testdep['package'] = $dep['name'];
620
        if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
621
            $dep['package'] = $dep['name'];
622
            if (!isset($options['soft'])) {
623
                $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
624
                    ' dependency "' .
625
                    $this->_registry->parsedPackageNameToString($dep, true) .
626
                    '", will be installed');
627
            }
628
            return false;
629
        }
187 mathias 630
 
94 jpm 631
        $options = $this->_downloader->getOptions();
632
        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
633
        if ($this->_explicitState) {
634
            $pname['state'] = $this->_explicitState;
635
        }
187 mathias 636
 
637
        $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
94 jpm 638
        if (PEAR::isError($url)) {
639
            PEAR::popErrorHandling();
640
            return $url;
641
        }
187 mathias 642
 
94 jpm 643
        $dep['package'] = $dep['name'];
644
        $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
645
            !isset($options['alldeps']), true);
646
        PEAR::popErrorHandling();
647
        if (PEAR::isError($ret)) {
648
            if (!isset($options['soft'])) {
649
                $this->_downloader->log(0, $ret->getMessage());
650
            }
187 mathias 651
 
94 jpm 652
            return false;
187 mathias 653
        }
654
 
655
        // check to see if a dep is already installed and is the same or newer
656
        if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
657
            $oper = 'has';
94 jpm 658
        } else {
187 mathias 659
            $oper = 'gt';
660
        }
661
 
662
        // do not try to move this before getDepPackageDownloadURL
663
        // we can't determine whether upgrade is necessary until we know what
664
        // version would be downloaded
665
        if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
666
            $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']);
667
            $dep['package'] = $dep['name'];
668
            if (!isset($options['soft'])) {
669
                $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
670
                    ' dependency "' .
671
                $this->_registry->parsedPackageNameToString($dep, true) .
672
                    '" version ' . $url['version'] . ', already installed as version ' .
673
                    $version);
94 jpm 674
            }
187 mathias 675
 
676
            return false;
94 jpm 677
        }
187 mathias 678
 
94 jpm 679
        if (isset($dep['nodefault'])) {
680
            $ret['nodefault'] = true;
681
        }
187 mathias 682
 
94 jpm 683
        return $ret;
684
    }
685
 
686
    function _detect1($deps, $pname, $options, $params)
687
    {
688
        $this->_downloadDeps = array();
689
        $skipnames = array();
690
        foreach ($deps as $dep) {
691
            $nodownload = false;
187 mathias 692
            if (isset ($dep['type']) && $dep['type'] === 'pkg') {
94 jpm 693
                $dep['channel'] = 'pear.php.net';
694
                $dep['package'] = $dep['name'];
695
                switch ($dep['rel']) {
696
                    case 'not' :
697
                        continue 2;
698
                    case 'ge' :
699
                    case 'eq' :
700
                    case 'gt' :
701
                    case 'has' :
702
                        $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
703
                            'required' :
704
                            'optional';
705
                        if (PEAR_Downloader_Package::willDownload($dep, $params)) {
706
                            $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
707
                                . ' dependency "' .
708
                                $this->_registry->parsedPackageNameToString($dep, true) .
709
                                '", will be installed');
710
                            continue 2;
711
                        }
712
                        $fakedp = new PEAR_PackageFile_v1;
713
                        $fakedp->setPackage($dep['name']);
714
                        // skip internet check if we are not upgrading (bug #5810)
715
                        if (!isset($options['upgrade']) && $this->isInstalled(
716
                              $fakedp, $dep['rel'])) {
717
                            $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
718
                                . ' dependency "' .
719
                                $this->_registry->parsedPackageNameToString($dep, true) .
720
                                '", is already installed');
721
                            continue 2;
722
                        }
723
                }
187 mathias 724
 
94 jpm 725
                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
726
                if ($this->_explicitState) {
727
                    $pname['state'] = $this->_explicitState;
728
                }
187 mathias 729
 
730
                $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
94 jpm 731
                $chan = 'pear.php.net';
732
                if (PEAR::isError($url)) {
733
                    // check to see if this is a pecl package that has jumped
734
                    // from pear.php.net to pecl.php.net channel
735
                    if (!class_exists('PEAR_Dependency2')) {
736
                        require_once 'PEAR/Dependency2.php';
737
                    }
187 mathias 738
 
94 jpm 739
                    $newdep = PEAR_Dependency2::normalizeDep($dep);
740
                    $newdep = $newdep[0];
741
                    $newdep['channel'] = 'pecl.php.net';
742
                    $chan = 'pecl.php.net';
187 mathias 743
                    $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
94 jpm 744
                    $obj = &$this->_installRegistry->getPackage($dep['name']);
745
                    if (PEAR::isError($url)) {
746
                        PEAR::popErrorHandling();
747
                        if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
748
                            $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
749
                                'required' :
750
                                'optional';
751
                            $dep['package'] = $dep['name'];
752
                            if (!isset($options['soft'])) {
753
                                $this->_downloader->log(3, $this->getShortName() .
754
                                    ': Skipping ' . $group . ' dependency "' .
755
                                    $this->_registry->parsedPackageNameToString($dep, true) .
756
                                    '", already installed as version ' . $obj->getVersion());
757
                            }
758
                            $skip = count($skipnames) ?
759
                                $skipnames[count($skipnames) - 1] : '';
760
                            if ($skip ==
761
                                  $this->_registry->parsedPackageNameToString($dep, true)) {
762
                                array_pop($skipnames);
763
                            }
764
                            continue;
765
                        } else {
766
                            if (isset($dep['optional']) && $dep['optional'] == 'yes') {
767
                                $this->_downloader->log(2, $this->getShortName() .
187 mathias 768
                                    ': Skipping optional dependency "' .
94 jpm 769
                                    $this->_registry->parsedPackageNameToString($dep, true) .
770
                                    '", no releases exist');
771
                                continue;
772
                            } else {
773
                                return $url;
774
                            }
775
                        }
776
                    }
777
                }
187 mathias 778
 
94 jpm 779
                PEAR::popErrorHandling();
780
                if (!isset($options['alldeps'])) {
781
                    if (isset($dep['optional']) && $dep['optional'] == 'yes') {
782
                        if (!isset($options['soft'])) {
783
                            $this->_downloader->log(3, 'Notice: package "' .
784
                                $this->getShortName() .
785
                                '" optional dependency "' .
786
                                $this->_registry->parsedPackageNameToString(
787
                                    array('channel' => $chan, 'package' =>
788
                                    $dep['name']), true) .
789
                                '" will not be automatically downloaded');
790
                        }
791
                        $skipnames[] = $this->_registry->parsedPackageNameToString(
792
                                array('channel' => $chan, 'package' =>
793
                                $dep['name']), true);
794
                        $nodownload = true;
795
                    }
796
                }
187 mathias 797
 
94 jpm 798
                if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
799
                    if (!isset($dep['optional']) || $dep['optional'] == 'no') {
800
                        if (!isset($options['soft'])) {
801
                            $this->_downloader->log(3, 'Notice: package "' .
802
                                $this->getShortName() .
803
                                '" required dependency "' .
804
                                $this->_registry->parsedPackageNameToString(
805
                                    array('channel' => $chan, 'package' =>
806
                                    $dep['name']), true) .
807
                                '" will not be automatically downloaded');
808
                        }
809
                        $skipnames[] = $this->_registry->parsedPackageNameToString(
810
                                array('channel' => $chan, 'package' =>
811
                                $dep['name']), true);
812
                        $nodownload = true;
813
                    }
814
                }
187 mathias 815
 
94 jpm 816
                // check to see if a dep is already installed
817
                // do not try to move this before getDepPackageDownloadURL
818
                // we can't determine whether upgrade is necessary until we know what
819
                // version would be downloaded
820
                if (!isset($options['force']) && $this->isInstalled(
821
                        $url, $dep['rel'])) {
822
                    $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
823
                        'required' :
824
                        'optional';
825
                    $dep['package'] = $dep['name'];
826
                    if (isset($newdep)) {
187 mathias 827
                        $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']);
94 jpm 828
                    } else {
829
                        $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
830
                    }
187 mathias 831
 
94 jpm 832
                    $dep['version'] = $url['version'];
833
                    if (!isset($options['soft'])) {
834
                        $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
835
                            ' dependency "' .
836
                            $this->_registry->parsedPackageNameToString($dep, true) .
837
                            '", already installed as version ' . $version);
838
                    }
187 mathias 839
 
94 jpm 840
                    $skip = count($skipnames) ?
841
                        $skipnames[count($skipnames) - 1] : '';
842
                    if ($skip ==
843
                          $this->_registry->parsedPackageNameToString($dep, true)) {
844
                        array_pop($skipnames);
845
                    }
187 mathias 846
 
94 jpm 847
                    continue;
848
                }
187 mathias 849
 
94 jpm 850
                if ($nodownload) {
851
                    continue;
852
                }
187 mathias 853
 
94 jpm 854
                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
855
                if (isset($newdep)) {
856
                    $dep = $newdep;
857
                }
187 mathias 858
 
94 jpm 859
                $dep['package'] = $dep['name'];
860
                $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
861
                    isset($dep['optional']) && $dep['optional'] == 'yes' &&
862
                    !isset($options['alldeps']), true);
863
                PEAR::popErrorHandling();
864
                if (PEAR::isError($ret)) {
865
                    if (!isset($options['soft'])) {
866
                        $this->_downloader->log(0, $ret->getMessage());
867
                    }
868
                    continue;
869
                }
187 mathias 870
 
94 jpm 871
                $this->_downloadDeps[] = $ret;
872
            }
873
        }
187 mathias 874
 
94 jpm 875
        if (count($skipnames)) {
876
            if (!isset($options['soft'])) {
877
                $this->_downloader->log(1, 'Did not download dependencies: ' .
878
                    implode(', ', $skipnames) .
879
                    ', use --alldeps or --onlyreqdeps to download automatically');
880
            }
881
        }
882
    }
883
 
884
    function setDownloadURL($pkg)
885
    {
886
        $this->_downloadURL = $pkg;
887
    }
888
 
889
    /**
890
     * Set the package.xml object for this downloaded package
891
     *
892
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
893
     */
894
    function setPackageFile(&$pkg)
895
    {
896
        $this->_packagefile = &$pkg;
897
    }
898
 
899
    function getShortName()
900
    {
901
        return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
902
            'package' => $this->getPackage()), true);
903
    }
904
 
905
    function getParsedPackage()
187 mathias 906
    {
94 jpm 907
        if (isset($this->_packagefile) || isset($this->_parsedname)) {
908
            return array('channel' => $this->getChannel(),
909
                'package' => $this->getPackage(),
910
                'version' => $this->getVersion());
911
        }
187 mathias 912
 
94 jpm 913
        return false;
914
    }
915
 
916
    function getDownloadURL()
917
    {
918
        return $this->_downloadURL;
919
    }
920
 
921
    function canDefault()
922
    {
187 mathias 923
        if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) {
924
            return false;
94 jpm 925
        }
187 mathias 926
 
94 jpm 927
        return true;
928
    }
929
 
930
    function getPackage()
931
    {
932
        if (isset($this->_packagefile)) {
933
            return $this->_packagefile->getPackage();
934
        } elseif (isset($this->_downloadURL['info'])) {
935
            return $this->_downloadURL['info']->getPackage();
936
        }
187 mathias 937
 
938
        return false;
94 jpm 939
    }
940
 
941
    /**
942
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
943
     */
944
    function isSubpackage(&$pf)
945
    {
946
        if (isset($this->_packagefile)) {
947
            return $this->_packagefile->isSubpackage($pf);
948
        } elseif (isset($this->_downloadURL['info'])) {
949
            return $this->_downloadURL['info']->isSubpackage($pf);
950
        }
187 mathias 951
 
952
        return false;
94 jpm 953
    }
954
 
955
    function getPackageType()
956
    {
957
        if (isset($this->_packagefile)) {
958
            return $this->_packagefile->getPackageType();
959
        } elseif (isset($this->_downloadURL['info'])) {
960
            return $this->_downloadURL['info']->getPackageType();
961
        }
187 mathias 962
 
963
        return false;
94 jpm 964
    }
965
 
966
    function isBundle()
967
    {
968
        if (isset($this->_packagefile)) {
969
            return $this->_packagefile->getPackageType() == 'bundle';
970
        }
187 mathias 971
 
972
        return false;
94 jpm 973
    }
974
 
975
    function getPackageXmlVersion()
976
    {
977
        if (isset($this->_packagefile)) {
978
            return $this->_packagefile->getPackagexmlVersion();
979
        } elseif (isset($this->_downloadURL['info'])) {
980
            return $this->_downloadURL['info']->getPackagexmlVersion();
981
        }
187 mathias 982
 
983
        return '1.0';
94 jpm 984
    }
985
 
986
    function getChannel()
987
    {
988
        if (isset($this->_packagefile)) {
989
            return $this->_packagefile->getChannel();
990
        } elseif (isset($this->_downloadURL['info'])) {
991
            return $this->_downloadURL['info']->getChannel();
992
        }
187 mathias 993
 
994
        return false;
94 jpm 995
    }
996
 
997
    function getURI()
998
    {
999
        if (isset($this->_packagefile)) {
1000
            return $this->_packagefile->getURI();
1001
        } elseif (isset($this->_downloadURL['info'])) {
1002
            return $this->_downloadURL['info']->getURI();
1003
        }
187 mathias 1004
 
1005
        return false;
94 jpm 1006
    }
1007
 
1008
    function getVersion()
1009
    {
1010
        if (isset($this->_packagefile)) {
1011
            return $this->_packagefile->getVersion();
1012
        } elseif (isset($this->_downloadURL['version'])) {
1013
            return $this->_downloadURL['version'];
1014
        }
187 mathias 1015
 
1016
        return false;
94 jpm 1017
    }
1018
 
1019
    function isCompatible($pf)
1020
    {
1021
        if (isset($this->_packagefile)) {
1022
            return $this->_packagefile->isCompatible($pf);
1023
        } elseif (isset($this->_downloadURL['info'])) {
1024
            return $this->_downloadURL['info']->isCompatible($pf);
1025
        }
187 mathias 1026
 
1027
        return true;
94 jpm 1028
    }
1029
 
1030
    function setGroup($group)
1031
    {
1032
        $this->_parsedname['group'] = $group;
1033
    }
1034
 
1035
    function getGroup()
1036
    {
1037
        if (isset($this->_parsedname['group'])) {
1038
            return $this->_parsedname['group'];
1039
        }
187 mathias 1040
 
1041
        return '';
94 jpm 1042
    }
1043
 
1044
    function isExtension($name)
1045
    {
1046
        if (isset($this->_packagefile)) {
1047
            return $this->_packagefile->isExtension($name);
1048
        } elseif (isset($this->_downloadURL['info'])) {
187 mathias 1049
            if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
1050
                return $this->_downloadURL['info']->getProvidesExtension() == $name;
1051
            }
1052
 
94 jpm 1053
            return false;
1054
        }
187 mathias 1055
 
1056
        return false;
94 jpm 1057
    }
1058
 
1059
    function getDeps()
1060
    {
1061
        if (isset($this->_packagefile)) {
1062
            $ver = $this->_packagefile->getPackagexmlVersion();
1063
            if (version_compare($ver, '2.0', '>=')) {
1064
                return $this->_packagefile->getDeps(true);
1065
            }
187 mathias 1066
 
1067
            return $this->_packagefile->getDeps();
94 jpm 1068
        } elseif (isset($this->_downloadURL['info'])) {
1069
            $ver = $this->_downloadURL['info']->getPackagexmlVersion();
1070
            if (version_compare($ver, '2.0', '>=')) {
1071
                return $this->_downloadURL['info']->getDeps(true);
1072
            }
187 mathias 1073
 
1074
            return $this->_downloadURL['info']->getDeps();
94 jpm 1075
        }
187 mathias 1076
 
1077
        return array();
94 jpm 1078
    }
1079
 
1080
    /**
1081
     * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
1082
     *                     returned from getDepDownloadURL()
1083
     */
1084
    function isEqual($param)
1085
    {
1086
        if (is_object($param)) {
1087
            $channel = $param->getChannel();
1088
            $package = $param->getPackage();
1089
            if ($param->getURI()) {
1090
                $param = array(
1091
                    'channel' => $param->getChannel(),
1092
                    'package' => $param->getPackage(),
1093
                    'version' => $param->getVersion(),
1094
                    'uri' => $param->getURI(),
1095
                );
1096
            } else {
1097
                $param = array(
1098
                    'channel' => $param->getChannel(),
1099
                    'package' => $param->getPackage(),
1100
                    'version' => $param->getVersion(),
1101
                );
1102
            }
1103
        } else {
1104
            if (isset($param['uri'])) {
1105
                if ($this->getChannel() != '__uri') {
1106
                    return false;
1107
                }
1108
                return $param['uri'] == $this->getURI();
1109
            }
187 mathias 1110
 
1111
            $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage();
1112
            $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel();
94 jpm 1113
            if (isset($param['rel'])) {
1114
                if (!class_exists('PEAR_Dependency2')) {
1115
                    require_once 'PEAR/Dependency2.php';
1116
                }
187 mathias 1117
 
94 jpm 1118
                $newdep = PEAR_Dependency2::normalizeDep($param);
1119
                $newdep = $newdep[0];
1120
            } elseif (isset($param['min'])) {
1121
                $newdep = $param;
1122
            }
1123
        }
187 mathias 1124
 
94 jpm 1125
        if (isset($newdep)) {
1126
            if (!isset($newdep['min'])) {
1127
                $newdep['min'] = '0';
1128
            }
187 mathias 1129
 
94 jpm 1130
            if (!isset($newdep['max'])) {
1131
                $newdep['max'] = '100000000000000000000';
1132
            }
187 mathias 1133
 
94 jpm 1134
            // use magic to support pecl packages suddenly jumping to the pecl channel
1135
            // we need to support both dependency possibilities
1136
            if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
1137
                if ($package == $this->getPackage()) {
1138
                    $channel = 'pecl.php.net';
1139
                }
1140
            }
1141
            if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
1142
                if ($package == $this->getPackage()) {
1143
                    $channel = 'pear.php.net';
1144
                }
1145
            }
187 mathias 1146
 
94 jpm 1147
            return (strtolower($package) == strtolower($this->getPackage()) &&
1148
                $channel == $this->getChannel() &&
1149
                version_compare($newdep['min'], $this->getVersion(), '<=') &&
1150
                version_compare($newdep['max'], $this->getVersion(), '>='));
1151
        }
187 mathias 1152
 
94 jpm 1153
        // use magic to support pecl packages suddenly jumping to the pecl channel
1154
        if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
1155
            if (strtolower($package) == strtolower($this->getPackage())) {
1156
                $channel = 'pear.php.net';
1157
            }
1158
        }
187 mathias 1159
 
94 jpm 1160
        if (isset($param['version'])) {
1161
            return (strtolower($package) == strtolower($this->getPackage()) &&
1162
                $channel == $this->getChannel() &&
1163
                $param['version'] == $this->getVersion());
1164
        }
187 mathias 1165
 
1166
        return strtolower($package) == strtolower($this->getPackage()) &&
1167
            $channel == $this->getChannel();
94 jpm 1168
    }
1169
 
1170
    function isInstalled($dep, $oper = '==')
1171
    {
1172
        if (!$dep) {
1173
            return false;
1174
        }
187 mathias 1175
 
94 jpm 1176
        if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
1177
            return false;
1178
        }
187 mathias 1179
 
94 jpm 1180
        if (is_object($dep)) {
1181
            $package = $dep->getPackage();
1182
            $channel = $dep->getChannel();
1183
            if ($dep->getURI()) {
1184
                $dep = array(
1185
                    'uri' => $dep->getURI(),
1186
                    'version' => $dep->getVersion(),
1187
                );
1188
            } else {
1189
                $dep = array(
1190
                    'version' => $dep->getVersion(),
1191
                );
1192
            }
1193
        } else {
1194
            if (isset($dep['uri'])) {
1195
                $channel = '__uri';
1196
                $package = $dep['dep']['name'];
1197
            } else {
1198
                $channel = $dep['info']->getChannel();
1199
                $package = $dep['info']->getPackage();
1200
            }
1201
        }
187 mathias 1202
 
94 jpm 1203
        $options = $this->_downloader->getOptions();
187 mathias 1204
        $test    = $this->_installRegistry->packageExists($package, $channel);
94 jpm 1205
        if (!$test && $channel == 'pecl.php.net') {
1206
            // do magic to allow upgrading from old pecl packages to new ones
1207
            $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
1208
            $channel = 'pear.php.net';
1209
        }
187 mathias 1210
 
94 jpm 1211
        if ($test) {
1212
            if (isset($dep['uri'])) {
1213
                if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
1214
                    return true;
1215
                }
1216
            }
187 mathias 1217
 
94 jpm 1218
            if (isset($options['upgrade'])) {
187 mathias 1219
                $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel);
1220
                if (version_compare($packageVersion, $dep['version'], '>=')) {
1221
                    return true;
94 jpm 1222
                }
187 mathias 1223
 
1224
                return false;
94 jpm 1225
            }
187 mathias 1226
 
94 jpm 1227
            return true;
1228
        }
187 mathias 1229
 
94 jpm 1230
        return false;
1231
    }
1232
 
1233
    /**
187 mathias 1234
     * Detect duplicate package names with differing versions
1235
     *
1236
     * If a user requests to install Date 1.4.6 and Date 1.4.7,
1237
     * for instance, this is a logic error.  This method
1238
     * detects this situation.
1239
     *
1240
     * @param array $params array of PEAR_Downloader_Package objects
1241
     * @param array $errorparams empty array
1242
     * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
1243
     */
1244
    public static function detectStupidDuplicates($params, &$errorparams)
1245
    {
1246
        $existing = array();
1247
        foreach ($params as $i => $param) {
1248
            $package = $param->getPackage();
1249
            $channel = $param->getChannel();
1250
            $group   = $param->getGroup();
1251
            if (!isset($existing[$channel . '/' . $package])) {
1252
                $existing[$channel . '/' . $package] = array();
1253
            }
1254
 
1255
            if (!isset($existing[$channel . '/' . $package][$group])) {
1256
                $existing[$channel . '/' . $package][$group] = array();
1257
            }
1258
 
1259
            $existing[$channel . '/' . $package][$group][] = $i;
1260
        }
1261
 
1262
        $indices = array();
1263
        foreach ($existing as $package => $groups) {
1264
            foreach ($groups as $group => $dupes) {
1265
                if (count($dupes) > 1) {
1266
                    $indices = $indices + $dupes;
1267
                }
1268
            }
1269
        }
1270
 
1271
        $indices = array_unique($indices);
1272
        foreach ($indices as $index) {
1273
            $errorparams[] = $params[$index];
1274
        }
1275
 
1276
        return count($errorparams);
1277
    }
1278
 
1279
    /**
94 jpm 1280
     * @param array
1281
     * @param bool ignore install groups - for final removal of dupe packages
1282
     */
187 mathias 1283
    public static function removeDuplicates(&$params, $ignoreGroups = false)
94 jpm 1284
    {
1285
        $pnames = array();
1286
        foreach ($params as $i => $param) {
1287
            if (!$param) {
1288
                continue;
1289
            }
187 mathias 1290
 
94 jpm 1291
            if ($param->getPackage()) {
187 mathias 1292
                $group = $ignoreGroups ? '' : $param->getGroup();
94 jpm 1293
                $pnames[$i] = $param->getChannel() . '/' .
1294
                    $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
1295
            }
1296
        }
187 mathias 1297
 
94 jpm 1298
        $pnames = array_unique($pnames);
187 mathias 1299
        $unset  = array_diff(array_keys($params), array_keys($pnames));
1300
        $testp  = array_flip($pnames);
94 jpm 1301
        foreach ($params as $i => $param) {
1302
            if (!$param) {
1303
                $unset[] = $i;
1304
                continue;
1305
            }
187 mathias 1306
 
94 jpm 1307
            if (!is_a($param, 'PEAR_Downloader_Package')) {
1308
                $unset[] = $i;
1309
                continue;
1310
            }
187 mathias 1311
 
1312
            $group = $ignoreGroups ? '' : $param->getGroup();
94 jpm 1313
            if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
1314
                  $param->getVersion() . '#' . $group])) {
1315
                $unset[] = $i;
1316
            }
1317
        }
187 mathias 1318
 
94 jpm 1319
        foreach ($unset as $i) {
1320
            unset($params[$i]);
1321
        }
187 mathias 1322
 
94 jpm 1323
        $ret = array();
1324
        foreach ($params as $i => $param) {
1325
            $ret[] = &$params[$i];
1326
        }
187 mathias 1327
 
94 jpm 1328
        $params = array();
1329
        foreach ($ret as $i => $param) {
1330
            $params[] = &$ret[$i];
1331
        }
1332
    }
1333
 
1334
    function explicitState()
1335
    {
1336
        return $this->_explicitState;
1337
    }
1338
 
1339
    function setExplicitState($s)
1340
    {
1341
        $this->_explicitState = $s;
1342
    }
1343
 
1344
    /**
1345
     */
187 mathias 1346
    public static function mergeDependencies(&$params)
94 jpm 1347
    {
187 mathias 1348
        $bundles = $newparams = array();
94 jpm 1349
        foreach ($params as $i => $param) {
1350
            if (!$param->isBundle()) {
1351
                continue;
1352
            }
187 mathias 1353
 
94 jpm 1354
            $bundles[] = $i;
1355
            $pf = &$param->getPackageFile();
1356
            $newdeps = array();
1357
            $contents = $pf->getBundledPackages();
1358
            if (!is_array($contents)) {
1359
                $contents = array($contents);
1360
            }
187 mathias 1361
 
94 jpm 1362
            foreach ($contents as $file) {
1363
                $filecontents = $pf->getFileContents($file);
1364
                $dl = &$param->getDownloader();
1365
                $options = $dl->getOptions();
1366
                if (PEAR::isError($dir = $dl->getDownloadDir())) {
1367
                    return $dir;
1368
                }
187 mathias 1369
 
94 jpm 1370
                $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
1371
                if (!$fp) {
1372
                    continue;
1373
                }
187 mathias 1374
 
1375
                // FIXME do symlink check
1376
 
94 jpm 1377
                fwrite($fp, $filecontents, strlen($filecontents));
1378
                fclose($fp);
1379
                if ($s = $params[$i]->explicitState()) {
1380
                    $obj->setExplicitState($s);
1381
                }
187 mathias 1382
 
1383
                $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
94 jpm 1384
                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1385
                if (PEAR::isError($dir = $dl->getDownloadDir())) {
1386
                    PEAR::popErrorHandling();
1387
                    return $dir;
1388
                }
187 mathias 1389
                $a = $dir . DIRECTORY_SEPARATOR . $file;
1390
                $e = $obj->_fromFile($a);
94 jpm 1391
                PEAR::popErrorHandling();
1392
                if (PEAR::isError($e)) {
1393
                    if (!isset($options['soft'])) {
1394
                        $dl->log(0, $e->getMessage());
1395
                    }
1396
                    continue;
1397
                }
187 mathias 1398
 
1399
                if (!PEAR_Downloader_Package::willDownload($obj,
1400
                      array_merge($params, $newparams)) && !$param->isInstalled($obj)) {
1401
                    $newparams[] = $obj;
94 jpm 1402
                }
1403
            }
1404
        }
187 mathias 1405
 
94 jpm 1406
        foreach ($bundles as $i) {
1407
            unset($params[$i]); // remove bundles - only their contents matter for installation
1408
        }
187 mathias 1409
 
94 jpm 1410
        PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
1411
        if (count($newparams)) { // add in bundled packages for install
1412
            foreach ($newparams as $i => $unused) {
1413
                $params[] = &$newparams[$i];
1414
            }
1415
            $newparams = array();
1416
        }
187 mathias 1417
 
94 jpm 1418
        foreach ($params as $i => $param) {
1419
            $newdeps = array();
1420
            foreach ($param->_downloadDeps as $dep) {
187 mathias 1421
                $merge = array_merge($params, $newparams);
1422
                if (!PEAR_Downloader_Package::willDownload($dep, $merge)
1423
                    && !$param->isInstalled($dep)
1424
                ) {
94 jpm 1425
                    $newdeps[] = $dep;
1426
                } else {
187 mathias 1427
                    //var_dump($dep);
94 jpm 1428
                    // detect versioning conflicts here
1429
                }
1430
            }
187 mathias 1431
 
1432
            // convert the dependencies into PEAR_Downloader_Package objects for the next time around
94 jpm 1433
            $params[$i]->_downloadDeps = array();
1434
            foreach ($newdeps as $dep) {
187 mathias 1435
                $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
94 jpm 1436
                if ($s = $params[$i]->explicitState()) {
1437
                    $obj->setExplicitState($s);
1438
                }
187 mathias 1439
 
94 jpm 1440
                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1441
                $e = $obj->fromDepURL($dep);
1442
                PEAR::popErrorHandling();
1443
                if (PEAR::isError($e)) {
1444
                    if (!isset($options['soft'])) {
1445
                        $obj->_downloader->log(0, $e->getMessage());
1446
                    }
1447
                    continue;
1448
                }
187 mathias 1449
 
94 jpm 1450
                $e = $obj->detectDependencies($params);
1451
                if (PEAR::isError($e)) {
1452
                    if (!isset($options['soft'])) {
1453
                        $obj->_downloader->log(0, $e->getMessage());
1454
                    }
1455
                }
187 mathias 1456
 
1457
                $newparams[] = $obj;
94 jpm 1458
            }
1459
        }
187 mathias 1460
 
94 jpm 1461
        if (count($newparams)) {
1462
            foreach ($newparams as $i => $unused) {
1463
                $params[] = &$newparams[$i];
1464
            }
1465
            return true;
1466
        }
187 mathias 1467
 
1468
        return false;
94 jpm 1469
    }
1470
 
1471
 
1472
    /**
1473
     */
187 mathias 1474
    public static function willDownload($param, $params)
94 jpm 1475
    {
1476
        if (!is_array($params)) {
1477
            return false;
1478
        }
187 mathias 1479
 
94 jpm 1480
        foreach ($params as $obj) {
1481
            if ($obj->isEqual($param)) {
1482
                return true;
1483
            }
1484
        }
187 mathias 1485
 
94 jpm 1486
        return false;
1487
    }
1488
 
1489
    /**
1490
     * For simpler unit-testing
1491
     * @param PEAR_Config
1492
     * @param int
1493
     * @param string
1494
     */
187 mathias 1495
    function &getPackagefileObject(&$c, $d)
94 jpm 1496
    {
187 mathias 1497
        $a = new PEAR_PackageFile($c, $d);
94 jpm 1498
        return $a;
1499
    }
1500
 
1501
    /**
1502
     * This will retrieve from a local file if possible, and parse out
1503
     * a group name as well.  The original parameter will be modified to reflect this.
1504
     * @param string|array can be a parsed package name as well
1505
     * @access private
1506
     */
1507
    function _fromFile(&$param)
1508
    {
1509
        $saveparam = $param;
1510
        if (is_string($param)) {
1511
            if (!@file_exists($param)) {
1512
                $test = explode('#', $param);
1513
                $group = array_pop($test);
187 mathias 1514
                if (@file_exists(implode('#', $test))) {
94 jpm 1515
                    $this->setGroup($group);
1516
                    $param = implode('#', $test);
1517
                    $this->_explicitGroup = true;
1518
                }
1519
            }
187 mathias 1520
 
94 jpm 1521
            if (@is_file($param)) {
1522
                $this->_type = 'local';
1523
                $options = $this->_downloader->getOptions();
187 mathias 1524
                $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug);
94 jpm 1525
                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1526
                $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
1527
                PEAR::popErrorHandling();
1528
                if (PEAR::isError($pf)) {
1529
                    $this->_valid = false;
1530
                    $param = $saveparam;
1531
                    return $pf;
1532
                }
1533
                $this->_packagefile = &$pf;
1534
                if (!$this->getGroup()) {
1535
                    $this->setGroup('default'); // install the default dependency group
1536
                }
1537
                return $this->_valid = true;
1538
            }
1539
        }
1540
        $param = $saveparam;
1541
        return $this->_valid = false;
1542
    }
1543
 
1544
    function _fromUrl($param, $saveparam = '')
1545
    {
187 mathias 1546
        if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) {
94 jpm 1547
            $options = $this->_downloader->getOptions();
1548
            $this->_type = 'url';
1549
            $callback = $this->_downloader->ui ?
1550
                array(&$this->_downloader, '_downloadCallback') : null;
1551
            $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
1552
            if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
1553
                $this->_downloader->popErrorHandling();
1554
                return $dir;
1555
            }
187 mathias 1556
 
1557
            $this->_downloader->log(3, 'Downloading "' . $param . '"');
94 jpm 1558
            $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
187 mathias 1559
                $dir, $callback, null, false, $this->getChannel());
94 jpm 1560
            $this->_downloader->popErrorHandling();
1561
            if (PEAR::isError($file)) {
1562
                if (!empty($saveparam)) {
1563
                    $saveparam = ", cannot download \"$saveparam\"";
1564
                }
1565
                $err = PEAR::raiseError('Could not download from "' . $param .
1566
                    '"' . $saveparam . ' (' . $file->getMessage() . ')');
1567
                    return $err;
1568
            }
187 mathias 1569
 
94 jpm 1570
            if ($this->_rawpackagefile) {
1571
                require_once 'Archive/Tar.php';
187 mathias 1572
                $tar = new Archive_Tar($file);
94 jpm 1573
                $packagexml = $tar->extractInString('package2.xml');
1574
                if (!$packagexml) {
1575
                    $packagexml = $tar->extractInString('package.xml');
1576
                }
187 mathias 1577
 
94 jpm 1578
                if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
1579
                      str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
187 mathias 1580
                    if ($this->getChannel() != 'pear.php.net') {
94 jpm 1581
                        return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
1582
                            'not match value returned from xml-rpc');
1583
                    }
187 mathias 1584
 
1585
                    // be more lax for the existing PEAR packages that have not-ok
1586
                    // characters in their package.xml
1587
                    $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
1588
                        $this->getPackage() . '" package has invalid characters in its ' .
1589
                        'package.xml.  The next version of PEAR may not be able to install ' .
1590
                        'this package for security reasons.  Please open a bug report at ' .
1591
                        'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
94 jpm 1592
                }
1593
            }
187 mathias 1594
 
94 jpm 1595
            // whew, download worked!
187 mathias 1596
            $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
1597
 
94 jpm 1598
            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1599
            $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
1600
            PEAR::popErrorHandling();
1601
            if (PEAR::isError($pf)) {
1602
                if (is_array($pf->getUserInfo())) {
1603
                    foreach ($pf->getUserInfo() as $err) {
1604
                        if (is_array($err)) {
1605
                            $err = $err['message'];
1606
                        }
187 mathias 1607
 
94 jpm 1608
                        if (!isset($options['soft'])) {
1609
                            $this->_downloader->log(0, "Validation Error: $err");
1610
                        }
1611
                    }
1612
                }
187 mathias 1613
 
94 jpm 1614
                if (!isset($options['soft'])) {
1615
                    $this->_downloader->log(0, $pf->getMessage());
1616
                }
187 mathias 1617
 
1618
                ///FIXME need to pass back some error code that we can use to match with to cancel all further operations
1619
                /// At least stop all deps of this package from being installed
1620
                $out = $saveparam ? $saveparam : $param;
1621
                $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive');
94 jpm 1622
                $this->_valid = false;
1623
                return $err;
1624
            }
187 mathias 1625
 
94 jpm 1626
            $this->_packagefile = &$pf;
1627
            $this->setGroup('default'); // install the default dependency group
1628
            return $this->_valid = true;
1629
        }
187 mathias 1630
 
94 jpm 1631
        return $this->_valid = false;
1632
    }
1633
 
1634
    /**
1635
     *
1636
     * @param string|array pass in an array of format
1637
     *                     array(
1638
     *                      'package' => 'pname',
1639
     *                     ['channel' => 'channame',]
1640
     *                     ['version' => 'version',]
1641
     *                     ['state' => 'state',])
1642
     *                     or a string of format [channame/]pname[-version|-state]
1643
     */
1644
    function _fromString($param)
1645
    {
1646
        $options = $this->_downloader->getOptions();
187 mathias 1647
        $channel = $this->_config->get('default_channel');
94 jpm 1648
        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
187 mathias 1649
        $pname = $this->_registry->parsePackageName($param, $channel);
94 jpm 1650
        PEAR::popErrorHandling();
1651
        if (PEAR::isError($pname)) {
1652
            if ($pname->getCode() == 'invalid') {
1653
                $this->_valid = false;
1654
                return false;
1655
            }
187 mathias 1656
 
94 jpm 1657
            if ($pname->getCode() == 'channel') {
1658
                $parsed = $pname->getUserInfo();
1659
                if ($this->_downloader->discover($parsed['channel'])) {
1660
                    if ($this->_config->get('auto_discover')) {
1661
                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
187 mathias 1662
                        $pname = $this->_registry->parsePackageName($param, $channel);
94 jpm 1663
                        PEAR::popErrorHandling();
1664
                    } else {
1665
                        if (!isset($options['soft'])) {
1666
                            $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
1667
                                '" is not initialized, use ' .
1668
                                '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
1669
                                'or pear config-set auto_discover 1');
1670
                        }
1671
                    }
1672
                }
187 mathias 1673
 
94 jpm 1674
                if (PEAR::isError($pname)) {
1675
                    if (!isset($options['soft'])) {
1676
                        $this->_downloader->log(0, $pname->getMessage());
1677
                    }
187 mathias 1678
 
94 jpm 1679
                    if (is_array($param)) {
1680
                        $param = $this->_registry->parsedPackageNameToString($param);
1681
                    }
187 mathias 1682
 
1683
                    $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
94 jpm 1684
                    $this->_valid = false;
1685
                    return $err;
1686
                }
1687
            } else {
1688
                if (!isset($options['soft'])) {
1689
                    $this->_downloader->log(0, $pname->getMessage());
1690
                }
187 mathias 1691
 
1692
                $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
94 jpm 1693
                $this->_valid = false;
1694
                return $err;
1695
            }
1696
        }
187 mathias 1697
 
94 jpm 1698
        if (!isset($this->_type)) {
187 mathias 1699
            $this->_type = 'rest';
94 jpm 1700
        }
187 mathias 1701
 
1702
        $this->_parsedname    = $pname;
1703
        $this->_explicitState = isset($pname['state']) ? $pname['state'] : false;
1704
        $this->_explicitGroup = isset($pname['group']) ? true : false;
1705
 
94 jpm 1706
        $info = $this->_downloader->_getPackageDownloadUrl($pname);
1707
        if (PEAR::isError($info)) {
1708
            if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
1709
                // try pecl
1710
                $pname['channel'] = 'pecl.php.net';
1711
                if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
1712
                    if (!PEAR::isError($test)) {
1713
                        $info = PEAR::raiseError($info->getMessage() . ' - package ' .
1714
                            $this->_registry->parsedPackageNameToString($pname, true) .
1715
                            ' can be installed with "pecl install ' . $pname['package'] .
1716
                            '"');
1717
                    } else {
1718
                        $pname['channel'] = 'pear.php.net';
1719
                    }
1720
                } else {
1721
                    $pname['channel'] = 'pear.php.net';
1722
                }
1723
            }
187 mathias 1724
 
94 jpm 1725
            return $info;
1726
        }
187 mathias 1727
 
94 jpm 1728
        $this->_rawpackagefile = $info['raw'];
1729
        $ret = $this->_analyzeDownloadURL($info, $param, $pname);
1730
        if (PEAR::isError($ret)) {
1731
            return $ret;
1732
        }
187 mathias 1733
 
94 jpm 1734
        if ($ret) {
1735
            $this->_downloadURL = $ret;
1736
            return $this->_valid = (bool) $ret;
1737
        }
1738
    }
1739
 
1740
    /**
1741
     * @param array output of package.getDownloadURL
1742
     * @param string|array|object information for detecting packages to be downloaded, and
1743
     *                            for errors
1744
     * @param array name information of the package
1745
     * @param array|null packages to be downloaded
1746
     * @param bool is this an optional dependency?
1747
     * @param bool is this any kind of dependency?
1748
     * @access private
1749
     */
1750
    function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
1751
                                 $isdependency = false)
1752
    {
1753
        if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
1754
            return false;
1755
        }
187 mathias 1756
 
1757
        if ($info === false) {
1758
            $saveparam = !is_string($param) ? ", cannot download \"$param\"" : '';
1759
 
94 jpm 1760
            // no releases exist
1761
            return PEAR::raiseError('No releases for package "' .
1762
                $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
1763
        }
187 mathias 1764
 
94 jpm 1765
        if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
1766
            $err = false;
1767
            if ($pname['channel'] == 'pecl.php.net') {
1768
                if ($info['info']->getChannel() != 'pear.php.net') {
1769
                    $err = true;
1770
                }
1771
            } elseif ($info['info']->getChannel() == 'pecl.php.net') {
1772
                if ($pname['channel'] != 'pear.php.net') {
1773
                    $err = true;
1774
                }
1775
            } else {
1776
                $err = true;
1777
            }
187 mathias 1778
 
94 jpm 1779
            if ($err) {
1780
                return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
1781
                    '" retrieved another channel\'s name for download! ("' .
1782
                    $info['info']->getChannel() . '")');
1783
            }
1784
        }
187 mathias 1785
 
1786
        $preferred_state = $this->_config->get('preferred_state');
94 jpm 1787
        if (!isset($info['url'])) {
187 mathias 1788
            $package_version = $this->_registry->packageInfo($info['info']->getPackage(),
1789
            'version', $info['info']->getChannel());
94 jpm 1790
            if ($this->isInstalled($info)) {
187 mathias 1791
                if ($isdependency && version_compare($info['version'], $package_version, '<=')) {
94 jpm 1792
                    // ignore bogus errors of "failed to download dependency"
1793
                    // if it is already installed and the one that would be
1794
                    // downloaded is older or the same version (Bug #7219)
1795
                    return false;
1796
                }
1797
            }
187 mathias 1798
 
1799
            if ($info['version'] === $package_version) {
1800
                if (!isset($options['soft'])) {
1801
                    $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
1802
                        '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' .
1803
                        ' (' . $package_version . ') is the same as the locally installed one.');
1804
                }
1805
 
1806
                return false;
1807
            }
1808
 
1809
            if (version_compare($info['version'], $package_version, '<=')) {
1810
                if (!isset($options['soft'])) {
1811
                    $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
1812
                        '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' .
1813
                        ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').');
1814
                }
1815
 
1816
                return false;
1817
            }
1818
 
94 jpm 1819
            $instead =  ', will instead download version ' . $info['version'] .
1820
                        ', stability "' . $info['info']->getState() . '"';
1821
            // releases exist, but we failed to get any
1822
            if (isset($this->_downloader->_options['force'])) {
1823
                if (isset($pname['version'])) {
1824
                    $vs = ', version "' . $pname['version'] . '"';
1825
                } elseif (isset($pname['state'])) {
1826
                    $vs = ', stability "' . $pname['state'] . '"';
1827
                } elseif ($param == 'dependency') {
1828
                    if (!class_exists('PEAR_Common')) {
1829
                        require_once 'PEAR/Common.php';
1830
                    }
187 mathias 1831
 
94 jpm 1832
                    if (!in_array($info['info']->getState(),
187 mathias 1833
                          PEAR_Common::betterStates($preferred_state, true))) {
94 jpm 1834
                        if ($optional) {
1835
                            // don't spit out confusing error message
1836
                            return $this->_downloader->_getPackageDownloadUrl(
1837
                                array('package' => $pname['package'],
1838
                                      'channel' => $pname['channel'],
1839
                                      'version' => $info['version']));
1840
                        }
187 mathias 1841
                        $vs = ' within preferred state "' . $preferred_state .
94 jpm 1842
                            '"';
1843
                    } else {
1844
                        if (!class_exists('PEAR_Dependency2')) {
1845
                            require_once 'PEAR/Dependency2.php';
1846
                        }
187 mathias 1847
 
94 jpm 1848
                        if ($optional) {
1849
                            // don't spit out confusing error message
1850
                            return $this->_downloader->_getPackageDownloadUrl(
1851
                                array('package' => $pname['package'],
1852
                                      'channel' => $pname['channel'],
1853
                                      'version' => $info['version']));
1854
                        }
1855
                        $vs = PEAR_Dependency2::_getExtraString($pname);
1856
                        $instead = '';
1857
                    }
1858
                } else {
187 mathias 1859
                    $vs = ' within preferred state "' . $preferred_state . '"';
94 jpm 1860
                }
187 mathias 1861
 
94 jpm 1862
                if (!isset($options['soft'])) {
1863
                    $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
1864
                        '/' . $pname['package'] . $vs . $instead);
1865
                }
187 mathias 1866
 
94 jpm 1867
                // download the latest release
1868
                return $this->_downloader->_getPackageDownloadUrl(
1869
                    array('package' => $pname['package'],
1870
                          'channel' => $pname['channel'],
1871
                          'version' => $info['version']));
1872
            } else {
187 mathias 1873
                if (isset($info['php']) && $info['php']) {
1874
                    $err = PEAR::raiseError('Failed to download ' .
1875
                        $this->_registry->parsedPackageNameToString(
1876
                            array('channel' => $pname['channel'],
1877
                                  'package' => $pname['package']),
1878
                                true) .
1879
                        ', latest release is version ' . $info['php']['v'] .
1880
                        ', but it requires PHP version "' .
1881
                        $info['php']['m'] . '", use "' .
1882
                        $this->_registry->parsedPackageNameToString(
1883
                            array('channel' => $pname['channel'], 'package' => $pname['package'],
1884
                            'version' => $info['php']['v'])) . '" to install',
1885
                            PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
1886
                    return $err;
1887
                }
1888
 
94 jpm 1889
                // construct helpful error message
1890
                if (isset($pname['version'])) {
1891
                    $vs = ', version "' . $pname['version'] . '"';
1892
                } elseif (isset($pname['state'])) {
1893
                    $vs = ', stability "' . $pname['state'] . '"';
1894
                } elseif ($param == 'dependency') {
1895
                    if (!class_exists('PEAR_Common')) {
1896
                        require_once 'PEAR/Common.php';
1897
                    }
187 mathias 1898
 
94 jpm 1899
                    if (!in_array($info['info']->getState(),
187 mathias 1900
                          PEAR_Common::betterStates($preferred_state, true))) {
94 jpm 1901
                        if ($optional) {
1902
                            // don't spit out confusing error message, and don't die on
1903
                            // optional dep failure!
1904
                            return $this->_downloader->_getPackageDownloadUrl(
1905
                                array('package' => $pname['package'],
1906
                                      'channel' => $pname['channel'],
1907
                                      'version' => $info['version']));
1908
                        }
187 mathias 1909
                        $vs = ' within preferred state "' . $preferred_state . '"';
94 jpm 1910
                    } else {
1911
                        if (!class_exists('PEAR_Dependency2')) {
1912
                            require_once 'PEAR/Dependency2.php';
1913
                        }
187 mathias 1914
 
94 jpm 1915
                        if ($optional) {
1916
                            // don't spit out confusing error message, and don't die on
1917
                            // optional dep failure!
1918
                            return $this->_downloader->_getPackageDownloadUrl(
1919
                                array('package' => $pname['package'],
1920
                                      'channel' => $pname['channel'],
1921
                                      'version' => $info['version']));
1922
                        }
1923
                        $vs = PEAR_Dependency2::_getExtraString($pname);
1924
                    }
1925
                } else {
187 mathias 1926
                    $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
94 jpm 1927
                }
187 mathias 1928
 
94 jpm 1929
                $options = $this->_downloader->getOptions();
1930
                // this is only set by the "download-all" command
1931
                if (isset($options['ignorepreferred_state'])) {
1932
                    $err = PEAR::raiseError(
1933
                        'Failed to download ' . $this->_registry->parsedPackageNameToString(
1934
                            array('channel' => $pname['channel'], 'package' => $pname['package']),
1935
                                true)
1936
                         . $vs .
1937
                        ', latest release is version ' . $info['version'] .
1938
                        ', stability "' . $info['info']->getState() . '", use "' .
1939
                        $this->_registry->parsedPackageNameToString(
1940
                            array('channel' => $pname['channel'], 'package' => $pname['package'],
1941
                            'version' => $info['version'])) . '" to install',
1942
                            PEAR_DOWNLOADER_PACKAGE_STATE);
1943
                    return $err;
1944
                }
187 mathias 1945
 
1946
                // Checks if the user has a package installed already and checks the release against
1947
                // the state against the installed package, this allows upgrades for packages
1948
                // with lower stability than the preferred_state
1949
                $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']);
1950
                if (!$this->isInstalled($info)
1951
                    || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true))
1952
                ) {
1953
                    $err = PEAR::raiseError(
1954
                        'Failed to download ' . $this->_registry->parsedPackageNameToString(
1955
                            array('channel' => $pname['channel'], 'package' => $pname['package']),
1956
                                true)
1957
                         . $vs .
1958
                        ', latest release is version ' . $info['version'] .
1959
                        ', stability "' . $info['info']->getState() . '", use "' .
1960
                        $this->_registry->parsedPackageNameToString(
1961
                            array('channel' => $pname['channel'], 'package' => $pname['package'],
1962
                            'version' => $info['version'])) . '" to install');
1963
                    return $err;
1964
                }
94 jpm 1965
            }
1966
        }
187 mathias 1967
 
94 jpm 1968
        if (isset($info['deprecated']) && $info['deprecated']) {
1969
            $this->_downloader->log(0,
187 mathias 1970
                'WARNING: "' .
94 jpm 1971
                    $this->_registry->parsedPackageNameToString(
1972
                            array('channel' => $info['info']->getChannel(),
1973
                                  'package' => $info['info']->getPackage()), true) .
1974
                '" is deprecated in favor of "' .
1975
                    $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
1976
                '"');
1977
        }
187 mathias 1978
 
94 jpm 1979
        return $info;
1980
    }
1981
}