require_once "PEAR.php";
+define('PEAR_DEPENDENCY_MISSING', -1);
+define('PEAR_DEPENDENCY_CONFLICT', -2);
+define('PEAR_DEPENDENCY_UPGRADE_MINOR', -3);
+define('PEAR_DEPENDENCY_UPGRADE_MAJOR', -4);
+define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5);
+
class PEAR_Dependency
{
function PEAR_Dependency(&$registry)
* [name] => HTML_Common
* )
*/
- function callCheckMethod($opts)
+ function callCheckMethod(&$errmsg, $opts)
{
$rel = isset($opts['rel']) ? $opts['rel'] : 'has';
$req = isset($opts['version']) ? $opts['version'] : null;
$name = isset($opts['name']) ? $opts['name'] : null;
+ $errmsg = '';
switch ($opts['type']) {
case 'pkg':
- return $this->checkPackage($name, $req, $rel);
+ return $this->checkPackage($errmsg, $name, $req, $rel);
break;
case 'ext':
- return $this->checkExtension($name, $req, $rel);
+ return $this->checkExtension($errmsg, $name, $req, $rel);
break;
case 'php':
- return $this->checkPHP($req, $rel);
+ return $this->checkPHP($errmsg, $req, $rel);
break;
case 'prog':
- return $this->checkProgram($name);
+ return $this->checkProgram($errmsg, $name);
break;
case 'os':
- return $this->checkOS($name);
+ return $this->checkOS($errmsg, $name);
break;
case 'sapi':
- return $this->checkSAPI($name);
+ return $this->checkSAPI($errmsg, $name);
break;
case 'zend':
- return $this->checkZend($name);
+ return $this->checkZend($errmsg, $name);
break;
default:
return "'{$opts['type']}' dependency type not supported";
*
* @return mixed bool false if no error or the error string
*/
- function checkPackage($name, $req = null, $relation = 'has')
+ function checkPackage(&$errmsg, $name, $req = null, $relation = 'has')
{
if (substr($relation, 0, 2) == 'v.') {
$relation = substr($relation, 2);
switch ($relation) {
case 'has':
if (!$this->registry->packageExists($name)) {
- return "requires package `$name'";
+ $errmsg = "requires package `$name'";
+ return PEAR_DEPENDENCY_MISSING;
}
return false;
case 'not':
if (!$this->registry->packageExists($name)) {
- return "conflicts with package `$name'";
+ $errmsg = "conflicts with package `$name'";
+ return PEAR_DEPENDENCY_CONFLICT;
}
return false;
case 'lt':
if (!$this->registry->packageExists($name)
|| !version_compare("$version", "$req", $relation))
{
- return "requires package `$name' " .
- $this->signOperator($relation) . " $req";
+ $errmsg = "requires package `$name' " .
+ $this->signOperator($relation) . " $req";
+ $code = $this->codeFromRelation($relation, $version, $req);
}
return false;
}
- return "Relation '$relation' with requirement '$req' is not supported (name=$name)";
+ $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$name)";
+ return PEAR_DEPENDENCY_BAD_DEPENDENCY;
}
/**
*
* @return mixed bool false if no error or the error string
*/
- function checkExtension($name, $req = null, $relation = 'has')
+ function checkExtension(&$errmsg, $name, $req = null, $relation = 'has')
{
// XXX (ssb): could we avoid loading the extension here?
if (!PEAR::loadExtension($name)) {
- return "'$name' PHP extension is not installed";
+ $errmsg = "'$name' PHP extension is not installed";
+ return PEAR_DEPENDENCY_MISSING;
}
if ($relation == 'has') {
return false;
}
+ $code = false;
if (substr($relation, 0, 2) == 'v.') {
$ext_ver = phpversion($name);
$operator = substr($relation, 2);
// Force params to be strings, otherwise the comparation will fail (ex. 0.9==0.90)
+ settype($req, "string");
if (!version_compare("$ext_ver", "$req", $operator)) {
- return "'$name' PHP extension version " .
- $this->signOperator($operator) . " $req is required";
+ $retval = "'$name' PHP extension version " .
+ $this->signOperator($operator) . " $req is required";
+ $code = $this->codeFromRelation($relation, $ext_ver, $req);
}
}
- return false;
+ return $code;
}
/**
*
* @return mixed bool false if no error or the error string
*/
- function checkOS($os)
+ function checkOS(&$errmsg, $os)
{
// XXX Fixme: Implement a more flexible way, like
// comma separated values or something similar to PEAR_OS
-
- // only 'has' relation is supported
- if ($os == PHP_OS) {
+ static $myos;
+ if (empty($myos)) {
+ include_once "OS/Guess.php";
+ $myos = new OS_Guess();
+ }
+ // only 'has' relation is currently supported
+ if ($myos->matchSignature($os)) {
return false;
}
- return "'$os' operating system not supported";
+ $errmsg = "'$os' operating system not supported";
+ return PEAR_DEPENDENCY_CONFLICT;
}
/**
*
* @return mixed bool false if no error or the error string
*/
- function checkPHP($req, $relation = 'ge')
+ function checkPHP(&$errmsg, $req, $relation = 'ge')
{
if (substr($relation, 0, 2) == 'v.') {
$php_ver = phpversion();
$operator = substr($relation, 2);
if (!version_compare("$php_ver", "$req", $operator)) {
- return "PHP version " . $this->signOperator($operator) .
- " $req is required";
+ $errmsg = "PHP version " . $this->signOperator($operator) .
+ " $req is required";
+ return PEAR_DEPENDENCY_CONFLICT;
}
}
return false;
*
* @return mixed bool false if no error or the error string
*/
- function checkProgram($program)
+ function checkProgram(&$errmsg, $program)
{
// XXX FIXME honor safe mode
$path_delim = OS_WINDOWS ? ';' : ':';
return false;
}
}
- return "'$program' program is not present in the PATH";
+ $errmsg = "'$program' program is not present in the PATH";
+ return PEAR_DEPENDENCY_MISSING;
}
/**
* hardcoded to 'has')
* @return mixed bool false if no error or the error string
*/
- function checkSAPI($name, $req = null, $relation = 'has')
+ function checkSAPI(&$errmsg, $name, $req = null, $relation = 'has')
{
// XXX Fixme: There is no way to know if the user has or
// not other SAPI backends installed than the installer one
if ($sapi_backend == $name) {
return false;
}
- return "'$sapi_backend' SAPI backend not supported";
+ $errmsg = "'$sapi_backend' SAPI backend not supported";
+ return PEAR_DEPENDENCY_CONFLICT;
}
*
* @return mixed bool false if no error or the error string
*/
- function checkZend($req, $relation = 'ge')
+ function checkZend(&$errmsg, $req, $relation = 'ge')
{
if (substr($relation, 0, 2) == 'v.') {
$zend_ver = zend_version();
$operator = substr($relation, 2);
if (!version_compare("$zend_ver", "$req", $operator)) {
- return "Zend version " . $this->signOperator($operator) .
- " $req is required";
+ $errmsg = "Zend version " . $this->signOperator($operator) .
+ " $req is required";
+ return PEAR_DEPENDENCY_CONFLICT;
}
}
return false;
return $operator;
}
}
+
+
+ function codeFromRelation($relation, $version, $req)
+ {
+ $code = PEAR_DEPENDENCY_BAD_DEPENDENCY;
+ switch ($relation) {
+ case 'gt': case 'ge': case 'eq':
+ // upgrade
+ $have_major = preg_replace('/\D.*/', '', $version);
+ $need_major = preg_replace('/\D.*/', '', $req);
+ if ($need_major > $have_major) {
+ $code = PEAR_DEPENDENCY_UPGRADE_MAJOR;
+ } else {
+ $code = PEAR_DEPENDENCY_UPGRADE_MINOR;
+ }
+ break;
+ case 'lt': case 'le': case 'ne':
+ $code = PEAR_DEPENDENCY_CONFLICT;
+ break;
+ }
+ return $code;
+ }
}
?>
function _installFile($file, $atts, $tmp_path)
{
static $os;
- ini_set("track_errors", 1);
if (isset($atts['platform'])) {
if (empty($os)) {
include_once "OS/Guess.php";
function addFileOperation($type, $data)
{
- $this->log(3, "adding to transaction: $type " . implode(" ", $data));
+ if ($type == 'chmod') {
+ $octmode = decoct($data[0]);
+ $this->log(3, "adding to transaction: $type $octmode $data[1]");
+ } else {
+ $this->log(3, "adding to transaction: $type " . implode(" ", $data));
+ }
$this->file_operations[] = array($type, $data);
}
break;
case 'delete':
// check that directory is writable
- if (!is_writable(dirname($data[0]))) {
+ if (file_exists($data[0]) && !is_writable(dirname($data[0]))) {
$errors[] = "permission denied ($type): $data[0]";
}
break;
break;
case 'chmod':
@chmod($data[0], $data[1]);
- $this->log(3, "+ chmod $data[0] $data[1]");
+ $octmode = decoct($data[0]);
+ $this->log(3, "+ chmod $octmode $data[1]");
break;
case 'delete':
@unlink($data[0]);
function checkDeps(&$pkginfo)
{
- $deps = &new PEAR_Dependency($this->registry);
- $errors = null;
+ $depchecker = &new PEAR_Dependency($this->registry);
+ $error = $errors = '';
+ $failed_deps = array();
if (is_array($pkginfo['release_deps'])) {
foreach($pkginfo['release_deps'] as $dep) {
- if ($error = $deps->callCheckMethod($dep)) {
- $errors .= "\n$error";
+ $code = $depchecker->callCheckMethod($error, $dep);
+ if ($code) {
+ $failed_deps[] = array($dep, $code, $error);
}
}
- if ($errors) {
- return $errors;
+ $n = count($failed_deps);
+ if ($n > 0) {
+ $depinstaller =& new PEAR_Installer($this->ui);
+ $to_install = array();
+ for ($i = 0; $i < $n; $i++) {
+ if (isset($failed_deps[$i]['type'])) {
+ $type = $failed_deps[$i]['type'];
+ } else {
+ $type = 'pkg';
+ }
+ switch ($failed_deps[$i][1]) {
+ case PEAR_DEPENDENCY_MISSING:
+ if ($type == 'pkg') {
+ // install
+ }
+ $errors .= "\n" . $failed_deps[$i][2];
+ break;
+ case PEAR_DEPENDENCY_UPGRADE_MINOR:
+ if ($type == 'pkg') {
+ // upgrade
+ }
+ $errors .= "\n" . $failed_deps[$i][2];
+ break;
+ default:
+ $errors .= "\n" . $failed_deps[$i][2];
+ break;
+ }
+ }
+ return substr($errors, 1);
}
}
return false;