Хранилища Subversion ant

Редакция

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

Редакция Автор № строки Строка
69 alex-w 1
<?php
2
/**
3
 * PEAR_PackageFile_v2, package.xml version 2.0
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: v2.php,v 1.143 2008/05/13 05:28:51 cellog Exp $
19
 * @link       http://pear.php.net/package/PEAR
20
 * @since      File available since Release 1.4.0a1
21
 */
22
/**
23
 * For error handling
24
 */
25
require_once 'PEAR/ErrorStack.php';
26
/**
27
 * @category   pear
28
 * @package    PEAR
29
 * @author     Greg Beaver <cellog@php.net>
30
 * @copyright  1997-2008 The PHP Group
31
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
32
 * @version    Release: 1.7.2
33
 * @link       http://pear.php.net/package/PEAR
34
 * @since      Class available since Release 1.4.0a1
35
 */
36
class PEAR_PackageFile_v2
37
{
38
 
39
    /**
40
     * Parsed package information
41
     * @var array
42
     * @access private
43
     */
44
    var $_packageInfo = array();
45
 
46
    /**
47
     * path to package .tgz or false if this is a local/extracted package.xml
48
     * @var string|false
49
     * @access private
50
     */
51
    var $_archiveFile;
52
 
53
    /**
54
     * path to package .xml or false if this is an abstract parsed-from-string xml
55
     * @var string|false
56
     * @access private
57
     */
58
    var $_packageFile;
59
 
60
    /**
61
     * This is used by file analysis routines to log progress information
62
     * @var PEAR_Common
63
     * @access protected
64
     */
65
    var $_logger;
66
 
67
    /**
68
     * This is set to the highest validation level that has been validated
69
     *
70
     * If the package.xml is invalid or unknown, this is set to 0.  If
71
     * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL.  If
72
     * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING
73
     * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING.  This allows validation
74
     * "caching" to occur, which is particularly important for package validation, so
75
     * that PHP files are not validated twice
76
     * @var int
77
     * @access private
78
     */
79
    var $_isValid = 0;
80
 
81
    /**
82
     * True if the filelist has been validated
83
     * @param bool
84
     */
85
    var $_filesValid = false;
86
 
87
    /**
88
     * @var PEAR_Registry
89
     * @access protected
90
     */
91
    var $_registry;
92
 
93
    /**
94
     * @var PEAR_Config
95
     * @access protected
96
     */
97
    var $_config;
98
 
99
    /**
100
     * Optional Dependency group requested for installation
101
     * @var string
102
     * @access private
103
     */
104
    var $_requestedGroup = false;
105
 
106
    /**
107
     * @var PEAR_ErrorStack
108
     * @access protected
109
     */
110
    var $_stack;
111
 
112
    /**
113
     * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible
114
     */
115
    var $_tasksNs;
116
 
117
    /**
118
     * Determines whether this packagefile was initialized only with partial package info
119
     *
120
     * If this package file was constructed via parsing REST, it will only contain
121
     *
122
     * - package name
123
     * - channel name
124
     * - dependencies
125
     * @var boolean
126
     * @access private
127
     */
128
    var $_incomplete = true;
129
 
130
    /**
131
     * @var PEAR_PackageFile_v2_Validator
132
     */
133
    var $_v2Validator;
134
 
135
    /**
136
     * The constructor merely sets up the private error stack
137
     */
138
    function PEAR_PackageFile_v2()
139
    {
140
        $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null);
141
        $this->_isValid = false;
142
    }
143
 
144
    /**
145
     * To make unit-testing easier
146
     * @param PEAR_Frontend_*
147
     * @param array options
148
     * @param PEAR_Config
149
     * @return PEAR_Downloader
150
     * @access protected
151
     */
152
    function &getPEARDownloader(&$i, $o, &$c)
153
    {
154
        $z = &new PEAR_Downloader($i, $o, $c);
155
        return $z;
156
    }
157
 
158
    /**
159
     * To make unit-testing easier
160
     * @param PEAR_Config
161
     * @param array options
162
     * @param array package name as returned from {@link PEAR_Registry::parsePackageName()}
163
     * @param int PEAR_VALIDATE_* constant
164
     * @return PEAR_Dependency2
165
     * @access protected
166
     */
167
    function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING)
168
    {
169
        if (!class_exists('PEAR_Dependency2')) {
170
            require_once 'PEAR/Dependency2.php';
171
        }
172
        $z = &new PEAR_Dependency2($c, $o, $p, $s);
173
        return $z;
174
    }
175
 
176
    function getInstalledBinary()
177
    {
178
        return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] :
179
            false;
180
    }
181
 
182
    /**
183
     * Installation of source package has failed, attempt to download and install the
184
     * binary version of this package.
185
     * @param PEAR_Installer
186
     * @return array|false
187
     */
188
    function installBinary(&$installer)
189
    {
190
        if (!OS_WINDOWS) {
191
            $a = false;
192
            return $a;
193
        }
194
        if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
195
            $releasetype = $this->getPackageType() . 'release';
196
            if (!is_array($installer->getInstallPackages())) {
197
                $a = false;
198
                return $a;
199
            }
200
            foreach ($installer->getInstallPackages() as $p) {
201
                if ($p->isExtension($this->_packageInfo['providesextension'])) {
202
                    if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') {
203
                        $a = false;
204
                        return $a; // the user probably downloaded it separately
205
                    }
206
                }
207
            }
208
            if (isset($this->_packageInfo[$releasetype]['binarypackage'])) {
209
                $installer->log(0, 'Attempting to download binary version of extension "' .
210
                    $this->_packageInfo['providesextension'] . '"');
211
                $params = $this->_packageInfo[$releasetype]['binarypackage'];
212
                if (!is_array($params) || !isset($params[0])) {
213
                    $params = array($params);
214
                }
215
                if (isset($this->_packageInfo['channel'])) {
216
                    foreach ($params as $i => $param) {
217
                        $params[$i] = array('channel' => $this->_packageInfo['channel'],
218
                            'package' => $param, 'version' => $this->getVersion());
219
                    }
220
                }
221
                $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(),
222
                    $installer->config);
223
                $verbose = $dl->config->get('verbose');
224
                $dl->config->set('verbose', -1);
225
                foreach ($params as $param) {
226
                    PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
227
                    $ret = $dl->download(array($param));
228
                    PEAR::popErrorHandling();
229
                    if (is_array($ret) && count($ret)) {
230
                        break;
231
                    }
232
                }
233
                $dl->config->set('verbose', $verbose);
234
                if (is_array($ret)) {
235
                    if (count($ret) == 1) {
236
                        $pf = $ret[0]->getPackageFile();
237
                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
238
                        $err = $installer->install($ret[0]);
239
                        PEAR::popErrorHandling();
240
                        if (is_array($err)) {
241
                            $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage();
242
                            // "install" self, so all dependencies will work transparently
243
                            $this->_registry->addPackage2($this);
244
                            $installer->log(0, 'Download and install of binary extension "' .
245
                                $this->_registry->parsedPackageNameToString(
246
                                    array('channel' => $pf->getChannel(),
247
                                          'package' => $pf->getPackage()), true) . '" successful');
248
                            $a = array($ret[0], $err);
249
                            return $a;
250
                        }
251
                        $installer->log(0, 'Download and install of binary extension "' .
252
                            $this->_registry->parsedPackageNameToString(
253
                                    array('channel' => $pf->getChannel(),
254
                                          'package' => $pf->getPackage()), true) . '" failed');
255
                    }
256
                }
257
            }
258
        }
259
        $a = false;
260
        return $a;
261
    }
262
 
263
    /**
264
     * @return string|false Extension name
265
     */
266
    function getProvidesExtension()
267
    {
268
        if (in_array($this->getPackageType(),
269
              array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
270
            if (isset($this->_packageInfo['providesextension'])) {
271
                return $this->_packageInfo['providesextension'];
272
            }
273
        }
274
        return false;
275
    }
276
 
277
    /**
278
     * @param string Extension name
279
     * @return bool
280
     */
281
    function isExtension($extension)
282
    {
283
        if (in_array($this->getPackageType(),
284
              array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
285
            return $this->_packageInfo['providesextension'] == $extension;
286
        }
287
        return false;
288
    }
289
 
290
    /**
291
     * Tests whether every part of the package.xml 1.0 is represented in
292
     * this package.xml 2.0
293
     * @param PEAR_PackageFile_v1
294
     * @return bool
295
     */
296
    function isEquivalent($pf1)
297
    {
298
        if (!$pf1) {
299
            return true;
300
        }
301
        if ($this->getPackageType() == 'bundle') {
302
            return false;
303
        }
304
        $this->_stack->getErrors(true);
305
        if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) {
306
            return false;
307
        }
308
        $pass = true;
309
        if ($pf1->getPackage() != $this->getPackage()) {
310
            $this->_differentPackage($pf1->getPackage());
311
            $pass = false;
312
        }
313
        if ($pf1->getVersion() != $this->getVersion()) {
314
            $this->_differentVersion($pf1->getVersion());
315
            $pass = false;
316
        }
317
        if (trim($pf1->getSummary()) != $this->getSummary()) {
318
            $this->_differentSummary($pf1->getSummary());
319
            $pass = false;
320
        }
321
        if (preg_replace('/\s+/', '', $pf1->getDescription()) !=
322
              preg_replace('/\s+/', '', $this->getDescription())) {
323
            $this->_differentDescription($pf1->getDescription());
324
            $pass = false;
325
        }
326
        if ($pf1->getState() != $this->getState()) {
327
            $this->_differentState($pf1->getState());
328
            $pass = false;
329
        }
330
        if (!strstr(preg_replace('/\s+/', '', $this->getNotes()),
331
              preg_replace('/\s+/', '', $pf1->getNotes()))) {
332
            $this->_differentNotes($pf1->getNotes());
333
            $pass = false;
334
        }
335
        $mymaintainers = $this->getMaintainers();
336
        $yourmaintainers = $pf1->getMaintainers();
337
        for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) {
338
            $reset = false;
339
            for ($i2 = 0; $i2 < count($mymaintainers); $i2++) {
340
                if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) {
341
                    if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) {
342
                        $this->_differentRole($mymaintainers[$i2]['handle'],
343
                            $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']);
344
                        $pass = false;
345
                    }
346
                    if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) {
347
                        $this->_differentEmail($mymaintainers[$i2]['handle'],
348
                            $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']);
349
                        $pass = false;
350
                    }
351
                    if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) {
352
                        $this->_differentName($mymaintainers[$i2]['handle'],
353
                            $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']);
354
                        $pass = false;
355
                    }
356
                    unset($mymaintainers[$i2]);
357
                    $mymaintainers = array_values($mymaintainers);
358
                    unset($yourmaintainers[$i1]);
359
                    $yourmaintainers = array_values($yourmaintainers);
360
                    $reset = true;
361
                    break;
362
                }
363
            }
364
            if ($reset) {
365
                $i1 = -1;
366
            }
367
        }
368
        $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers);
369
        $filelist = $this->getFilelist();
370
        foreach ($pf1->getFilelist() as $file => $atts) {
371
            if (!isset($filelist[$file])) {
372
                $this->_missingFile($file);
373
                $pass = false;
374
            }
375
        }
376
        return $pass;
377
    }
378
 
379
    function _differentPackage($package)
380
    {
381
        $this->_stack->push(__FUNCTION__, 'error', array('package' => $package,
382
            'self' => $this->getPackage()),
383
            'package.xml 1.0 package "%package%" does not match "%self%"');
384
    }
385
 
386
    function _differentVersion($version)
387
    {
388
        $this->_stack->push(__FUNCTION__, 'error', array('version' => $version,
389
            'self' => $this->getVersion()),
390
            'package.xml 1.0 version "%version%" does not match "%self%"');
391
    }
392
 
393
    function _differentState($state)
394
    {
395
        $this->_stack->push(__FUNCTION__, 'error', array('state' => $state,
396
            'self' => $this->getState()),
397
            'package.xml 1.0 state "%state%" does not match "%self%"');
398
    }
399
 
400
    function _differentRole($handle, $role, $selfrole)
401
    {
402
        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
403
            'role' => $role, 'self' => $selfrole),
404
            'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"');
405
    }
406
 
407
    function _differentEmail($handle, $email, $selfemail)
408
    {
409
        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
410
            'email' => $email, 'self' => $selfemail),
411
            'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"');
412
    }
413
 
414
    function _differentName($handle, $name, $selfname)
415
    {
416
        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
417
            'name' => $name, 'self' => $selfname),
418
            'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"');
419
    }
420
 
421
    function _unmatchedMaintainers($my, $yours)
422
    {
423
        if ($my) {
424
            array_walk($my, create_function('&$i, $k', '$i = $i["handle"];'));
425
            $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my),
426
                'package.xml 2.0 has unmatched extra maintainers "%handles%"');
427
        }
428
        if ($yours) {
429
            array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];'));
430
            $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours),
431
                'package.xml 1.0 has unmatched extra maintainers "%handles%"');
432
        }
433
    }
434
 
435
    function _differentNotes($notes)
436
    {
437
        $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...';
438
        $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() :
439
            substr($this->getNotes(), 0, 24) . '...';
440
        $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes,
441
            'self' => $truncmynotes),
442
            'package.xml 1.0 release notes "%notes%" do not match "%self%"');
443
    }
444
 
445
    function _differentSummary($summary)
446
    {
447
        $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...';
448
        $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() :
449
            substr($this->getsummary(), 0, 24) . '...';
450
        $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary,
451
            'self' => $truncmysummary),
452
            'package.xml 1.0 summary "%summary%" does not match "%self%"');
453
    }
454
 
455
    function _differentDescription($description)
456
    {
457
        $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...');
458
        $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() :
459
            substr($this->getdescription(), 0, 24) . '...');
460
        $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription,
461
            'self' => $truncmydescription),
462
            'package.xml 1.0 description "%description%" does not match "%self%"');
463
    }
464
 
465
    function _missingFile($file)
466
    {
467
        $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
468
            'package.xml 1.0 file "%file%" is not present in <contents>');
469
    }
470
 
471
    /**
472
     * WARNING - do not use this function unless you know what you're doing
473
     */
474
    function setRawState($state)
475
    {
476
        if (!isset($this->_packageInfo['stability'])) {
477
            $this->_packageInfo['stability'] = array();
478
        }
479
        $this->_packageInfo['stability']['release'] = $state;
480
    }
481
 
482
    /**
483
     * WARNING - do not use this function unless you know what you're doing
484
     */
485
    function setRawCompatible($compatible)
486
    {
487
        $this->_packageInfo['compatible'] = $compatible;
488
    }
489
 
490
    /**
491
     * WARNING - do not use this function unless you know what you're doing
492
     */
493
    function setRawPackage($package)
494
    {
495
        $this->_packageInfo['name'] = $package;
496
    }
497
 
498
    /**
499
     * WARNING - do not use this function unless you know what you're doing
500
     */
501
    function setRawChannel($channel)
502
    {
503
        $this->_packageInfo['channel'] = $channel;
504
    }
505
 
506
    function setRequestedGroup($group)
507
    {
508
        $this->_requestedGroup = $group;
509
    }
510
 
511
    function getRequestedGroup()
512
    {
513
        if (isset($this->_requestedGroup)) {
514
            return $this->_requestedGroup;
515
        }
516
        return false;
517
    }
518
 
519
    /**
520
     * For saving in the registry.
521
     *
522
     * Set the last version that was installed
523
     * @param string
524
     */
525
    function setLastInstalledVersion($version)
526
    {
527
        $this->_packageInfo['_lastversion'] = $version;
528
    }
529
 
530
    /**
531
     * @return string|false
532
     */
533
    function getLastInstalledVersion()
534
    {
535
        if (isset($this->_packageInfo['_lastversion'])) {
536
            return $this->_packageInfo['_lastversion'];
537
        }
538
        return false;
539
    }
540
 
541
    /**
542
     * Determines whether this package.xml has post-install scripts or not
543
     * @return array|false
544
     */
545
    function listPostinstallScripts()
546
    {
547
        $filelist = $this->getFilelist();
548
        $contents = $this->getContents();
549
        $contents = $contents['dir']['file'];
550
        if (!is_array($contents) || !isset($contents[0])) {
551
            $contents = array($contents);
552
        }
553
        $taskfiles = array();
554
        foreach ($contents as $file) {
555
            $atts = $file['attribs'];
556
            unset($file['attribs']);
557
            if (count($file)) {
558
                $taskfiles[$atts['name']] = $file;
559
            }
560
        }
561
        $common = new PEAR_Common;
562
        $common->debug = $this->_config->get('verbose');
563
        $this->_scripts = array();
564
        $ret = array();
565
        foreach ($taskfiles as $name => $tasks) {
566
            if (!isset($filelist[$name])) {
567
                // ignored files will not be in the filelist
568
                continue;
569
            }
570
            $atts = $filelist[$name];
571
            foreach ($tasks as $tag => $raw) {
572
                $task = $this->getTask($tag);
573
                $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL);
574
                if ($task->isScript()) {
575
                    $ret[] = $filelist[$name]['installed_as'];
576
                }
577
            }
578
        }
579
        if (count($ret)) {
580
            return $ret;
581
        }
582
        return false;
583
    }
584
 
585
    /**
586
     * Initialize post-install scripts for running
587
     *
588
     * This method can be used to detect post-install scripts, as the return value
589
     * indicates whether any exist
590
     * @return bool
591
     */
592
    function initPostinstallScripts()
593
    {
594
        $filelist = $this->getFilelist();
595
        $contents = $this->getContents();
596
        $contents = $contents['dir']['file'];
597
        if (!is_array($contents) || !isset($contents[0])) {
598
            $contents = array($contents);
599
        }
600
        $taskfiles = array();
601
        foreach ($contents as $file) {
602
            $atts = $file['attribs'];
603
            unset($file['attribs']);
604
            if (count($file)) {
605
                $taskfiles[$atts['name']] = $file;
606
            }
607
        }
608
        $common = new PEAR_Common;
609
        $common->debug = $this->_config->get('verbose');
610
        $this->_scripts = array();
611
        foreach ($taskfiles as $name => $tasks) {
612
            if (!isset($filelist[$name])) {
613
                // file was not installed due to installconditions
614
                continue;
615
            }
616
            $atts = $filelist[$name];
617
            foreach ($tasks as $tag => $raw) {
618
                $taskname = $this->getTask($tag);
619
                $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL);
620
                if (!$task->isScript()) {
621
                    continue; // scripts are only handled after installation
622
                }
623
                $lastversion = isset($this->_packageInfo['_lastversion']) ?
624
                    $this->_packageInfo['_lastversion'] : null;
625
                $task->init($raw, $atts, $lastversion);
626
                $res = $task->startSession($this, $atts['installed_as']);
627
                if (!$res) {
628
                    continue; // skip this file
629
                }
630
                if (PEAR::isError($res)) {
631
                    return $res;
632
                }
633
                $assign = &$task;
634
                $this->_scripts[] = &$assign;
635
            }
636
        }
637
        if (count($this->_scripts)) {
638
            return true;
639
        }
640
        return false;
641
    }
642
 
643
    function runPostinstallScripts()
644
    {
645
        if ($this->initPostinstallScripts()) {
646
            $ui = &PEAR_Frontend::singleton();
647
            if ($ui) {
648
                $ui->runPostinstallScripts($this->_scripts, $this);
649
            }
650
        }
651
    }
652
 
653
 
654
    /**
655
     * Convert a recursive set of <dir> and <file> tags into a single <dir> tag with
656
     * <file> tags.
657
     */
658
    function flattenFilelist()
659
    {
660
        if (isset($this->_packageInfo['bundle'])) {
661
            return;
662
        }
663
        $filelist = array();
664
        if (isset($this->_packageInfo['contents']['dir']['dir'])) {
665
            $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']);
666
            if (!isset($filelist[1])) {
667
                $filelist = $filelist[0];
668
            }
669
            $this->_packageInfo['contents']['dir']['file'] = $filelist;
670
            unset($this->_packageInfo['contents']['dir']['dir']);
671
        } else {
672
            // else already flattened but check for baseinstalldir propagation
673
            if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) {
674
                if (isset($this->_packageInfo['contents']['dir']['file'][0])) {
675
                    foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) {
676
                        if (isset($file['attribs']['baseinstalldir'])) {
677
                            continue;
678
                        }
679
                        $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir']
680
                            = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
681
                    }
682
                } else {
683
                    if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) {
684
                       $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir']
685
                            = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
686
                    }
687
                }
688
            }
689
        }
690
    }
691
 
692
    /**
693
     * @param array the final flattened file list
694
     * @param array the current directory being processed
695
     * @param string|false any recursively inherited baeinstalldir attribute
696
     * @param string private recursion variable
697
     * @return array
698
     * @access protected
699
     */
700
    function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '')
701
    {
702
        if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) {
703
            $baseinstall = $dir['attribs']['baseinstalldir'];
704
        }
705
        if (isset($dir['dir'])) {
706
            if (!isset($dir['dir'][0])) {
707
                $dir['dir'] = array($dir['dir']);
708
            }
709
            foreach ($dir['dir'] as $subdir) {
710
                if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) {
711
                    $name = '*unknown*';
712
                } else {
713
                    $name = $subdir['attribs']['name'];
714
                }
715
                $newpath = empty($path) ? $name :
716
                    $path . '/' . $name;
717
                $this->_getFlattenedFilelist($files, $subdir,
718
                    $baseinstall, $newpath);
719
            }
720
        }
721
        if (isset($dir['file'])) {
722
            if (!isset($dir['file'][0])) {
723
                $dir['file'] = array($dir['file']);
724
            }
725
            foreach ($dir['file'] as $file) {
726
                $attrs = $file['attribs'];
727
                $name = $attrs['name'];
728
                if ($baseinstall && !isset($attrs['baseinstalldir'])) {
729
                    $attrs['baseinstalldir'] = $baseinstall;
730
                }
731
                $attrs['name'] = empty($path) ? $name : $path . '/' . $name;
732
                $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
733
                    $attrs['name']);
734
                $file['attribs'] = $attrs;
735
                $files[] = $file;
736
            }
737
        }
738
    }
739
 
740
    function setConfig(&$config)
741
    {
742
        $this->_config = &$config;
743
        $this->_registry = &$config->getRegistry();
744
    }
745
 
746
    function setLogger(&$logger)
747
    {
748
        if (!is_object($logger) || !method_exists($logger, 'log')) {
749
            return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
750
        }
751
        $this->_logger = &$logger;
752
    }
753
 
754
    /**
755
     * WARNING - do not use this function directly unless you know what you're doing
756
     */
757
    function setDeps($deps)
758
    {
759
        $this->_packageInfo['dependencies'] = $deps;
760
    }
761
 
762
    /**
763
     * WARNING - do not use this function directly unless you know what you're doing
764
     */
765
    function setCompatible($compat)
766
    {
767
        $this->_packageInfo['compatible'] = $compat;
768
    }
769
 
770
    function setPackagefile($file, $archive = false)
771
    {
772
        $this->_packageFile = $file;
773
        $this->_archiveFile = $archive ? $archive : $file;
774
    }
775
 
776
    /**
777
     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
778
     * @param boolean determines whether to purge the error stack after retrieving
779
     * @return array
780
     */
781
    function getValidationWarnings($purge = true)
782
    {
783
        return $this->_stack->getErrors($purge);
784
    }
785
 
786
    function getPackageFile()
787
    {
788
        return $this->_packageFile;
789
    }
790
 
791
    function getArchiveFile()
792
    {
793
        return $this->_archiveFile;
794
    }
795
 
796
 
797
    /**
798
     * Directly set the array that defines this packagefile
799
     *
800
     * WARNING: no validation.  This should only be performed by internal methods
801
     * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2
802
     * @param array
803
     */
804
    function fromArray($pinfo)
805
    {
806
        unset($pinfo['old']);
807
        unset($pinfo['xsdversion']);
808
        $this->_incomplete = false;
809
        $this->_packageInfo = $pinfo;
810
    }
811
 
812
    function isIncomplete()
813
    {
814
        return $this->_incomplete;
815
    }
816
 
817
    /**
818
     * @return array
819
     */
820
    function toArray($forreg = false)
821
    {
822
        if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
823
            return false;
824
        }
825
        return $this->getArray($forreg);
826
    }
827
 
828
    function getArray($forReg = false)
829
    {
830
        if ($forReg) {
831
            $arr = $this->_packageInfo;
832
            $arr['old'] = array();
833
            $arr['old']['version'] = $this->getVersion();
834
            $arr['old']['release_date'] = $this->getDate();
835
            $arr['old']['release_state'] = $this->getState();
836
            $arr['old']['release_license'] = $this->getLicense();
837
            $arr['old']['release_notes'] = $this->getNotes();
838
            $arr['old']['release_deps'] = $this->getDeps();
839
            $arr['old']['maintainers'] = $this->getMaintainers();
840
            $arr['xsdversion'] = '2.0';
841
            return $arr;
842
        } else {
843
            $info = $this->_packageInfo;
844
            unset($info['dirtree']);
845
            if (isset($info['_lastversion'])) {
846
                unset($info['_lastversion']);
847
            }
848
            if (isset($info['#binarypackage'])) {
849
                unset($info['#binarypackage']);
850
            }
851
            return $info;
852
        }
853
    }
854
 
855
    function packageInfo($field)
856
    {
857
        $arr = $this->getArray(true);
858
        if ($field == 'state') {
859
            return $arr['stability']['release'];
860
        }
861
        if ($field == 'api-version') {
862
            return $arr['version']['api'];
863
        }
864
        if ($field == 'api-state') {
865
            return $arr['stability']['api'];
866
        }
867
        if (isset($arr['old'][$field])) {
868
            if (!is_string($arr['old'][$field])) {
869
                return null;
870
            }
871
            return $arr['old'][$field];
872
        }
873
        if (isset($arr[$field])) {
874
            if (!is_string($arr[$field])) {
875
                return null;
876
            }
877
            return $arr[$field];
878
        }
879
        return null;
880
    }
881
 
882
    function getName()
883
    {
884
        return $this->getPackage();
885
    }
886
 
887
    function getPackage()
888
    {
889
        if (isset($this->_packageInfo['name'])) {
890
            return $this->_packageInfo['name'];
891
        }
892
        return false;
893
    }
894
 
895
    function getChannel()
896
    {
897
        if (isset($this->_packageInfo['uri'])) {
898
            return '__uri';
899
        }
900
        if (isset($this->_packageInfo['channel'])) {
901
            return strtolower($this->_packageInfo['channel']);
902
        }
903
        return false;
904
    }
905
 
906
    function getUri()
907
    {
908
        if (isset($this->_packageInfo['uri'])) {
909
            return $this->_packageInfo['uri'];
910
        }
911
        return false;
912
    }
913
 
914
    function getExtends()
915
    {
916
        if (isset($this->_packageInfo['extends'])) {
917
            return $this->_packageInfo['extends'];
918
        }
919
        return false;
920
    }
921
 
922
    function getSummary()
923
    {
924
        if (isset($this->_packageInfo['summary'])) {
925
            return $this->_packageInfo['summary'];
926
        }
927
        return false;
928
    }
929
 
930
    function getDescription()
931
    {
932
        if (isset($this->_packageInfo['description'])) {
933
            return $this->_packageInfo['description'];
934
        }
935
        return false;
936
    }
937
 
938
    function getMaintainers($raw = false)
939
    {
940
        if (!isset($this->_packageInfo['lead'])) {
941
            return false;
942
        }
943
        if ($raw) {
944
            $ret = array('lead' => $this->_packageInfo['lead']);
945
            (isset($this->_packageInfo['developer'])) ?
946
                $ret['developer'] = $this->_packageInfo['developer'] :null;
947
            (isset($this->_packageInfo['contributor'])) ?
948
                $ret['contributor'] = $this->_packageInfo['contributor'] :null;
949
            (isset($this->_packageInfo['helper'])) ?
950
                $ret['helper'] = $this->_packageInfo['helper'] :null;
951
            return $ret;
952
        } else {
953
            $ret = array();
954
            $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] :
955
                array($this->_packageInfo['lead']);
956
            foreach ($leads as $lead) {
957
                $s = $lead;
958
                $s['handle'] = $s['user'];
959
                unset($s['user']);
960
                $s['role'] = 'lead';
961
                $ret[] = $s;
962
            }
963
            if (isset($this->_packageInfo['developer'])) {
964
                $leads = isset($this->_packageInfo['developer'][0]) ?
965
                    $this->_packageInfo['developer'] :
966
                    array($this->_packageInfo['developer']);
967
                foreach ($leads as $maintainer) {
968
                    $s = $maintainer;
969
                    $s['handle'] = $s['user'];
970
                    unset($s['user']);
971
                    $s['role'] = 'developer';
972
                    $ret[] = $s;
973
                }
974
            }
975
            if (isset($this->_packageInfo['contributor'])) {
976
                $leads = isset($this->_packageInfo['contributor'][0]) ?
977
                    $this->_packageInfo['contributor'] :
978
                    array($this->_packageInfo['contributor']);
979
                foreach ($leads as $maintainer) {
980
                    $s = $maintainer;
981
                    $s['handle'] = $s['user'];
982
                    unset($s['user']);
983
                    $s['role'] = 'contributor';
984
                    $ret[] = $s;
985
                }
986
            }
987
            if (isset($this->_packageInfo['helper'])) {
988
                $leads = isset($this->_packageInfo['helper'][0]) ?
989
                    $this->_packageInfo['helper'] :
990
                    array($this->_packageInfo['helper']);
991
                foreach ($leads as $maintainer) {
992
                    $s = $maintainer;
993
                    $s['handle'] = $s['user'];
994
                    unset($s['user']);
995
                    $s['role'] = 'helper';
996
                    $ret[] = $s;
997
                }
998
            }
999
            return $ret;
1000
        }
1001
        return false;
1002
    }
1003
 
1004
    function getLeads()
1005
    {
1006
        if (isset($this->_packageInfo['lead'])) {
1007
            return $this->_packageInfo['lead'];
1008
        }
1009
        return false;
1010
    }
1011
 
1012
    function getDevelopers()
1013
    {
1014
        if (isset($this->_packageInfo['developer'])) {
1015
            return $this->_packageInfo['developer'];
1016
        }
1017
        return false;
1018
    }
1019
 
1020
    function getContributors()
1021
    {
1022
        if (isset($this->_packageInfo['contributor'])) {
1023
            return $this->_packageInfo['contributor'];
1024
        }
1025
        return false;
1026
    }
1027
 
1028
    function getHelpers()
1029
    {
1030
        if (isset($this->_packageInfo['helper'])) {
1031
            return $this->_packageInfo['helper'];
1032
        }
1033
        return false;
1034
    }
1035
 
1036
    function setDate($date)
1037
    {
1038
        if (!isset($this->_packageInfo['date'])) {
1039
            // ensure that the extends tag is set up in the right location
1040
            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
1041
                array('time', 'version',
1042
                    'stability', 'license', 'notes', 'contents', 'compatible',
1043
                    'dependencies', 'providesextension', 'srcpackage', 'srcuri',
1044
                    'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
1045
                    'zendextbinrelease', 'bundle', 'changelog'), array(), 'date');
1046
        }
1047
        $this->_packageInfo['date'] = $date;
1048
        $this->_isValid = 0;
1049
    }
1050
 
1051
    function setTime($time)
1052
    {
1053
        $this->_isValid = 0;
1054
        if (!isset($this->_packageInfo['time'])) {
1055
            // ensure that the time tag is set up in the right location
1056
            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
1057
                    array('version',
1058
                    'stability', 'license', 'notes', 'contents', 'compatible',
1059
                    'dependencies', 'providesextension', 'srcpackage', 'srcuri',
1060
                    'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
1061
                    'zendextbinrelease', 'bundle', 'changelog'), $time, 'time');
1062
        }
1063
        $this->_packageInfo['time'] = $time;
1064
    }
1065
 
1066
    function getDate()
1067
    {
1068
        if (isset($this->_packageInfo['date'])) {
1069
            return $this->_packageInfo['date'];
1070
        }
1071
        return false;
1072
    }
1073
 
1074
    function getTime()
1075
    {
1076
        if (isset($this->_packageInfo['time'])) {
1077
            return $this->_packageInfo['time'];
1078
        }
1079
        return false;
1080
    }
1081
 
1082
    /**
1083
     * @param package|api version category to return
1084
     */
1085
    function getVersion($key = 'release')
1086
    {
1087
        if (isset($this->_packageInfo['version'][$key])) {
1088
            return $this->_packageInfo['version'][$key];
1089
        }
1090
        return false;
1091
    }
1092
 
1093
    function getStability()
1094
    {
1095
        if (isset($this->_packageInfo['stability'])) {
1096
            return $this->_packageInfo['stability'];
1097
        }
1098
        return false;
1099
    }
1100
 
1101
    function getState($key = 'release')
1102
    {
1103
        if (isset($this->_packageInfo['stability'][$key])) {
1104
            return $this->_packageInfo['stability'][$key];
1105
        }
1106
        return false;
1107
    }
1108
 
1109
    function getLicense($raw = false)
1110
    {
1111
        if (isset($this->_packageInfo['license'])) {
1112
            if ($raw) {
1113
                return $this->_packageInfo['license'];
1114
            }
1115
            if (is_array($this->_packageInfo['license'])) {
1116
                return $this->_packageInfo['license']['_content'];
1117
            } else {
1118
                return $this->_packageInfo['license'];
1119
            }
1120
        }
1121
        return false;
1122
    }
1123
 
1124
    function getLicenseLocation()
1125
    {
1126
        if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) {
1127
            return false;
1128
        }
1129
        return $this->_packageInfo['license']['attribs'];
1130
    }
1131
 
1132
    function getNotes()
1133
    {
1134
        if (isset($this->_packageInfo['notes'])) {
1135
            return $this->_packageInfo['notes'];
1136
        }
1137
        return false;
1138
    }
1139
 
1140
    /**
1141
     * Return the <usesrole> tag contents, if any
1142
     * @return array|false
1143
     */
1144
    function getUsesrole()
1145
    {
1146
        if (isset($this->_packageInfo['usesrole'])) {
1147
            return $this->_packageInfo['usesrole'];
1148
        }
1149
        return false;
1150
    }
1151
 
1152
    /**
1153
     * Return the <usestask> tag contents, if any
1154
     * @return array|false
1155
     */
1156
    function getUsestask()
1157
    {
1158
        if (isset($this->_packageInfo['usestask'])) {
1159
            return $this->_packageInfo['usestask'];
1160
        }
1161
        return false;
1162
    }
1163
 
1164
    /**
1165
     * This should only be used to retrieve filenames and install attributes
1166
     */
1167
    function getFilelist($preserve = false)
1168
    {
1169
        if (isset($this->_packageInfo['filelist']) && !$preserve) {
1170
            return $this->_packageInfo['filelist'];
1171
        }
1172
        $this->flattenFilelist();
1173
        if ($contents = $this->getContents()) {
1174
            $ret = array();
1175
            if (!isset($contents['dir'])) {
1176
                return false;
1177
            }
1178
            if (!isset($contents['dir']['file'][0])) {
1179
                $contents['dir']['file'] = array($contents['dir']['file']);
1180
            }
1181
            foreach ($contents['dir']['file'] as $file) {
1182
                $name = $file['attribs']['name'];
1183
                if (!$preserve) {
1184
                    $file = $file['attribs'];
1185
                }
1186
                $ret[$name] = $file;
1187
            }
1188
            if (!$preserve) {
1189
                $this->_packageInfo['filelist'] = $ret;
1190
            }
1191
            return $ret;
1192
        }
1193
        return false;
1194
    }
1195
 
1196
    /**
1197
     * Return configure options array, if any
1198
     *
1199
     * @return array|false
1200
     */
1201
    function getConfigureOptions()
1202
    {
1203
        if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
1204
            return false;
1205
        }
1206
        $releases = $this->getReleases();
1207
        if (isset($releases[0])) {
1208
            $releases = $releases[0];
1209
        }
1210
        if (isset($releases['configureoption'])) {
1211
            if (!isset($releases['configureoption'][0])) {
1212
                $releases['configureoption'] = array($releases['configureoption']);
1213
            }
1214
            for ($i = 0; $i < count($releases['configureoption']); $i++) {
1215
                $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs'];
1216
            }
1217
            return $releases['configureoption'];
1218
        }
1219
        return false;
1220
    }
1221
 
1222
    /**
1223
     * This is only used at install-time, after all serialization
1224
     * is over.
1225
     */
1226
    function resetFilelist()
1227
    {
1228
        $this->_packageInfo['filelist'] = array();
1229
    }
1230
 
1231
    /**
1232
     * Retrieve a list of files that should be installed on this computer
1233
     * @return array
1234
     */
1235
    function getInstallationFilelist($forfilecheck = false)
1236
    {
1237
        $contents = $this->getFilelist(true);
1238
        if (isset($contents['dir']['attribs']['baseinstalldir'])) {
1239
            $base = $contents['dir']['attribs']['baseinstalldir'];
1240
        }
1241
        if (isset($this->_packageInfo['bundle'])) {
1242
            return PEAR::raiseError(
1243
                'Exception: bundles should be handled in download code only');
1244
        }
1245
        $release = $this->getReleases();
1246
        if ($release) {
1247
            if (!isset($release[0])) {
1248
                if (!isset($release['installconditions']) && !isset($release['filelist'])) {
1249
                    if ($forfilecheck) {
1250
                        return $this->getFilelist();
1251
                    }
1252
                    return $contents;
1253
                }
1254
                $release = array($release);
1255
            }
1256
            $depchecker = &$this->getPEARDependency2($this->_config, array(),
1257
                array('channel' => $this->getChannel(), 'package' => $this->getPackage()),
1258
                PEAR_VALIDATE_INSTALLING);
1259
            foreach ($release as $instance) {
1260
                if (isset($instance['installconditions'])) {
1261
                    $installconditions = $instance['installconditions'];
1262
                    if (is_array($installconditions)) {
1263
                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1264
                        foreach ($installconditions as $type => $conditions) {
1265
                            if (!isset($conditions[0])) {
1266
                                $conditions = array($conditions);
1267
                            }
1268
                            foreach ($conditions as $condition) {
1269
                                $ret = $depchecker->{"validate{$type}Dependency"}($condition);
1270
                                if (PEAR::isError($ret)) {
1271
                                    PEAR::popErrorHandling();
1272
                                    continue 3; // skip this release
1273
                                }
1274
                            }
1275
                        }
1276
                        PEAR::popErrorHandling();
1277
                    }
1278
                }
1279
                // this is the release to use
1280
                if (isset($instance['filelist'])) {
1281
                    // ignore files
1282
                    if (isset($instance['filelist']['ignore'])) {
1283
                        $ignore = isset($instance['filelist']['ignore'][0]) ?
1284
                            $instance['filelist']['ignore'] :
1285
                            array($instance['filelist']['ignore']);
1286
                        foreach ($ignore as $ig) {
1287
                            unset ($contents[$ig['attribs']['name']]);
1288
                        }
1289
                    }
1290
                    // install files as this name
1291
                    if (isset($instance['filelist']['install'])) {
1292
                        $installas = isset($instance['filelist']['install'][0]) ?
1293
                            $instance['filelist']['install'] :
1294
                            array($instance['filelist']['install']);
1295
                        foreach ($installas as $as) {
1296
                            $contents[$as['attribs']['name']]['attribs']['install-as'] =
1297
                                $as['attribs']['as'];
1298
                        }
1299
                    }
1300
                }
1301
                if ($forfilecheck) {
1302
                    foreach ($contents as $file => $attrs) {
1303
                        $contents[$file] = $attrs['attribs'];
1304
                    }
1305
                }
1306
                return $contents;
1307
            }
1308
        } else { // simple release - no installconditions or install-as
1309
            if ($forfilecheck) {
1310
                return $this->getFilelist();
1311
            }
1312
            return $contents;
1313
        }
1314
        // no releases matched
1315
        return PEAR::raiseError('No releases in package.xml matched the existing operating ' .
1316
            'system, extensions installed, or architecture, cannot install');
1317
    }
1318
 
1319
    /**
1320
     * This is only used at install-time, after all serialization
1321
     * is over.
1322
     * @param string file name
1323
     * @param string installed path
1324
     */
1325
    function setInstalledAs($file, $path)
1326
    {
1327
        if ($path) {
1328
            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
1329
        }
1330
        unset($this->_packageInfo['filelist'][$file]['installed_as']);
1331
    }
1332
 
1333
    function getInstalledLocation($file)
1334
    {
1335
        if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) {
1336
            return $this->_packageInfo['filelist'][$file]['installed_as'];
1337
        }
1338
        return false;
1339
    }
1340
 
1341
    /**
1342
     * This is only used at install-time, after all serialization
1343
     * is over.
1344
     */
1345
    function installedFile($file, $atts)
1346
    {
1347
        if (isset($this->_packageInfo['filelist'][$file])) {
1348
            $this->_packageInfo['filelist'][$file] =
1349
                array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
1350
        } else {
1351
            $this->_packageInfo['filelist'][$file] = $atts['attribs'];
1352
        }
1353
    }
1354
 
1355
    /**
1356
     * Retrieve the contents tag
1357
     */
1358
    function getContents()
1359
    {
1360
        if (isset($this->_packageInfo['contents'])) {
1361
            return $this->_packageInfo['contents'];
1362
        }
1363
        return false;
1364
    }
1365
 
1366
    /**
1367
     * @param string full path to file
1368
     * @param string attribute name
1369
     * @param string attribute value
1370
     * @param int risky but fast - use this to choose a file based on its position in the list
1371
     *            of files.  Index is zero-based like PHP arrays.
1372
     * @return bool success of operation
1373
     */
1374
    function setFileAttribute($filename, $attr, $value, $index = false)
1375
    {
1376
        $this->_isValid = 0;
1377
        if (in_array($attr, array('role', 'name', 'baseinstalldir'))) {
1378
            $this->_filesValid = false;
1379
        }
1380
        if ($index !== false &&
1381
              isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) {
1382
            $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value;
1383
            return true;
1384
        }
1385
        if (!isset($this->_packageInfo['contents']['dir']['file'])) {
1386
            return false;
1387
        }
1388
        $files = $this->_packageInfo['contents']['dir']['file'];
1389
        if (!isset($files[0])) {
1390
            $files = array($files);
1391
            $ind = false;
1392
        } else {
1393
            $ind = true;
1394
        }
1395
        foreach ($files as $i => $file) {
1396
            if (isset($file['attribs'])) {
1397
                if ($file['attribs']['name'] == $filename) {
1398
                    if ($ind) {
1399
                        $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value;
1400
                    } else {
1401
                        $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value;
1402
                    }
1403
                    return true;
1404
                }
1405
            }
1406
        }
1407
        return false;
1408
    }
1409
 
1410
    function setDirtree($path)
1411
    {
1412
        if (!isset($this->_packageInfo['dirtree'])) {
1413
            $this->_packageInfo['dirtree'] = array();
1414
        }
1415
        $this->_packageInfo['dirtree'][$path] = true;
1416
    }
1417
 
1418
    function getDirtree()
1419
    {
1420
        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
1421
            return $this->_packageInfo['dirtree'];
1422
        }
1423
        return false;
1424
    }
1425
 
1426
    function resetDirtree()
1427
    {
1428
        unset($this->_packageInfo['dirtree']);
1429
    }
1430
 
1431
    /**
1432
     * Determines whether this package claims it is compatible with the version of
1433
     * the package that has a recommended version dependency
1434
     * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package
1435
     * @return boolean
1436
     */
1437
    function isCompatible($pf)
1438
    {
1439
        if (!isset($this->_packageInfo['compatible'])) {
1440
            return false;
1441
        }
1442
        if (!isset($this->_packageInfo['channel'])) {
1443
            return false;
1444
        }
1445
        $me = $pf->getVersion();
1446
        $compatible = $this->_packageInfo['compatible'];
1447
        if (!isset($compatible[0])) {
1448
            $compatible = array($compatible);
1449
        }
1450
        $found = false;
1451
        foreach ($compatible as $info) {
1452
            if (strtolower($info['name']) == strtolower($pf->getPackage())) {
1453
                if (strtolower($info['channel']) == strtolower($pf->getChannel())) {
1454
                    $found = true;
1455
                    break;
1456
                }
1457
            }
1458
        }
1459
        if (!$found) {
1460
            return false;
1461
        }
1462
        if (isset($info['exclude'])) {
1463
            if (!isset($info['exclude'][0])) {
1464
                $info['exclude'] = array($info['exclude']);
1465
            }
1466
            foreach ($info['exclude'] as $exclude) {
1467
                if (version_compare($me, $exclude, '==')) {
1468
                    return false;
1469
                }
1470
            }
1471
        }
1472
        if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) {
1473
            return true;
1474
        }
1475
        return false;
1476
    }
1477
 
1478
    /**
1479
     * @return array|false
1480
     */
1481
    function getCompatible()
1482
    {
1483
        if (isset($this->_packageInfo['compatible'])) {
1484
            return $this->_packageInfo['compatible'];
1485
        }
1486
        return false;
1487
    }
1488
 
1489
    function getDependencies()
1490
    {
1491
        if (isset($this->_packageInfo['dependencies'])) {
1492
            return $this->_packageInfo['dependencies'];
1493
        }
1494
        return false;
1495
    }
1496
 
1497
    function isSubpackageOf($p)
1498
    {
1499
        return $p->isSubpackage($this);
1500
    }
1501
 
1502
    /**
1503
     * Determines whether the passed in package is a subpackage of this package.
1504
     *
1505
     * No version checking is done, only name verification.
1506
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
1507
     * @return bool
1508
     */
1509
    function isSubpackage($p)
1510
    {
1511
        $sub = array();
1512
        if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) {
1513
            $sub = $this->_packageInfo['dependencies']['required']['subpackage'];
1514
            if (!isset($sub[0])) {
1515
                $sub = array($sub);
1516
            }
1517
        }
1518
        if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) {
1519
            $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage'];
1520
            if (!isset($sub1[0])) {
1521
                $sub1 = array($sub1);
1522
            }
1523
            $sub = array_merge($sub, $sub1);
1524
        }
1525
        if (isset($this->_packageInfo['dependencies']['group'])) {
1526
            $group = $this->_packageInfo['dependencies']['group'];
1527
            if (!isset($group[0])) {
1528
                $group = array($group);
1529
            }
1530
            foreach ($group as $deps) {
1531
                if (isset($deps['subpackage'])) {
1532
                    $sub2 = $deps['subpackage'];
1533
                    if (!isset($sub2[0])) {
1534
                        $sub2 = array($sub2);
1535
                    }
1536
                    $sub = array_merge($sub, $sub2);
1537
                }
1538
            }
1539
        }
1540
        foreach ($sub as $dep) {
1541
            if (strtolower($dep['name']) == strtolower($p->getPackage())) {
1542
                if (isset($dep['channel'])) {
1543
                    if (strtolower($dep['channel']) == strtolower($p->getChannel())) {
1544
                        return true;
1545
                    }
1546
                } else {
1547
                    if ($dep['uri'] == $p->getURI()) {
1548
                        return true;
1549
                    }
1550
                }
1551
            }
1552
        }
1553
        return false;
1554
    }
1555
 
1556
    function dependsOn($package, $channel)
1557
    {
1558
        if (!($deps = $this->getDependencies())) {
1559
            return false;
1560
        }
1561
        foreach (array('package', 'subpackage') as $type) {
1562
            foreach (array('required', 'optional') as $needed) {
1563
                if (isset($deps[$needed][$type])) {
1564
                    if (!isset($deps[$needed][$type][0])) {
1565
                        $deps[$needed][$type] = array($deps[$needed][$type]);
1566
                    }
1567
                    foreach ($deps[$needed][$type] as $dep) {
1568
                        $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
1569
                        if (strtolower($dep['name']) == strtolower($package) &&
1570
                              $depchannel == $channel) {
1571
                            return true;
1572
                        }
1573
                    }
1574
                }
1575
            }
1576
            if (isset($deps['group'])) {
1577
                if (!isset($deps['group'][0])) {
1578
                    $dep['group'] = array($deps['group']);
1579
                }
1580
                foreach ($deps['group'] as $group) {
1581
                    if (isset($group[$type])) {
1582
                        if (!is_array($group[$type])) {
1583
                            $group[$type] = array($group[$type]);
1584
                        }
1585
                        foreach ($group[$type] as $dep) {
1586
                            $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
1587
                            if (strtolower($dep['name']) == strtolower($package) &&
1588
                                  $depchannel == $channel) {
1589
                                return true;
1590
                            }
1591
                        }
1592
                    }
1593
                }
1594
            }
1595
        }
1596
        return false;
1597
    }
1598
 
1599
    /**
1600
     * Get the contents of a dependency group
1601
     * @param string
1602
     * @return array|false
1603
     */
1604
    function getDependencyGroup($name)
1605
    {
1606
        $name = strtolower($name);
1607
        if (!isset($this->_packageInfo['dependencies']['group'])) {
1608
            return false;
1609
        }
1610
        $groups = $this->_packageInfo['dependencies']['group'];
1611
        if (!isset($groups[0])) {
1612
            $groups = array($groups);
1613
        }
1614
        foreach ($groups as $group) {
1615
            if (strtolower($group['attribs']['name']) == $name) {
1616
                return $group;
1617
            }
1618
        }
1619
        return false;
1620
    }
1621
 
1622
    /**
1623
     * Retrieve a partial package.xml 1.0 representation of dependencies
1624
     *
1625
     * a very limited representation of dependencies is returned by this method.
1626
     * The <exclude> tag for excluding certain versions of a dependency is
1627
     * completely ignored.  In addition, dependency groups are ignored, with the
1628
     * assumption that all dependencies in dependency groups are also listed in
1629
     * the optional group that work with all dependency groups
1630
     * @param boolean return package.xml 2.0 <dependencies> tag
1631
     * @return array|false
1632
     */
1633
    function getDeps($raw = false, $nopearinstaller = false)
1634
    {
1635
        if (isset($this->_packageInfo['dependencies'])) {
1636
            if ($raw) {
1637
                return $this->_packageInfo['dependencies'];
1638
            }
1639
            $ret = array();
1640
            $map = array(
1641
                'php' => 'php',
1642
                'package' => 'pkg',
1643
                'subpackage' => 'pkg',
1644
                'extension' => 'ext',
1645
                'os' => 'os',
1646
                'pearinstaller' => 'pkg',
1647
                );
1648
            foreach (array('required', 'optional') as $type) {
1649
                $optional = ($type == 'optional') ? 'yes' : 'no';
1650
                if (!isset($this->_packageInfo['dependencies'][$type])
1651
                    || empty($this->_packageInfo['dependencies'][$type])) {
1652
                    continue;
1653
                }
1654
                foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) {
1655
                    if ($dtype == 'pearinstaller' && $nopearinstaller) {
1656
                        continue;
1657
                    }
1658
                    if (!isset($deps[0])) {
1659
                        $deps = array($deps);
1660
                    }
1661
                    foreach ($deps as $dep) {
1662
                        if (!isset($map[$dtype])) {
1663
                            // no support for arch type
1664
                            continue;
1665
                        }
1666
                        if ($dtype == 'pearinstaller') {
1667
                            $dep['name'] = 'PEAR';
1668
                            $dep['channel'] = 'pear.php.net';
1669
                        }
1670
                        $s = array('type' => $map[$dtype]);
1671
                        if (isset($dep['channel'])) {
1672
                            $s['channel'] = $dep['channel'];
1673
                        }
1674
                        if (isset($dep['uri'])) {
1675
                            $s['uri'] = $dep['uri'];
1676
                        }
1677
                        if (isset($dep['name'])) {
1678
                            $s['name'] = $dep['name'];
1679
                        }
1680
                        if (isset($dep['conflicts'])) {
1681
                            $s['rel'] = 'not';
1682
                        } else {
1683
                            if (!isset($dep['min']) &&
1684
                                  !isset($dep['max'])) {
1685
                                $s['rel'] = 'has';
1686
                                $s['optional'] = $optional;
1687
                            } elseif (isset($dep['min']) &&
1688
                                  isset($dep['max'])) {
1689
                                $s['rel'] = 'ge';
1690
                                $s1 = $s;
1691
                                $s1['rel'] = 'le';
1692
                                $s['version'] = $dep['min'];
1693
                                $s1['version'] = $dep['max'];
1694
                                if (isset($dep['channel'])) {
1695
                                    $s1['channel'] = $dep['channel'];
1696
                                }
1697
                                if ($dtype != 'php') {
1698
                                    $s['name'] = $dep['name'];
1699
                                    $s1['name'] = $dep['name'];
1700
                                }
1701
                                $s['optional'] = $optional;
1702
                                $s1['optional'] = $optional;
1703
                                $ret[] = $s1;
1704
                            } elseif (isset($dep['min'])) {
1705
                                if (isset($dep['exclude']) &&
1706
                                      $dep['exclude'] == $dep['min']) {
1707
                                    $s['rel'] = 'gt';
1708
                                } else {
1709
                                    $s['rel'] = 'ge';
1710
                                }
1711
                                $s['version'] = $dep['min'];
1712
                                $s['optional'] = $optional;
1713
                                if ($dtype != 'php') {
1714
                                    $s['name'] = $dep['name'];
1715
                                }
1716
                            } elseif (isset($dep['max'])) {
1717
                                if (isset($dep['exclude']) &&
1718
                                      $dep['exclude'] == $dep['max']) {
1719
                                    $s['rel'] = 'lt';
1720
                                } else {
1721
                                    $s['rel'] = 'le';
1722
                                }
1723
                                $s['version'] = $dep['max'];
1724
                                $s['optional'] = $optional;
1725
                                if ($dtype != 'php') {
1726
                                    $s['name'] = $dep['name'];
1727
                                }
1728
                            }
1729
                        }
1730
                        $ret[] = $s;
1731
                    }
1732
                }
1733
            }
1734
            if (count($ret)) {
1735
                return $ret;
1736
            }
1737
        }
1738
        return false;
1739
    }
1740
 
1741
    /**
1742
     * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false
1743
     */
1744
    function getPackageType()
1745
    {
1746
        if (isset($this->_packageInfo['phprelease'])) {
1747
            return 'php';
1748
        }
1749
        if (isset($this->_packageInfo['extsrcrelease'])) {
1750
            return 'extsrc';
1751
        }
1752
        if (isset($this->_packageInfo['extbinrelease'])) {
1753
            return 'extbin';
1754
        }
1755
        if (isset($this->_packageInfo['zendextsrcrelease'])) {
1756
            return 'zendextsrc';
1757
        }
1758
        if (isset($this->_packageInfo['zendextbinrelease'])) {
1759
            return 'zendextbin';
1760
        }
1761
        if (isset($this->_packageInfo['bundle'])) {
1762
            return 'bundle';
1763
        }
1764
        return false;
1765
    }
1766
 
1767
    /**
1768
     * @return array|false
1769
     */
1770
    function getReleases()
1771
    {
1772
        $type = $this->getPackageType();
1773
        if ($type != 'bundle') {
1774
            $type .= 'release';
1775
        }
1776
        if ($this->getPackageType() && isset($this->_packageInfo[$type])) {
1777
            return $this->_packageInfo[$type];
1778
        }
1779
        return false;
1780
    }
1781
 
1782
    /**
1783
     * @return array
1784
     */
1785
    function getChangelog()
1786
    {
1787
        if (isset($this->_packageInfo['changelog'])) {
1788
            return $this->_packageInfo['changelog'];
1789
        }
1790
        return false;
1791
    }
1792
 
1793
    function hasDeps()
1794
    {
1795
        return isset($this->_packageInfo['dependencies']);
1796
    }
1797
 
1798
    function getPackagexmlVersion()
1799
    {
1800
        if (isset($this->_packageInfo['zendextsrcrelease'])) {
1801
            return '2.1';
1802
        }
1803
        if (isset($this->_packageInfo['zendextbinrelease'])) {
1804
            return '2.1';
1805
        }
1806
        return '2.0';
1807
    }
1808
 
1809
    /**
1810
     * @return array|false
1811
     */
1812
    function getSourcePackage()
1813
    {
1814
        if (isset($this->_packageInfo['extbinrelease']) ||
1815
              isset($this->_packageInfo['zendextbinrelease'])) {
1816
            return array('channel' => $this->_packageInfo['srcchannel'],
1817
                         'package' => $this->_packageInfo['srcpackage']);
1818
        }
1819
        return false;
1820
    }
1821
 
1822
    function getBundledPackages()
1823
    {
1824
        if (isset($this->_packageInfo['bundle'])) {
1825
            return $this->_packageInfo['contents']['bundledpackage'];
1826
        }
1827
        return false;
1828
    }
1829
 
1830
    function getLastModified()
1831
    {
1832
        if (isset($this->_packageInfo['_lastmodified'])) {
1833
            return $this->_packageInfo['_lastmodified'];
1834
        }
1835
        return false;
1836
    }
1837
 
1838
    /**
1839
     * Get the contents of a file listed within the package.xml
1840
     * @param string
1841
     * @return string
1842
     */
1843
    function getFileContents($file)
1844
    {
1845
        if ($this->_archiveFile == $this->_packageFile) { // unpacked
1846
            $dir = dirname($this->_packageFile);
1847
            $file = $dir . DIRECTORY_SEPARATOR . $file;
1848
            $file = str_replace(array('/', '\\'),
1849
                array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
1850
            if (file_exists($file) && is_readable($file)) {
1851
                return implode('', file($file));
1852
            }
1853
        } else { // tgz
1854
            $tar = &new Archive_Tar($this->_archiveFile);
1855
            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
1856
            if ($file != 'package.xml' && $file != 'package2.xml') {
1857
                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
1858
            }
1859
            $file = $tar->extractInString($file);
1860
            $tar->popErrorHandling();
1861
            if (PEAR::isError($file)) {
1862
                return PEAR::raiseError("Cannot locate file '$file' in archive");
1863
            }
1864
            return $file;
1865
        }
1866
    }
1867
 
1868
    function &getRW()
1869
    {
1870
        if (!class_exists('PEAR_PackageFile_v2_rw')) {
1871
            require_once 'PEAR/PackageFile/v2/rw.php';
1872
        }
1873
        $a = new PEAR_PackageFile_v2_rw;
1874
        foreach (get_object_vars($this) as $name => $unused) {
1875
            if (!isset($this->$name)) {
1876
                continue;
1877
            }
1878
            if ($name == '_config' || $name == '_logger'|| $name == '_registry' ||
1879
                  $name == '_stack') {
1880
                $a->$name = &$this->$name;
1881
            } else {
1882
                $a->$name = $this->$name;
1883
            }
1884
        }
1885
        return $a;
1886
    }
1887
 
1888
    function &getDefaultGenerator()
1889
    {
1890
        if (!class_exists('PEAR_PackageFile_Generator_v2')) {
1891
            require_once 'PEAR/PackageFile/Generator/v2.php';
1892
        }
1893
        $a = &new PEAR_PackageFile_Generator_v2($this);
1894
        return $a;
1895
    }
1896
 
1897
    function analyzeSourceCode($file, $string = false)
1898
    {
1899
        if (!isset($this->_v2Validator) ||
1900
              !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
1901
            if (!class_exists('PEAR_PackageFile_v2_Validator')) {
1902
                require_once 'PEAR/PackageFile/v2/Validator.php';
1903
            }
1904
            $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
1905
        }
1906
        return $this->_v2Validator->analyzeSourceCode($file, $string);
1907
    }
1908
 
1909
    function validate($state = PEAR_VALIDATE_NORMAL)
1910
    {
1911
        if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
1912
            return false;
1913
        }
1914
        if (!isset($this->_v2Validator) ||
1915
              !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
1916
            if (!class_exists('PEAR_PackageFile_v2_Validator')) {
1917
                require_once 'PEAR/PackageFile/v2/Validator.php';
1918
            }
1919
            $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
1920
        }
1921
        if (isset($this->_packageInfo['xsdversion'])) {
1922
            unset($this->_packageInfo['xsdversion']);
1923
        }
1924
        return $this->_v2Validator->validate($this, $state);
1925
    }
1926
 
1927
    function getTasksNs()
1928
    {
1929
        if (!isset($this->_tasksNs)) {
1930
            if (isset($this->_packageInfo['attribs'])) {
1931
                foreach ($this->_packageInfo['attribs'] as $name => $value) {
1932
                    if ($value == 'http://pear.php.net/dtd/tasks-1.0') {
1933
                        $this->_tasksNs = str_replace('xmlns:', '', $name);
1934
                        break;
1935
                    }
1936
                }
1937
            }
1938
        }
1939
        return $this->_tasksNs;
1940
    }
1941
 
1942
    /**
1943
     * Determine whether a task name is a valid task.  Custom tasks may be defined
1944
     * using subdirectories by putting a "-" in the name, as in <tasks:mycustom-task>
1945
     *
1946
     * Note that this method will auto-load the task class file and test for the existence
1947
     * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class
1948
     * PEAR_Task_mycustom_task
1949
     * @param string
1950
     * @return boolean
1951
     */
1952
    function getTask($task)
1953
    {
1954
        $this->getTasksNs();
1955
        // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace
1956
        $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task);
1957
        $taskfile = str_replace(' ', '/', ucwords($task));
1958
        $task = str_replace(array(' ', '/'), '_', ucwords($task));
1959
        if (class_exists("PEAR_Task_$task")) {
1960
            return "PEAR_Task_$task";
1961
        }
1962
        $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true);
1963
        if ($fp) {
1964
            fclose($fp);
1965
            require_once "PEAR/Task/$taskfile.php";
1966
            return "PEAR_Task_$task";
1967
        }
1968
        return false;
1969
    }
1970
 
1971
    /**
1972
     * Key-friendly array_splice
1973
     * @param tagname to splice a value in before
1974
     * @param mixed the value to splice in
1975
     * @param string the new tag name
1976
     */
1977
    function _ksplice($array, $key, $value, $newkey)
1978
    {
1979
        $offset = array_search($key, array_keys($array));
1980
        $after = array_slice($array, $offset);
1981
        $before = array_slice($array, 0, $offset);
1982
        $before[$newkey] = $value;
1983
        return array_merge($before, $after);
1984
    }
1985
 
1986
    /**
1987
     * @param array a list of possible keys, in the order they may occur
1988
     * @param mixed contents of the new package.xml tag
1989
     * @param string tag name
1990
     * @access private
1991
     */
1992
    function _insertBefore($array, $keys, $contents, $newkey)
1993
    {
1994
        foreach ($keys as $key) {
1995
            if (isset($array[$key])) {
1996
                return $array = $this->_ksplice($array, $key, $contents, $newkey);
1997
            }
1998
        }
1999
        $array[$newkey] = $contents;
2000
        return $array;
2001
    }
2002
 
2003
    /**
2004
     * @param subsection of {@link $_packageInfo}
2005
     * @param array|string tag contents
2006
     * @param array format:
2007
     * <pre>
2008
     * array(
2009
     *   tagname => array(list of tag names that follow this one),
2010
     *   childtagname => array(list of child tag names that follow this one),
2011
     * )
2012
     * </pre>
2013
     *
2014
     * This allows construction of nested tags
2015
     * @access private
2016
     */
2017
    function _mergeTag($manip, $contents, $order)
2018
    {
2019
        if (count($order)) {
2020
            foreach ($order as $tag => $curorder) {
2021
                if (!isset($manip[$tag])) {
2022
                    // ensure that the tag is set up
2023
                    $manip = $this->_insertBefore($manip, $curorder, array(), $tag);
2024
                }
2025
                if (count($order) > 1) {
2026
                    $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1));
2027
                    return $manip;
2028
                }
2029
            }
2030
        } else {
2031
            return $manip;
2032
        }
2033
        if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) {
2034
            $manip[$tag][] = $contents;
2035
        } else {
2036
            if (!count($manip[$tag])) {
2037
                $manip[$tag] = $contents;
2038
            } else {
2039
                $manip[$tag] = array($manip[$tag]);
2040
                $manip[$tag][] = $contents;
2041
            }
2042
        }
2043
        return $manip;
2044
    }
2045
}
2046
?>