You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
7.8 KiB
PHP
290 lines
7.8 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of Composer.
|
|
*
|
|
* (c) Nils Adermann <naderman@naderman.de>
|
|
* Jordi Boggiano <j.boggiano@seld.be>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Composer\DependencyResolver;
|
|
|
|
/**
|
|
* @author Nils Adermann <naderman@naderman.de>
|
|
*/
|
|
class Rule
|
|
{
|
|
const RULE_INTERNAL_ALLOW_UPDATE = 1;
|
|
const RULE_JOB_INSTALL = 2;
|
|
const RULE_JOB_REMOVE = 3;
|
|
const RULE_PACKAGE_CONFLICT = 6;
|
|
const RULE_PACKAGE_REQUIRES = 7;
|
|
const RULE_PACKAGE_OBSOLETES = 8;
|
|
const RULE_INSTALLED_PACKAGE_OBSOLETES = 9;
|
|
const RULE_PACKAGE_SAME_NAME = 10;
|
|
const RULE_PACKAGE_IMPLICIT_OBSOLETES = 11;
|
|
const RULE_LEARNED = 12;
|
|
const RULE_PACKAGE_ALIAS = 13;
|
|
|
|
/**
|
|
* The literals this rule consists of.
|
|
*
|
|
* Each element is a package id either positive for installation or
|
|
* negative meaning removal.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $literals;
|
|
|
|
protected $pool;
|
|
|
|
protected $disabled;
|
|
protected $type;
|
|
protected $id;
|
|
protected $reason;
|
|
protected $reasonData;
|
|
|
|
protected $job;
|
|
|
|
protected $ruleHash;
|
|
|
|
public function __construct(Pool $pool, array $literals, $reason, $reasonData, $job = null)
|
|
{
|
|
$this->pool = $pool;
|
|
|
|
// sort all packages ascending by id
|
|
sort($literals);
|
|
|
|
$this->literals = $literals;
|
|
$this->reason = $reason;
|
|
$this->reasonData = $reasonData;
|
|
|
|
$this->disabled = false;
|
|
|
|
$this->job = $job;
|
|
|
|
$this->type = -1;
|
|
|
|
$this->ruleHash = substr(md5(implode(',', $this->literals)), 0, 5);
|
|
}
|
|
|
|
public function getHash()
|
|
{
|
|
return $this->ruleHash;
|
|
}
|
|
|
|
public function setId($id)
|
|
{
|
|
$this->id = $id;
|
|
}
|
|
|
|
public function getId()
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function getJob()
|
|
{
|
|
return $this->job;
|
|
}
|
|
|
|
public function getReason()
|
|
{
|
|
return $this->reason;
|
|
}
|
|
|
|
public function getReasonData()
|
|
{
|
|
return $this->reasonData;
|
|
}
|
|
|
|
public function getRequiredPackage()
|
|
{
|
|
if ($this->reason === self::RULE_JOB_INSTALL) {
|
|
return $this->reasonData;
|
|
}
|
|
|
|
if ($this->reason === self::RULE_PACKAGE_REQUIRES) {
|
|
return $this->reasonData->getTarget();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if this rule is equal to another one
|
|
*
|
|
* Ignores whether either of the rules is disabled.
|
|
*
|
|
* @param Rule $rule The rule to check against
|
|
* @return bool Whether the rules are equal
|
|
*/
|
|
public function equals(Rule $rule)
|
|
{
|
|
if ($this->ruleHash !== $rule->ruleHash) {
|
|
return false;
|
|
}
|
|
|
|
if (count($this->literals) != count($rule->literals)) {
|
|
return false;
|
|
}
|
|
|
|
for ($i = 0, $n = count($this->literals); $i < $n; $i++) {
|
|
if ($this->literals[$i] !== $rule->literals[$i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function setType($type)
|
|
{
|
|
$this->type = $type;
|
|
}
|
|
|
|
public function getType()
|
|
{
|
|
return $this->type;
|
|
}
|
|
|
|
public function disable()
|
|
{
|
|
$this->disabled = true;
|
|
}
|
|
|
|
public function enable()
|
|
{
|
|
$this->disabled = false;
|
|
}
|
|
|
|
public function isDisabled()
|
|
{
|
|
return $this->disabled;
|
|
}
|
|
|
|
public function isEnabled()
|
|
{
|
|
return !$this->disabled;
|
|
}
|
|
|
|
public function isAssertion()
|
|
{
|
|
return 1 === count($this->literals);
|
|
}
|
|
|
|
public function getPrettyString(array $installedMap = array())
|
|
{
|
|
$ruleText = '';
|
|
foreach ($this->literals as $i => $literal) {
|
|
if ($i != 0) {
|
|
$ruleText .= '|';
|
|
}
|
|
$ruleText .= $this->pool->literalToPrettyString($literal, $installedMap);
|
|
}
|
|
|
|
switch ($this->reason) {
|
|
case self::RULE_INTERNAL_ALLOW_UPDATE:
|
|
return $ruleText;
|
|
|
|
case self::RULE_JOB_INSTALL:
|
|
return "Install command rule ($ruleText)";
|
|
|
|
case self::RULE_JOB_REMOVE:
|
|
return "Remove command rule ($ruleText)";
|
|
|
|
case self::RULE_PACKAGE_CONFLICT:
|
|
$package1 = $this->pool->literalToPackage($this->literals[0]);
|
|
$package2 = $this->pool->literalToPackage($this->literals[1]);
|
|
|
|
return $package1->getPrettyString().' conflicts with '.$this->formatPackagesUnique(array($package2)).'.';
|
|
|
|
case self::RULE_PACKAGE_REQUIRES:
|
|
$literals = $this->literals;
|
|
$sourceLiteral = array_shift($literals);
|
|
$sourcePackage = $this->pool->literalToPackage($sourceLiteral);
|
|
|
|
$requires = array();
|
|
foreach ($literals as $literal) {
|
|
$requires[] = $this->pool->literalToPackage($literal);
|
|
}
|
|
|
|
$text = $this->reasonData->getPrettyString($sourcePackage);
|
|
if ($requires) {
|
|
$text .= ' -> satisfiable by ' . $this->formatPackagesUnique($requires) . '.';
|
|
} else {
|
|
$targetName = $this->reasonData->getTarget();
|
|
|
|
// handle php extensions
|
|
if (0 === strpos($targetName, 'ext-')) {
|
|
$ext = substr($targetName, 4);
|
|
$error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
|
|
|
|
$text .= ' -> the requested PHP extension '.$ext.' '.$error.'.';
|
|
} elseif (0 === strpos($targetName, 'lib-')) {
|
|
// handle linked libs
|
|
$lib = substr($targetName, 4);
|
|
|
|
$text .= ' -> the requested linked library '.$lib.' has the wrong version installed or is missing from your system, make sure to have the extension providing it.';
|
|
} else {
|
|
$text .= ' -> no matching package found.';
|
|
}
|
|
}
|
|
|
|
return $text;
|
|
|
|
case self::RULE_PACKAGE_OBSOLETES:
|
|
return $ruleText;
|
|
case self::RULE_INSTALLED_PACKAGE_OBSOLETES:
|
|
return $ruleText;
|
|
case self::RULE_PACKAGE_SAME_NAME:
|
|
return 'Can only install one of: ' . $this->formatPackagesUnique($this->literals) . '.';
|
|
case self::RULE_PACKAGE_IMPLICIT_OBSOLETES:
|
|
return $ruleText;
|
|
case self::RULE_LEARNED:
|
|
return 'Conclusion: '.$ruleText;
|
|
case self::RULE_PACKAGE_ALIAS:
|
|
return $ruleText;
|
|
}
|
|
}
|
|
|
|
protected function formatPackagesUnique(array $packages)
|
|
{
|
|
$prepared = array();
|
|
foreach ($packages as $package) {
|
|
if (!is_object($package)) {
|
|
$package = $this->pool->literalToPackage($package);
|
|
}
|
|
$prepared[$package->getName()]['name'] = $package->getPrettyName();
|
|
$prepared[$package->getName()]['versions'][$package->getVersion()] = $package->getPrettyVersion();
|
|
}
|
|
foreach ($prepared as $name => $package) {
|
|
$prepared[$name] = $package['name'].'['.implode(', ', $package['versions']).']';
|
|
}
|
|
|
|
return implode(', ', $prepared);
|
|
}
|
|
|
|
/**
|
|
* Formats a rule as a string of the format (Literal1|Literal2|...)
|
|
*
|
|
* @return string
|
|
*/
|
|
public function __toString()
|
|
{
|
|
$result = ($this->isDisabled()) ? 'disabled(' : '(';
|
|
|
|
foreach ($this->literals as $i => $literal) {
|
|
if ($i != 0) {
|
|
$result .= '|';
|
|
}
|
|
$result .= $this->pool->literalToString($literal);
|
|
}
|
|
|
|
$result .= ')';
|
|
|
|
return $result;
|
|
}
|
|
}
|