Source for file DependencyDB.php
Documentation is available at DependencyDB.php
* PEAR_DependencyDB, advanced installed packages dependency database
* @author Tomas V. V. Cox <cox@idecnet.com>
* @author Greg Beaver <cellog@php.net>
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: DependencyDB.php 313023 2011-07-06 19:17:11Z dufuz $
* @link http://pear.php.net/package/PEAR
* @since File available since Release 1.4.0a1
* Needed for error handling
require_once 'PEAR/Config.php';
$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array ();
* Track dependency relationships between installed packages
* @author Greg Beaver <cellog@php.net>
* @author Tomas V.V.Cox <cox@idec.net.com>
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 1.9.4
* @link http://pear.php.net/package/PEAR
* @since Class available since Release 1.4.0a1
* This is initialized by {@link setConfig()}
* This is initialized by {@link setConfig()}
* Filename of the dependency DB (usually .depdb)
* File name of the lockfile (usually .depdblock)
* Open file resource for locking the lockfile
* API version of this class, used to validate a file on-disk
* Cached dependency database file
* Get a raw dependency database. Calls setConfig() and assertDepsDB()
* @param string|falsefull path to the dependency database, or false to use default
* @return PEAR_DependencyDB|PEAR_Error
function &singleton(&$config, $depdb = false )
$phpdir = $config->get ('php_dir', null , 'pear.php.net');
if (!isset ($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) {
$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a;
$a->setConfig ($config, $depdb);
return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir];
* Set up the registry/location of dependency DB
* @param PEAR_Config|false
* @param string|falsefull path to the dependency database, or false to use default
$this->_config = &$config;
$this->_depdb = $this->_config->get('php_dir', null , 'pear.php.net') .
DIRECTORY_SEPARATOR . '.depdb';
$this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
while ($dir && $dir != '.') {
* Create the dependency database, if it doesn't exist. Error if the database is
* newer than the code reading it.
* @return void|PEAR_Error
$depdb = $this->_getDepDB ();
// Datatype format has been changed, rebuild the Deps DB
if ($depdb['_version'] < $this->_version) {
if ($depdb['_version']{0 } > $this->_version{0 }) {
return PEAR ::raiseError ('Dependency database is version ' .
$depdb['_version'] . ', and we are version ' .
$this->_version . ', cannot continue');
* Get a list of installed packages that depend on this package
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
$data = $this->_getDepDB ();
if (isset ($data['packages'][$channel][$package])) {
return $data['packages'][$channel][$package];
* Get a list of the actual dependencies of installed packages that depend on
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
$data = $this->_getDepDB ();
foreach ($depend as $info) {
foreach ($temp as $dep) {
isset ($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) &&
if (!isset ($dependencies[$info['channel']])) {
$dependencies[$info['channel']] = array ();
if (!isset ($dependencies[$info['channel']][$info['package']])) {
$dependencies[$info['channel']][$info['package']] = array ();
$dependencies[$info['channel']][$info['package']][] = $dep;
* Get a list of dependencies of this installed package
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
$data = $this->_getDepDB ();
if (isset ($data['dependencies'][$channel][$package])) {
return $data['dependencies'][$channel][$package];
* Determine whether $parent depends on $child, near or deep
* @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
* @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
return $this->_dependsOn ($parent, $child, $c);
function _dependsOn ($parent, $child, &$checked)
if (isset ($checked[$channel][$package][$depchannel][$deppackage])) {
return false; // avoid endless recursion
$checked[$channel][$package][$depchannel][$deppackage] = true;
if (!isset ($this->_cache ['dependencies'][$channel][$package])) {
foreach ($this->_cache ['dependencies'][$channel][$package] as $info) {
if (isset ($info['dep']['uri'])) {
if ($info['dep']['uri'] == $child->getURI ()) {
} elseif (isset ($child['uri'])) {
if ($info['dep']['uri'] == $child['uri']) {
if (strtolower($info['dep']['channel']) == $depchannel &&
strtolower($info['dep']['name']) == $deppackage) {
foreach ($this->_cache ['dependencies'][$channel][$package] as $info) {
if (isset ($info['dep']['uri'])) {
if ($this->_dependsOn (array (
'uri' => $info['dep']['uri'],
'package' => $info['dep']['name']), $child, $checked)) {
if ($this->_dependsOn (array (
'channel' => $info['dep']['channel'],
'package' => $info['dep']['name']), $child, $checked)) {
* Register dependencies of a package that is being installed or upgraded
* @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
$data = $this->_getDepDB ();
$this->_setPackageDeps ($data, $package);
$this->_writeDepDB ($data);
* Remove dependencies of a package that is being uninstalled, or upgraded.
* Upgraded packages first uninstall, then install
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|arrayIf an array, then it must have
* indices 'channel' and 'package'
$data = $this->_getDepDB ();
if (!isset ($data['dependencies'][$channel][$package])) {
foreach ($data['dependencies'][$channel][$package] as $dep) {
$depchannel = isset ($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']);
if (isset ($data['packages'][$depchannel][$depname])) {
foreach ($data['packages'][$depchannel][$depname] as $i => $info) {
if ($info['channel'] == $channel && $info['package'] == $package) {
unset ($data['packages'][$depchannel][$depname][$i]);
if (!count($data['packages'][$depchannel][$depname])) {
unset ($data['packages'][$depchannel][$depname]);
if (!count($data['packages'][$depchannel])) {
unset ($data['packages'][$depchannel]);
$data['packages'][$depchannel][$depname] =
unset ($data['dependencies'][$channel][$package]);
if (!count($data['dependencies'][$channel])) {
unset ($data['dependencies'][$channel]);
if (!count($data['dependencies'])) {
unset ($data['dependencies']);
if (!count($data['packages'])) {
unset ($data['packages']);
$this->_writeDepDB ($data);
* Rebuild the dependency DB by reading registry entries.
* @return true|PEAR_Error
$depdb = array ('_version' => $this->_version );
// allow startup for read-only with older Registry
$packages = $this->_registry ->listAllPackages ();
foreach ($packages as $channel => $ps) {
foreach ($ps as $package) {
$package = $this->_registry ->getPackage ($package, $channel);
$this->_setPackageDeps ($depdb, $package);
$error = $this->_writeDepDB ($depdb);
* Register usage of the dependency DB to prevent race conditions
* @param int one of the LOCK_* constants
* @return true|PEAR_Error
function _lock ($mode = LOCK_EX )
// XXX does not check type of lock (LOCK_SH/LOCK_EX)
// XXX People reported problems with LOCK_SH and 'w'
} elseif (!is_file($this->_lockfile )) {
'it exists and is not a regular file');
$this->_lockFp = @fopen($this->_lockfile , $open_mode);
(isset ($php_errormsg) ? ": " . $php_errormsg : ""));
if (!(int) flock($this->_lockFp , $mode)) {
case LOCK_SH: $str = 'shared'; break;
case LOCK_EX: $str = 'exclusive'; break;
case LOCK_UN: $str = 'unlock'; break;
default: $str = 'unknown'; break;
return PEAR::raiseError(" could not acquire $str lock ($this->_lockfile)" );
* Release usage of dependency DB
* @return true|PEAR_Error
$ret = $this->_lock (LOCK_UN );
* Load the dependency database from disk, or return the cache
* @return array|PEAR_Error
return array ('_version' => $this->_version );
if (isset ($this->_cache )) {
if (!$fp = fopen($this->_depdb , 'r')) {
$err = PEAR::raiseError("Could not open dependencies file `". $this->_depdb. "'");
* Write out the dependency database to disk
* @param array the database
* @return true|PEAR_Error
function _writeDepDB (&$deps)
if (!$fp = fopen($this->_depdb , 'wb')) {
return PEAR::raiseError("Could not open dependencies file `". $this->_depdb. "' for writing");
* Register all dependencies from a package in the dependencies database, in essence
* "installing" the package's dependency information
* @param array the database
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
function _setPackageDeps (&$data, &$pkg)
if ($pkg->getPackagexmlVersion () == '1.0') {
$gen = &$pkg->getDefaultGenerator ();
$deps = $gen->dependenciesToV2 ();
$deps = $pkg->getDeps (true );
if (!isset ($data['dependencies'])) {
$data['dependencies'] = array ();
if (!isset ($data['dependencies'][$channel])) {
$data['dependencies'][$channel] = array ();
$data['dependencies'][$channel][$package] = array ();
if (isset ($deps['required']['package'])) {
if (!isset ($deps['required']['package'][0 ])) {
$deps['required']['package'] = array ($deps['required']['package']);
foreach ($deps['required']['package'] as $dep) {
$this->_registerDep ($data, $pkg, $dep, 'required');
if (isset ($deps['optional']['package'])) {
if (!isset ($deps['optional']['package'][0 ])) {
$deps['optional']['package'] = array ($deps['optional']['package']);
foreach ($deps['optional']['package'] as $dep) {
$this->_registerDep ($data, $pkg, $dep, 'optional');
if (isset ($deps['required']['subpackage'])) {
if (!isset ($deps['required']['subpackage'][0 ])) {
$deps['required']['subpackage'] = array ($deps['required']['subpackage']);
foreach ($deps['required']['subpackage'] as $dep) {
$this->_registerDep ($data, $pkg, $dep, 'required');
if (isset ($deps['optional']['subpackage'])) {
if (!isset ($deps['optional']['subpackage'][0 ])) {
$deps['optional']['subpackage'] = array ($deps['optional']['subpackage']);
foreach ($deps['optional']['subpackage'] as $dep) {
$this->_registerDep ($data, $pkg, $dep, 'optional');
if (isset ($deps['group'])) {
if (!isset ($deps['group'][0 ])) {
$deps['group'] = array ($deps['group']);
foreach ($deps['group'] as $group) {
if (isset ($group['package'])) {
if (!isset ($group['package'][0 ])) {
$group['package'] = array ($group['package']);
foreach ($group['package'] as $dep) {
$this->_registerDep ($data, $pkg, $dep, 'optional',
$group['attribs']['name']);
if (isset ($group['subpackage'])) {
if (!isset ($group['subpackage'][0 ])) {
$group['subpackage'] = array ($group['subpackage']);
foreach ($group['subpackage'] as $dep) {
$this->_registerDep ($data, $pkg, $dep, 'optional',
$group['attribs']['name']);
if ($data['dependencies'][$channel][$package] == array ()) {
unset ($data['dependencies'][$channel][$package]);
if (!count($data['dependencies'][$channel])) {
unset ($data['dependencies'][$channel]);
* @param array the database
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
* @param array the specific dependency
* @param required|optionalwhether this is a required or an optional dep
* @param string|falsedependency group this dependency is from, or false for ordinary dep
function _registerDep (&$data, &$pkg, $dep, $type, $group = false )
$depchannel = isset ($dep['channel']) ? $dep['channel'] : '__uri';
if (!isset ($data['dependencies'])) {
$data['dependencies'] = array ();
if (!isset ($data['dependencies'][$channel])) {
$data['dependencies'][$channel] = array ();
if (!isset ($data['dependencies'][$channel][$package])) {
$data['dependencies'][$channel][$package] = array ();
$data['dependencies'][$channel][$package][] = $info;
if (isset ($data['packages'][$depchannel][$dep['name']])) {
foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) {
if ($p['channel'] == $channel && $p['package'] == $package) {
if (!isset ($data['packages'])) {
$data['packages'] = array ();
if (!isset ($data['packages'][$depchannel])) {
$data['packages'][$depchannel] = array ();
if (!isset ($data['packages'][$depchannel][$dep['name']])) {
$data['packages'][$depchannel][$dep['name']] = array ();
$data['packages'][$depchannel][$dep['name']][] = array (
Documentation generated on Wed, 06 Jul 2011 23:30:43 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.
|