]> granicus.if.org Git - php/commitdiff
Experimental dependencies database handling functions
authorTomas V.V.Cox <cox@php.net>
Mon, 7 Jul 2003 15:44:07 +0000 (15:44 +0000)
committerTomas V.V.Cox <cox@php.net>
Mon, 7 Jul 2003 15:44:07 +0000 (15:44 +0000)
(not yet in production)

pear/PEAR/DependencyDB.php [new file with mode: 0644]

diff --git a/pear/PEAR/DependencyDB.php b/pear/PEAR/DependencyDB.php
new file mode 100644 (file)
index 0000000..58c218f
--- /dev/null
@@ -0,0 +1,307 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license,       |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available through the world-wide-web at the following url:           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors:   Tomas V.V.Cox <cox@idecnet.com>                           |
+// |                                                                      |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+/**
+Experimental dependencies database handling functions (not yet in production)
+
+<?php
+include './DependencyDB.php';
+PEAR::setErrorHandling(PEAR_ERROR_DIE);
+$dep = PEAR_DependencyDB::singleton('./test.deps', '/home/cox/www/include/pear');
+//$dep->rebuildDB();
+$a = $dep->checkAction('uninstall', 'net_socket');
+print_r($a);
+?>
+
+**/
+
+require_once 'PEAR.php';
+require_once 'PEAR/Registry.php';
+require_once 'PEAR/Dependency.php';
+
+class PEAR_DependencyDB extends PEAR
+{
+    var $pear_reg = false;
+    var $pear_dep = false;
+    var $depdb_file = false;
+    var $lockfile = false;
+    var $lock_fp = false;
+    var $depdb_version = '1.0';
+
+    function &singleton($depdb_file, $reg_file)
+    {
+        $obj = new PEAR_DependencyDB;
+        $reg = &new PEAR_Registry($reg_file);
+        $obj->pear_reg = $reg;
+        $obj->lockfile = $reg->lockfile;
+        $obj->pear_dep = new PEAR_Dependency($reg);
+        $obj->depdb_file = $depdb_file;
+        $obj->assertDepsDB();
+        return $obj;
+    }
+
+    function assertDepsDB()
+    {
+        if (!is_file($this->depdb_file)) {
+            $this->rebuildDB();
+        } else {
+            $depdb = $this->_getDepDB();
+            // Datatype format has been changed, rebuild the Deps DB
+            if ($depdb['depdb_version'] != $this->depdb_version) {
+                $this->rebuildDB();
+            }
+        }
+    }
+
+    function _lock($mode = LOCK_EX)
+    {
+        if (!eregi('Windows 9', php_uname())) {
+            if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
+                // XXX does not check type of lock (LOCK_SH/LOCK_EX)
+                return true;
+            }
+            $open_mode = 'w';
+            // XXX People reported problems with LOCK_SH and 'w'
+            if ($mode === LOCK_SH) {
+                if (@!is_file($this->lockfile)) {
+                    touch($this->lockfile);
+                }
+                $open_mode = 'r';
+            }
+
+            $this->lock_fp = @fopen($this->lockfile, $open_mode);
+
+            if (!is_resource($this->lock_fp)) {
+                return $this->raiseError("could not create lock file" .
+                                         (isset($php_errormsg) ? ": " . $php_errormsg : ""));
+            }
+            if (!(int)flock($this->lock_fp, $mode)) {
+                switch ($mode) {
+                    case LOCK_SH: $str = 'shared';    break;
+                    case LOCK_EX: $str = 'exclusive'; break;
+                    case LOCK_UN: $str = 'unlock';    break;
+                    default:      $str = 'unknown';   break;
+                }
+                return $this->raiseError("could not acquire $str lock ($this->lockfile)");
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ _unlock()
+
+    function _unlock()
+    {
+        $ret = $this->_lock(LOCK_UN);
+        $this->lock_fp = null;
+        return $ret;
+    }
+
+    // {{{ rebuildDepsFile()
+
+    function rebuildDB()
+    {
+        $depdb = array('depdb_version' => $this->depdb_version);
+        $packages = $this->pear_reg->listPackages();
+        foreach ($packages as $package) {
+            $deps = $this->pear_reg->packageInfo($package, 'release_deps');
+            $this->setPackageDep($depdb, $package, $deps);
+        }
+        print_r($depdb);
+        $error = $this->_writeDepDB($depdb);
+        if (PEAR::isError($error)) {
+            return $error;
+        }
+        return true;
+    }
+
+    function &_getDepDB()
+    {
+        if (!$fp = fopen($this->depdb_file, 'r')) {
+            return $this->raiseError("Could not open dependencies file `".$this->depdb_file."'");
+        }
+        $data = fread($fp, filesize($this->depdb_file));
+        fclose($fp);
+        return unserialize($data);
+    }
+
+    function _writeDepDB(&$deps)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+            return $e;
+        }
+        if (!$fp = fopen($this->depdb_file, 'wb')) {
+            $this->_unlock();
+            return $this->raiseError("Could not open dependencies file `".$this->depfile."' for writting");
+        }
+        fwrite($fp, serialize($deps));
+        fclose($fp);
+        $this->_unlock();
+        return true;
+    }
+    /*
+    function removePackageDep($package)
+    {
+        $data = &$this->_depGetDepDB();
+        if (PEAR::isError($data)) {
+            return $data;
+        }
+        // Other packages depends on this package, can't be removed
+        if (isset($data['deps'][$package])) {
+            return $data['deps'][$package];
+        }
+        // The package depends on others, remove those dependencies
+        if (isset($data['pkgs'][$package])) {
+            foreach ($data['pkgs'][$package] as $pkg => $key) {
+                // remove the dependency
+                unset($data['deps'][$pkg][$key]);
+                // if no more dependencies, remove the subject too
+                if (!count($data['deps'][$pkg])) {
+                    unset($data['deps'][$pkg]);
+                }
+            }
+            // remove the package from the index list
+            unset($data['pkgs'][$package]);
+        }
+        return $this->_depWriteDepDB();
+    }
+    */
+
+    function checkAction($action, $package, $new_version = null)
+    {
+        $depdb = &$this->_getDepDB();
+        if (PEAR::isError($depdb)) {
+            return $depdb;
+        }
+        $fails = '';
+        switch($action) {
+            case 'uninstall':
+                // Other packages depends on this package, can't be removed
+                if (isset($depdb['deps'][$package])) {
+                    foreach ($depdb['deps'][$package] as $dep) {
+                        $fails .= "Package '" . $dep['depend'] . "' depends on '$package'\n";
+                    }
+                    return $fails;
+                }
+                return true;
+            case 'install':
+            case 'upgrade':
+                // Other packages depend on this package, check deps. Ex:
+                // <dep type='pkg' rel='lt' version='1.0'>Foo</dep> and we are trying to
+                // update Foo to version 2.0
+                if (isset($depdb['deps'][$package])) {
+                    foreach ($depdb['deps'][$package] as $dep) {
+                        $relation = $dep['rel'];
+                        if ($relation == 'not') {
+                            $fails .= "Package '" . $dep['depend'] . "' conflicts with '$package'\n";
+                        } elseif ($relation != 'has' && $new_version !== null) {
+                            if (!version_compare("$new_version", "{$dep['version']}", $relation)) {
+                                $fails .= "Package '" . $dep['depend'] . "' requires ".
+                                          "$package " . $this->pear_dep->signOperator($relation) .
+                                          " " . $dep['version'];
+                            }
+                        }
+                    }
+                    if (isset($fails)) {
+                        return $fails;
+                    }
+                }
+                return true;
+        }
+    }
+
+    function commitAction($action, $package)
+    {
+
+    }
+
+    /**
+    * Update or insert a the dependencies of a package, prechecking
+    * that the package won't break any dependency in the process
+
+    The data structure is as follows:
+    $dep_db = array(
+        // Other packages depends on this packages
+        'deps' => array(
+            'Package Name' => array(
+                0 => array(
+                    // This package depends on 'Package Name'
+                    'depend' => 'Package',
+                    // Which version 'Package' needs of 'Package Name'
+                    'version' => '1.0',
+                    // The requirement (version_compare() operator)
+                    'rel' => 'ge'
+                ),
+            ),
+        )
+        // This packages are dependant on other packages
+        'pkgs' => array(
+            'Package Dependant' => array(
+                // This is a index list with paths over the 'deps' array for quick
+                // searching things like "what dependecies has this package?"
+                // $dep_db['deps']['Package Name'][3]
+                'Package Name' => 3 // key in array ['deps']['Package Name']
+            ),
+        )
+    )
+
+    Note: It only supports package dependencies no other type
+    */
+
+    function setPackageDep(&$data, $package, $rel_deps = array())
+    {
+        // This package has no dependencies
+        if (!is_array($rel_deps) || !count($rel_deps)) {
+            return true;
+        }
+
+        // The package depends on others, register that
+        foreach ($rel_deps as $dep) {
+            // We only support deps of type 'pkg's
+            if ($dep && $dep['type'] == 'pkg' && isset($dep['name'])) {
+                $dep_name = strtolower($dep['name']);
+                $write = array('depend'  => $package,
+                               'rel'     => $dep['rel']);
+                if ($dep['rel'] != 'has') {
+                    $write['version'] = $dep['version'];
+                }
+                settype($data['deps'][$dep_name], 'array');
+
+                // The dependency already exists, update it
+                if (isset($data['pkgs'][$package][$dep_name])) {
+                    $key = $data['pkgs'][$package][$dep_name];
+                    $data['deps'][$dep_name][$key] = $write;
+
+                // New dependency, insert it
+                } else {
+                    $data['deps'][$dep_name][] = $write;
+                    $key = key($data['deps'][$dep_name]);
+                    settype($data['pkgs'][$package], 'array');
+                    $data['pkgs'][$package][$dep_name] = $key;
+                }
+            }
+        }
+        return true;
+    }
+    // }}}
+}
+?>