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_DependencyDB, advanced installed packages dependency database
4
 *
5
 * PHP versions 4 and 5
6
 *
7
 * @category   pear
8
 * @package    PEAR
9
 * @author     Tomas V. V. Cox <cox@idecnet.com>
10
 * @author     Greg Beaver <cellog@php.net>
187 mathias 11
 * @copyright  1997-2009 The Authors
12
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
94 jpm 13
 * @link       http://pear.php.net/package/PEAR
14
 * @since      File available since Release 1.4.0a1
15
 */
16
 
17
/**
18
 * Needed for error handling
19
 */
20
require_once 'PEAR.php';
21
require_once 'PEAR/Config.php';
22
 
23
$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
24
/**
25
 * Track dependency relationships between installed packages
26
 * @category   pear
27
 * @package    PEAR
28
 * @author     Greg Beaver <cellog@php.net>
29
 * @author     Tomas V.V.Cox <cox@idec.net.com>
187 mathias 30
 * @copyright  1997-2009 The Authors
31
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
32
 * @version    Release: 1.10.1
94 jpm 33
 * @link       http://pear.php.net/package/PEAR
34
 * @since      Class available since Release 1.4.0a1
35
 */
36
class PEAR_DependencyDB
37
{
38
    // {{{ properties
39
 
40
    /**
41
     * This is initialized by {@link setConfig()}
42
     * @var PEAR_Config
43
     * @access private
44
     */
45
    var $_config;
46
    /**
47
     * This is initialized by {@link setConfig()}
48
     * @var PEAR_Registry
49
     * @access private
50
     */
51
    var $_registry;
52
    /**
53
     * Filename of the dependency DB (usually .depdb)
54
     * @var string
55
     * @access private
56
     */
57
    var $_depdb = false;
58
    /**
59
     * File name of the lockfile (usually .depdblock)
60
     * @var string
61
     * @access private
62
     */
63
    var $_lockfile = false;
64
    /**
65
     * Open file resource for locking the lockfile
66
     * @var resource|false
67
     * @access private
68
     */
69
    var $_lockFp = false;
70
    /**
71
     * API version of this class, used to validate a file on-disk
72
     * @var string
73
     * @access private
74
     */
75
    var $_version = '1.0';
76
    /**
77
     * Cached dependency database file
78
     * @var array|null
79
     * @access private
80
     */
81
    var $_cache;
82
 
83
    // }}}
84
    // {{{ & singleton()
85
 
86
    /**
87
     * Get a raw dependency database.  Calls setConfig() and assertDepsDB()
88
     * @param PEAR_Config
89
     * @param string|false full path to the dependency database, or false to use default
90
     * @return PEAR_DependencyDB|PEAR_Error
91
     */
187 mathias 92
    public static function &singleton(&$config, $depdb = false)
94 jpm 93
    {
187 mathias 94
        $phpdir = $config->get('php_dir', null, 'pear.php.net');
95
        if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) {
94 jpm 96
            $a = new PEAR_DependencyDB;
187 mathias 97
            $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a;
94 jpm 98
            $a->setConfig($config, $depdb);
187 mathias 99
            $e = $a->assertDepsDB();
100
            if (PEAR::isError($e)) {
94 jpm 101
                return $e;
102
            }
103
        }
187 mathias 104
 
105
        return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir];
94 jpm 106
    }
107
 
108
    /**
109
     * Set up the registry/location of dependency DB
110
     * @param PEAR_Config|false
111
     * @param string|false full path to the dependency database, or false to use default
112
     */
113
    function setConfig(&$config, $depdb = false)
114
    {
115
        if (!$config) {
116
            $this->_config = &PEAR_Config::singleton();
117
        } else {
118
            $this->_config = &$config;
119
        }
187 mathias 120
 
94 jpm 121
        $this->_registry = &$this->_config->getRegistry();
122
        if (!$depdb) {
187 mathias 123
            $dir = $this->_config->get('metadata_dir', null, 'pear.php.net');
124
            if (!$dir) {
125
                $dir = $this->_config->get('php_dir', null, 'pear.php.net');
126
            }
127
            $this->_depdb =  $dir . DIRECTORY_SEPARATOR . '.depdb';
94 jpm 128
        } else {
129
            $this->_depdb = $depdb;
130
        }
187 mathias 131
 
94 jpm 132
        $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
133
    }
134
    // }}}
135
 
136
    function hasWriteAccess()
137
    {
138
        if (!file_exists($this->_depdb)) {
139
            $dir = $this->_depdb;
140
            while ($dir && $dir != '.') {
141
                $dir = dirname($dir); // cd ..
142
                if ($dir != '.' && file_exists($dir)) {
143
                    if (is_writeable($dir)) {
144
                        return true;
145
                    }
187 mathias 146
 
147
                    return false;
94 jpm 148
                }
149
            }
187 mathias 150
 
94 jpm 151
            return false;
152
        }
187 mathias 153
 
94 jpm 154
        return is_writeable($this->_depdb);
155
    }
156
 
157
    // {{{ assertDepsDB()
158
 
159
    /**
160
     * Create the dependency database, if it doesn't exist.  Error if the database is
161
     * newer than the code reading it.
162
     * @return void|PEAR_Error
163
     */
164
    function assertDepsDB()
165
    {
166
        if (!is_file($this->_depdb)) {
167
            $this->rebuildDB();
187 mathias 168
            return;
94 jpm 169
        }
187 mathias 170
 
171
        $depdb = $this->_getDepDB();
172
        // Datatype format has been changed, rebuild the Deps DB
173
        if ($depdb['_version'] < $this->_version) {
174
            $this->rebuildDB();
175
        }
176
 
177
        if ($depdb['_version']{0} > $this->_version{0}) {
178
            return PEAR::raiseError('Dependency database is version ' .
179
                $depdb['_version'] . ', and we are version ' .
180
                $this->_version . ', cannot continue');
181
        }
94 jpm 182
    }
183
 
184
    /**
185
     * Get a list of installed packages that depend on this package
186
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
187
     * @return array|false
188
     */
189
    function getDependentPackages(&$pkg)
190
    {
191
        $data = $this->_getDepDB();
192
        if (is_object($pkg)) {
193
            $channel = strtolower($pkg->getChannel());
194
            $package = strtolower($pkg->getPackage());
195
        } else {
196
            $channel = strtolower($pkg['channel']);
197
            $package = strtolower($pkg['package']);
198
        }
187 mathias 199
 
94 jpm 200
        if (isset($data['packages'][$channel][$package])) {
201
            return $data['packages'][$channel][$package];
202
        }
187 mathias 203
 
94 jpm 204
        return false;
205
    }
206
 
207
    /**
208
     * Get a list of the actual dependencies of installed packages that depend on
209
     * a package.
210
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
211
     * @return array|false
212
     */
213
    function getDependentPackageDependencies(&$pkg)
214
    {
215
        $data = $this->_getDepDB();
216
        if (is_object($pkg)) {
217
            $channel = strtolower($pkg->getChannel());
218
            $package = strtolower($pkg->getPackage());
219
        } else {
220
            $channel = strtolower($pkg['channel']);
221
            $package = strtolower($pkg['package']);
222
        }
187 mathias 223
 
94 jpm 224
        $depend = $this->getDependentPackages($pkg);
225
        if (!$depend) {
226
            return false;
227
        }
187 mathias 228
 
94 jpm 229
        $dependencies = array();
230
        foreach ($depend as $info) {
231
            $temp = $this->getDependencies($info);
232
            foreach ($temp as $dep) {
187 mathias 233
                if (
234
                    isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) &&
235
                    strtolower($dep['dep']['channel']) == $channel &&
236
                    strtolower($dep['dep']['name']) == $package
237
                ) {
94 jpm 238
                    if (!isset($dependencies[$info['channel']])) {
239
                        $dependencies[$info['channel']] = array();
240
                    }
187 mathias 241
 
94 jpm 242
                    if (!isset($dependencies[$info['channel']][$info['package']])) {
243
                        $dependencies[$info['channel']][$info['package']] = array();
244
                    }
245
                    $dependencies[$info['channel']][$info['package']][] = $dep;
246
                }
247
            }
248
        }
187 mathias 249
 
94 jpm 250
        return $dependencies;
251
    }
252
 
253
    /**
254
     * Get a list of dependencies of this installed package
255
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
256
     * @return array|false
257
     */
258
    function getDependencies(&$pkg)
259
    {
260
        if (is_object($pkg)) {
261
            $channel = strtolower($pkg->getChannel());
262
            $package = strtolower($pkg->getPackage());
263
        } else {
264
            $channel = strtolower($pkg['channel']);
265
            $package = strtolower($pkg['package']);
266
        }
187 mathias 267
 
94 jpm 268
        $data = $this->_getDepDB();
269
        if (isset($data['dependencies'][$channel][$package])) {
270
            return $data['dependencies'][$channel][$package];
271
        }
187 mathias 272
 
94 jpm 273
        return false;
274
    }
275
 
276
    /**
277
     * Determine whether $parent depends on $child, near or deep
278
     * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
279
     * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
280
     */
281
    function dependsOn($parent, $child)
282
    {
283
        $c = array();
284
        $this->_getDepDB();
285
        return $this->_dependsOn($parent, $child, $c);
286
    }
187 mathias 287
 
94 jpm 288
    function _dependsOn($parent, $child, &$checked)
289
    {
290
        if (is_object($parent)) {
291
            $channel = strtolower($parent->getChannel());
292
            $package = strtolower($parent->getPackage());
293
        } else {
294
            $channel = strtolower($parent['channel']);
295
            $package = strtolower($parent['package']);
296
        }
187 mathias 297
 
94 jpm 298
        if (is_object($child)) {
299
            $depchannel = strtolower($child->getChannel());
300
            $deppackage = strtolower($child->getPackage());
301
        } else {
302
            $depchannel = strtolower($child['channel']);
303
            $deppackage = strtolower($child['package']);
304
        }
187 mathias 305
 
94 jpm 306
        if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
307
            return false; // avoid endless recursion
308
        }
187 mathias 309
 
94 jpm 310
        $checked[$channel][$package][$depchannel][$deppackage] = true;
311
        if (!isset($this->_cache['dependencies'][$channel][$package])) {
312
            return false;
313
        }
187 mathias 314
 
94 jpm 315
        foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
316
            if (isset($info['dep']['uri'])) {
317
                if (is_object($child)) {
318
                    if ($info['dep']['uri'] == $child->getURI()) {
319
                        return true;
320
                    }
321
                } elseif (isset($child['uri'])) {
322
                    if ($info['dep']['uri'] == $child['uri']) {
323
                        return true;
324
                    }
325
                }
326
                return false;
327
            }
187 mathias 328
 
329
            if (strtolower($info['dep']['channel']) == $depchannel &&
330
                  strtolower($info['dep']['name']) == $deppackage) {
94 jpm 331
                return true;
332
            }
333
        }
187 mathias 334
 
94 jpm 335
        foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
336
            if (isset($info['dep']['uri'])) {
337
                if ($this->_dependsOn(array(
338
                        'uri' => $info['dep']['uri'],
339
                        'package' => $info['dep']['name']), $child, $checked)) {
340
                    return true;
341
                }
342
            } else {
343
                if ($this->_dependsOn(array(
344
                        'channel' => $info['dep']['channel'],
345
                        'package' => $info['dep']['name']), $child, $checked)) {
346
                    return true;
347
                }
348
            }
349
        }
187 mathias 350
 
94 jpm 351
        return false;
352
    }
353
 
354
    /**
355
     * Register dependencies of a package that is being installed or upgraded
356
     * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
357
     */
358
    function installPackage(&$package)
359
    {
360
        $data = $this->_getDepDB();
361
        unset($this->_cache);
362
        $this->_setPackageDeps($data, $package);
363
        $this->_writeDepDB($data);
364
    }
365
 
366
    /**
367
     * Remove dependencies of a package that is being uninstalled, or upgraded.
368
     *
369
     * Upgraded packages first uninstall, then install
370
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
371
     *        indices 'channel' and 'package'
372
     */
373
    function uninstallPackage(&$pkg)
374
    {
375
        $data = $this->_getDepDB();
376
        unset($this->_cache);
377
        if (is_object($pkg)) {
378
            $channel = strtolower($pkg->getChannel());
379
            $package = strtolower($pkg->getPackage());
380
        } else {
381
            $channel = strtolower($pkg['channel']);
382
            $package = strtolower($pkg['package']);
383
        }
187 mathias 384
 
94 jpm 385
        if (!isset($data['dependencies'][$channel][$package])) {
386
            return true;
387
        }
187 mathias 388
 
94 jpm 389
        foreach ($data['dependencies'][$channel][$package] as $dep) {
187 mathias 390
            $found      = false;
391
            $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']);
392
            $depname    = strtolower($dep['dep']['name']);
393
            if (isset($data['packages'][$depchannel][$depname])) {
394
                foreach ($data['packages'][$depchannel][$depname] as $i => $info) {
395
                    if ($info['channel'] == $channel && $info['package'] == $package) {
94 jpm 396
                        $found = true;
397
                        break;
398
                    }
399
                }
400
            }
187 mathias 401
 
94 jpm 402
            if ($found) {
187 mathias 403
                unset($data['packages'][$depchannel][$depname][$i]);
404
                if (!count($data['packages'][$depchannel][$depname])) {
405
                    unset($data['packages'][$depchannel][$depname]);
94 jpm 406
                    if (!count($data['packages'][$depchannel])) {
407
                        unset($data['packages'][$depchannel]);
408
                    }
409
                } else {
187 mathias 410
                    $data['packages'][$depchannel][$depname] =
411
                        array_values($data['packages'][$depchannel][$depname]);
94 jpm 412
                }
413
            }
414
        }
187 mathias 415
 
94 jpm 416
        unset($data['dependencies'][$channel][$package]);
417
        if (!count($data['dependencies'][$channel])) {
418
            unset($data['dependencies'][$channel]);
419
        }
187 mathias 420
 
94 jpm 421
        if (!count($data['dependencies'])) {
422
            unset($data['dependencies']);
423
        }
187 mathias 424
 
94 jpm 425
        if (!count($data['packages'])) {
426
            unset($data['packages']);
427
        }
187 mathias 428
 
94 jpm 429
        $this->_writeDepDB($data);
430
    }
431
 
432
    /**
433
     * Rebuild the dependency DB by reading registry entries.
434
     * @return true|PEAR_Error
435
     */
436
    function rebuildDB()
437
    {
438
        $depdb = array('_version' => $this->_version);
439
        if (!$this->hasWriteAccess()) {
440
            // allow startup for read-only with older Registry
441
            return $depdb;
442
        }
187 mathias 443
 
94 jpm 444
        $packages = $this->_registry->listAllPackages();
187 mathias 445
        if (PEAR::isError($packages)) {
446
            return $packages;
447
        }
448
 
94 jpm 449
        foreach ($packages as $channel => $ps) {
450
            foreach ($ps as $package) {
451
                $package = $this->_registry->getPackage($package, $channel);
187 mathias 452
                if (PEAR::isError($package)) {
453
                    return $package;
454
                }
94 jpm 455
                $this->_setPackageDeps($depdb, $package);
456
            }
457
        }
187 mathias 458
 
94 jpm 459
        $error = $this->_writeDepDB($depdb);
460
        if (PEAR::isError($error)) {
461
            return $error;
462
        }
187 mathias 463
 
94 jpm 464
        $this->_cache = $depdb;
465
        return true;
466
    }
467
 
468
    /**
469
     * Register usage of the dependency DB to prevent race conditions
470
     * @param int one of the LOCK_* constants
471
     * @return true|PEAR_Error
472
     * @access private
473
     */
474
    function _lock($mode = LOCK_EX)
475
    {
187 mathias 476
        if (stristr(php_uname(), 'Windows 9')) {
477
            return true;
478
        }
479
 
480
        if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
481
            // XXX does not check type of lock (LOCK_SH/LOCK_EX)
482
            return true;
483
        }
484
 
485
        $open_mode = 'w';
486
        // XXX People reported problems with LOCK_SH and 'w'
487
        if ($mode === LOCK_SH) {
488
            if (!file_exists($this->_lockfile)) {
489
                touch($this->_lockfile);
490
            } elseif (!is_file($this->_lockfile)) {
491
                return PEAR::raiseError('could not create Dependency lock file, ' .
492
                    'it exists and is not a regular file');
94 jpm 493
            }
187 mathias 494
            $open_mode = 'r';
495
        }
496
 
497
        if (!is_resource($this->_lockFp)) {
498
            $this->_lockFp = @fopen($this->_lockfile, $open_mode);
499
        }
500
 
501
        if (!is_resource($this->_lockFp)) {
502
            return PEAR::raiseError("could not create Dependency lock file" .
503
                                     (isset($php_errormsg) ? ": " . $php_errormsg : ""));
504
        }
505
 
506
        if (!(int)flock($this->_lockFp, $mode)) {
507
            switch ($mode) {
508
                case LOCK_SH: $str = 'shared';    break;
509
                case LOCK_EX: $str = 'exclusive'; break;
510
                case LOCK_UN: $str = 'unlock';    break;
511
                default:      $str = 'unknown';   break;
94 jpm 512
            }
513
 
187 mathias 514
            return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
94 jpm 515
        }
187 mathias 516
 
94 jpm 517
        return true;
518
    }
519
 
520
    /**
521
     * Release usage of dependency DB
522
     * @return true|PEAR_Error
523
     * @access private
524
     */
525
    function _unlock()
526
    {
527
        $ret = $this->_lock(LOCK_UN);
528
        if (is_resource($this->_lockFp)) {
529
            fclose($this->_lockFp);
530
        }
531
        $this->_lockFp = null;
532
        return $ret;
533
    }
534
 
535
    /**
536
     * Load the dependency database from disk, or return the cache
537
     * @return array|PEAR_Error
538
     */
539
    function _getDepDB()
540
    {
541
        if (!$this->hasWriteAccess()) {
542
            return array('_version' => $this->_version);
543
        }
187 mathias 544
 
94 jpm 545
        if (isset($this->_cache)) {
546
            return $this->_cache;
547
        }
187 mathias 548
 
94 jpm 549
        if (!$fp = fopen($this->_depdb, 'r')) {
550
            $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
551
            return $err;
552
        }
187 mathias 553
 
94 jpm 554
        clearstatcache();
555
        fclose($fp);
556
        $data = unserialize(file_get_contents($this->_depdb));
557
        $this->_cache = $data;
558
        return $data;
559
    }
560
 
561
    /**
562
     * Write out the dependency database to disk
563
     * @param array the database
564
     * @return true|PEAR_Error
565
     * @access private
566
     */
567
    function _writeDepDB(&$deps)
568
    {
569
        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
570
            return $e;
571
        }
187 mathias 572
 
94 jpm 573
        if (!$fp = fopen($this->_depdb, 'wb')) {
574
            $this->_unlock();
575
            return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
576
        }
187 mathias 577
 
94 jpm 578
        fwrite($fp, serialize($deps));
579
        fclose($fp);
580
        $this->_unlock();
581
        $this->_cache = $deps;
582
        return true;
583
    }
584
 
585
    /**
586
     * Register all dependencies from a package in the dependencies database, in essence
587
     * "installing" the package's dependency information
588
     * @param array the database
589
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
590
     * @access private
591
     */
592
    function _setPackageDeps(&$data, &$pkg)
593
    {
594
        $pkg->setConfig($this->_config);
595
        if ($pkg->getPackagexmlVersion() == '1.0') {
596
            $gen = &$pkg->getDefaultGenerator();
597
            $deps = $gen->dependenciesToV2();
598
        } else {
599
            $deps = $pkg->getDeps(true);
600
        }
187 mathias 601
 
94 jpm 602
        if (!$deps) {
603
            return;
604
        }
187 mathias 605
 
94 jpm 606
        if (!is_array($data)) {
607
            $data = array();
608
        }
187 mathias 609
 
94 jpm 610
        if (!isset($data['dependencies'])) {
611
            $data['dependencies'] = array();
612
        }
187 mathias 613
 
614
        $channel = strtolower($pkg->getChannel());
615
        $package = strtolower($pkg->getPackage());
616
 
617
        if (!isset($data['dependencies'][$channel])) {
618
            $data['dependencies'][$channel] = array();
94 jpm 619
        }
187 mathias 620
 
621
        $data['dependencies'][$channel][$package] = array();
94 jpm 622
        if (isset($deps['required']['package'])) {
623
            if (!isset($deps['required']['package'][0])) {
624
                $deps['required']['package'] = array($deps['required']['package']);
625
            }
187 mathias 626
 
94 jpm 627
            foreach ($deps['required']['package'] as $dep) {
628
                $this->_registerDep($data, $pkg, $dep, 'required');
629
            }
630
        }
187 mathias 631
 
94 jpm 632
        if (isset($deps['optional']['package'])) {
633
            if (!isset($deps['optional']['package'][0])) {
634
                $deps['optional']['package'] = array($deps['optional']['package']);
635
            }
187 mathias 636
 
94 jpm 637
            foreach ($deps['optional']['package'] as $dep) {
638
                $this->_registerDep($data, $pkg, $dep, 'optional');
639
            }
640
        }
187 mathias 641
 
94 jpm 642
        if (isset($deps['required']['subpackage'])) {
643
            if (!isset($deps['required']['subpackage'][0])) {
644
                $deps['required']['subpackage'] = array($deps['required']['subpackage']);
645
            }
187 mathias 646
 
94 jpm 647
            foreach ($deps['required']['subpackage'] as $dep) {
648
                $this->_registerDep($data, $pkg, $dep, 'required');
649
            }
650
        }
187 mathias 651
 
94 jpm 652
        if (isset($deps['optional']['subpackage'])) {
653
            if (!isset($deps['optional']['subpackage'][0])) {
654
                $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
655
            }
187 mathias 656
 
94 jpm 657
            foreach ($deps['optional']['subpackage'] as $dep) {
658
                $this->_registerDep($data, $pkg, $dep, 'optional');
659
            }
660
        }
187 mathias 661
 
94 jpm 662
        if (isset($deps['group'])) {
663
            if (!isset($deps['group'][0])) {
664
                $deps['group'] = array($deps['group']);
665
            }
187 mathias 666
 
94 jpm 667
            foreach ($deps['group'] as $group) {
668
                if (isset($group['package'])) {
669
                    if (!isset($group['package'][0])) {
670
                        $group['package'] = array($group['package']);
671
                    }
187 mathias 672
 
94 jpm 673
                    foreach ($group['package'] as $dep) {
674
                        $this->_registerDep($data, $pkg, $dep, 'optional',
675
                            $group['attribs']['name']);
676
                    }
677
                }
187 mathias 678
 
94 jpm 679
                if (isset($group['subpackage'])) {
680
                    if (!isset($group['subpackage'][0])) {
681
                        $group['subpackage'] = array($group['subpackage']);
682
                    }
187 mathias 683
 
94 jpm 684
                    foreach ($group['subpackage'] as $dep) {
685
                        $this->_registerDep($data, $pkg, $dep, 'optional',
686
                            $group['attribs']['name']);
687
                    }
688
                }
689
            }
690
        }
187 mathias 691
 
692
        if ($data['dependencies'][$channel][$package] == array()) {
693
            unset($data['dependencies'][$channel][$package]);
694
            if (!count($data['dependencies'][$channel])) {
695
                unset($data['dependencies'][$channel]);
94 jpm 696
            }
697
        }
698
    }
699
 
700
    /**
701
     * @param array the database
702
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
703
     * @param array the specific dependency
704
     * @param required|optional whether this is a required or an optional dep
705
     * @param string|false dependency group this dependency is from, or false for ordinary dep
706
     */
707
    function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
708
    {
709
        $info = array(
187 mathias 710
            'dep'   => $dep,
711
            'type'  => $type,
712
            'group' => $group
713
        );
94 jpm 714
 
187 mathias 715
        $dep  = array_map('strtolower', $dep);
716
        $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
94 jpm 717
        if (!isset($data['dependencies'])) {
718
            $data['dependencies'] = array();
719
        }
187 mathias 720
 
721
        $channel = strtolower($pkg->getChannel());
722
        $package = strtolower($pkg->getPackage());
723
 
724
        if (!isset($data['dependencies'][$channel])) {
725
            $data['dependencies'][$channel] = array();
94 jpm 726
        }
187 mathias 727
 
728
        if (!isset($data['dependencies'][$channel][$package])) {
729
            $data['dependencies'][$channel][$package] = array();
94 jpm 730
        }
187 mathias 731
 
732
        $data['dependencies'][$channel][$package][] = $info;
733
        if (isset($data['packages'][$depchannel][$dep['name']])) {
94 jpm 734
            $found = false;
187 mathias 735
            foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) {
736
                if ($p['channel'] == $channel && $p['package'] == $package) {
94 jpm 737
                    $found = true;
738
                    break;
739
                }
740
            }
741
        } else {
742
            if (!isset($data['packages'])) {
743
                $data['packages'] = array();
744
            }
187 mathias 745
 
746
            if (!isset($data['packages'][$depchannel])) {
747
                $data['packages'][$depchannel] = array();
94 jpm 748
            }
187 mathias 749
 
750
            if (!isset($data['packages'][$depchannel][$dep['name']])) {
751
                $data['packages'][$depchannel][$dep['name']] = array();
94 jpm 752
            }
187 mathias 753
 
754
            $found = false;
94 jpm 755
        }
187 mathias 756
 
757
        if (!$found) {
758
            $data['packages'][$depchannel][$dep['name']][] = array(
759
                'channel' => $channel,
760
                'package' => $package
761
            );
762
        }
94 jpm 763
    }
764
}