Merge remote-tracking branch 'upstream/master' into docs
* upstream/master: (42 commits) Correct the parent path in the watch tree, after moving a rule out of the path Add config in composer json schema Add scripts to json schema Use updateAll request method in upddate mode in install command Readd update-all jobs and make them available through the request Fix local git repo handling in GitDriver Add getVersionConstraint test case to avoid version normalization issues Fix line endings of Composer TestCase Correct placing of braces Clean up the incomplete marker like suggested in https://github.com/composer/composer/pull/324#r465391 When changing watched literals of a rule, update the parent's next pointer Fix TODO tags to confirm with the projects standard Display undecided literals as undecided with a ?, when printing the decision map Add a debug print method for the entire watch tree to the solver Support both require and requires as depends link-type arg Create an impossible rule when trying to install something that doesn't exist. Add todos to explain why try/catch is inside the test Add SolverProblemsException and test basic solver failures Deciding to install a package and wanting to install it, is not a conflict Restore realpath behavior ... Conflicts: Resources/composer-schema.jsonpull/319/head
commit
ee73b332e5
|
@ -101,6 +101,20 @@
|
||||||
"description": "This is a hash of package name (keys) and version constraints (values) that this package suggests work well with it (typically this will only be suggested to the user).",
|
"description": "This is a hash of package name (keys) and version constraints (values) that this package suggests work well with it (typically this will only be suggested to the user).",
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
},
|
},
|
||||||
|
"config": {
|
||||||
|
"type": ["object"],
|
||||||
|
"description": "Composer options.",
|
||||||
|
"properties": {
|
||||||
|
"vendor-dir": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The location where all packages are installed, defaults to \"vendor\"."
|
||||||
|
},
|
||||||
|
"bin-dir": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The location where all binaries are linked, defaults to \"vendor/bin\"."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"type": ["object", "array"],
|
"type": ["object", "array"],
|
||||||
"description": "Arbitrary extra data that can be used by custom installers, for example, package of type composer-installer must have a 'class' key defining the installer class name.",
|
"description": "Arbitrary extra data that can be used by custom installers, for example, package of type composer-installer must have a 'class' key defining the installer class name.",
|
||||||
|
@ -128,6 +142,52 @@
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"type": ["object"],
|
||||||
|
"description": "Scripts listeners that will be executed before/after some events.",
|
||||||
|
"properties": {
|
||||||
|
"pre-install-cmd": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs before the install command is executed, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"post-install-cmd": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs after the install command is executed, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"pre-update-cmd": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs before the update command is executed, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"post-update-cmd": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs after the update command is executed, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"pre-package-install": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs before a package is installed, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"post-package-install": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs after a package is installed, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"pre-package-update": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs before a package is updated, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"post-package-update": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs after a package is updated, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"pre-package-uninstall": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs before a package has been uninstalled, contains one or more Class::method callables.",
|
||||||
|
},
|
||||||
|
"post-package-uninstall": {
|
||||||
|
"type": ["array", "string"],
|
||||||
|
"description": "Occurs after a package has been uninstalled, contains one or more Class::method callables.",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||||
*/
|
*/
|
||||||
class DependsCommand extends Command
|
class DependsCommand extends Command
|
||||||
{
|
{
|
||||||
|
protected $linkTypes = array('require', 'recommend', 'suggest');
|
||||||
|
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
@ -32,7 +34,7 @@ class DependsCommand extends Command
|
||||||
->setDescription('Shows which packages depend on the given package')
|
->setDescription('Shows which packages depend on the given package')
|
||||||
->setDefinition(array(
|
->setDefinition(array(
|
||||||
new InputArgument('package', InputArgument::REQUIRED, 'Package to inspect'),
|
new InputArgument('package', InputArgument::REQUIRED, 'Package to inspect'),
|
||||||
new InputOption('link-type', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Link types to show', array('requires', 'recommends', 'suggests'))
|
new InputOption('link-type', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Link types to show', $this->linkTypes)
|
||||||
))
|
))
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
Displays detailed information about where a package is referenced.
|
Displays detailed information about where a package is referenced.
|
||||||
|
@ -74,10 +76,15 @@ EOT
|
||||||
|
|
||||||
$repos = $composer->getRepositoryManager()->getRepositories();
|
$repos = $composer->getRepositoryManager()->getRepositories();
|
||||||
$types = $input->getOption('link-type');
|
$types = $input->getOption('link-type');
|
||||||
|
|
||||||
foreach ($repos as $repository) {
|
foreach ($repos as $repository) {
|
||||||
foreach ($repository->getPackages() as $package) {
|
foreach ($repository->getPackages() as $package) {
|
||||||
foreach ($types as $type) {
|
foreach ($types as $type) {
|
||||||
foreach ($package->{'get'.$type}() as $link) {
|
$type = rtrim($type, 's');
|
||||||
|
if (!in_array($type, $this->linkTypes)) {
|
||||||
|
throw new \InvalidArgumentException('Unexpected link type: '.$type.', valid types: '.implode(', ', $this->linkTypes));
|
||||||
|
}
|
||||||
|
foreach ($package->{'get'.$type.'s'}() as $link) {
|
||||||
if ($link->getTarget() === $needle) {
|
if ($link->getTarget() === $needle) {
|
||||||
if ($verbose) {
|
if ($verbose) {
|
||||||
$references[] = array($type, $package, $link);
|
$references[] = array($type, $package, $link);
|
||||||
|
|
|
@ -119,14 +119,9 @@ EOT
|
||||||
$installedPackages = $installedRepo->getPackages();
|
$installedPackages = $installedRepo->getPackages();
|
||||||
$links = $this->collectLinks($composer->getPackage(), $noInstallRecommends, $installSuggests);
|
$links = $this->collectLinks($composer->getPackage(), $noInstallRecommends, $installSuggests);
|
||||||
|
|
||||||
foreach ($links as $link) {
|
$request->updateAll();
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
if ($package->getName() === $link->getTarget()) {
|
|
||||||
$request->update($package->getName(), new VersionConstraint('=', $package->getVersion()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
foreach ($links as $link) {
|
||||||
$request->install($link->getTarget(), $link->getConstraint());
|
$request->install($link->getTarget(), $link->getConstraint());
|
||||||
}
|
}
|
||||||
} elseif ($composer->getLocker()->isLocked()) {
|
} elseif ($composer->getLocker()->isLocked()) {
|
||||||
|
|
|
@ -21,16 +21,6 @@ use Composer\Package\LinkConstraint\VersionConstraint;
|
||||||
*/
|
*/
|
||||||
class DefaultPolicy implements PolicyInterface
|
class DefaultPolicy implements PolicyInterface
|
||||||
{
|
{
|
||||||
public function allowUninstall()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function allowDowngrade()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
|
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
|
||||||
{
|
{
|
||||||
$constraint = new VersionConstraint($operator, $b->getVersion());
|
$constraint = new VersionConstraint($operator, $b->getVersion());
|
||||||
|
@ -39,16 +29,11 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return $constraint->matchSpecific($version);
|
return $constraint->matchSpecific($version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package, $allowAll = false)
|
public function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package)
|
||||||
{
|
{
|
||||||
$packages = array();
|
$packages = array();
|
||||||
|
|
||||||
foreach ($pool->whatProvides($package->getName()) as $candidate) {
|
foreach ($pool->whatProvides($package->getName()) as $candidate) {
|
||||||
// skip old packages unless downgrades are an option
|
|
||||||
if (!$allowAll && !$this->allowDowngrade() && $this->versionCompare($package, $candidate, '>')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($candidate !== $package) {
|
if ($candidate !== $package) {
|
||||||
$packages[] = $candidate;
|
$packages[] = $candidate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,8 @@ use Composer\Package\PackageInterface;
|
||||||
*/
|
*/
|
||||||
interface PolicyInterface
|
interface PolicyInterface
|
||||||
{
|
{
|
||||||
function allowUninstall();
|
|
||||||
function allowDowngrade();
|
|
||||||
function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
||||||
function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package, $allowAll);
|
function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package);
|
||||||
function installable(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package);
|
function installable(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package);
|
||||||
function selectPreferedPackages(Pool $pool, array $installedMap, array $literals);
|
function selectPreferedPackages(Pool $pool, array $installedMap, array $literals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,11 @@ class Request
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateAll()
|
||||||
|
{
|
||||||
|
$this->jobs[] = array('cmd' => 'update-all', 'packages' => array());
|
||||||
|
}
|
||||||
|
|
||||||
public function getJobs()
|
public function getJobs()
|
||||||
{
|
{
|
||||||
return $this->jobs;
|
return $this->jobs;
|
||||||
|
|
|
@ -29,6 +29,8 @@ class Rule
|
||||||
public $next1;
|
public $next1;
|
||||||
public $next2;
|
public $next2;
|
||||||
|
|
||||||
|
public $ruleHash;
|
||||||
|
|
||||||
public function __construct(array $literals, $reason, $reasonData)
|
public function __construct(array $literals, $reason, $reasonData)
|
||||||
{
|
{
|
||||||
// sort all packages ascending by id
|
// sort all packages ascending by id
|
||||||
|
@ -85,7 +87,7 @@ class Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 0, $n = count($this->literals); $i < $n; $i++) {
|
for ($i = 0, $n = count($this->literals); $i < $n; $i++) {
|
||||||
if (!$this->literals[$i]->getId() === $rule->literals[$i]->getId()) {
|
if ($this->literals[$i]->getId() !== $rule->literals[$i]->getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ class RuleSet implements \IteratorAggregate, \Countable
|
||||||
// highest priority => lowest number
|
// highest priority => lowest number
|
||||||
const TYPE_PACKAGE = 0;
|
const TYPE_PACKAGE = 0;
|
||||||
const TYPE_JOB = 1;
|
const TYPE_JOB = 1;
|
||||||
const TYPE_UPDATE = 2;
|
|
||||||
const TYPE_FEATURE = 3;
|
const TYPE_FEATURE = 3;
|
||||||
const TYPE_CHOICE = 4;
|
const TYPE_CHOICE = 4;
|
||||||
const TYPE_LEARNED = 5;
|
const TYPE_LEARNED = 5;
|
||||||
|
@ -29,7 +28,6 @@ class RuleSet implements \IteratorAggregate, \Countable
|
||||||
-1 => 'UNKNOWN',
|
-1 => 'UNKNOWN',
|
||||||
self::TYPE_PACKAGE => 'PACKAGE',
|
self::TYPE_PACKAGE => 'PACKAGE',
|
||||||
self::TYPE_FEATURE => 'FEATURE',
|
self::TYPE_FEATURE => 'FEATURE',
|
||||||
self::TYPE_UPDATE => 'UPDATE',
|
|
||||||
self::TYPE_JOB => 'JOB',
|
self::TYPE_JOB => 'JOB',
|
||||||
self::TYPE_CHOICE => 'CHOICE',
|
self::TYPE_CHOICE => 'CHOICE',
|
||||||
self::TYPE_LEARNED => 'LEARNED',
|
self::TYPE_LEARNED => 'LEARNED',
|
||||||
|
|
|
@ -52,7 +52,6 @@ class Solver
|
||||||
protected $decisionMap;
|
protected $decisionMap;
|
||||||
protected $installedMap;
|
protected $installedMap;
|
||||||
|
|
||||||
protected $packageToUpdateRule = array();
|
|
||||||
protected $packageToFeatureRule = array();
|
protected $packageToFeatureRule = array();
|
||||||
|
|
||||||
public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed)
|
public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed)
|
||||||
|
@ -77,7 +76,7 @@ class Solver
|
||||||
* that goes with the reason
|
* that goes with the reason
|
||||||
* @return Rule The generated rule or null if tautological
|
* @return Rule The generated rule or null if tautological
|
||||||
*/
|
*/
|
||||||
public function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
|
protected function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
$literals = array(new Literal($package, false));
|
$literals = array(new Literal($package, false));
|
||||||
|
|
||||||
|
@ -128,7 +127,7 @@ class Solver
|
||||||
* goes with the reason
|
* goes with the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createInstallRule(PackageInterface $package, $reason, $reasonData = null)
|
protected function createInstallRule(PackageInterface $package, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
return new Rule(new Literal($package, true));
|
return new Rule(new Literal($package, true));
|
||||||
}
|
}
|
||||||
|
@ -146,7 +145,7 @@ class Solver
|
||||||
* the reason
|
* the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createInstallOneOfRule(array $packages, $reason, $reasonData = null)
|
protected function createInstallOneOfRule(array $packages, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
if (empty($packages)) {
|
if (empty($packages)) {
|
||||||
return $this->createImpossibleRule($reason, $reasonData);
|
return $this->createImpossibleRule($reason, $reasonData);
|
||||||
|
@ -172,7 +171,7 @@ class Solver
|
||||||
* goes with the reason
|
* goes with the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createRemoveRule(PackageInterface $package, $reason, $reasonData = null)
|
protected function createRemoveRule(PackageInterface $package, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
return new Rule(array(new Literal($package, false)), $reason, $reasonData);
|
return new Rule(array(new Literal($package, false)), $reason, $reasonData);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +190,7 @@ class Solver
|
||||||
* goes with the reason
|
* goes with the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
|
protected function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
// ignore self conflict
|
// ignore self conflict
|
||||||
if ($issuer === $provider) {
|
if ($issuer === $provider) {
|
||||||
|
@ -212,7 +211,7 @@ class Solver
|
||||||
* the reason
|
* the reason
|
||||||
* @return Rule An empty rule
|
* @return Rule An empty rule
|
||||||
*/
|
*/
|
||||||
public function createImpossibleRule($reason, $reasonData = null)
|
protected function createImpossibleRule($reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
return new Rule(array(), $reason, $reasonData);
|
return new Rule(array(), $reason, $reasonData);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +236,7 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRulesForPackage(PackageInterface $package)
|
protected function addRulesForPackage(PackageInterface $package)
|
||||||
{
|
{
|
||||||
$workQueue = new \SplQueue;
|
$workQueue = new \SplQueue;
|
||||||
$workQueue->enqueue($package);
|
$workQueue->enqueue($package);
|
||||||
|
@ -305,7 +304,7 @@ class Solver
|
||||||
// if ignoreinstalledsobsoletes is not set, we're also checking
|
// if ignoreinstalledsobsoletes is not set, we're also checking
|
||||||
// obsoletes of installed packages (like newer rpm versions)
|
// obsoletes of installed packages (like newer rpm versions)
|
||||||
//
|
//
|
||||||
/** @TODO: if ($this->noInstalledObsoletes) */
|
/** TODO if ($this->noInstalledObsoletes) */
|
||||||
if (true) {
|
if (true) {
|
||||||
$noObsoletes = isset($this->noObsoletes[$package->getId()]);
|
$noObsoletes = isset($this->noObsoletes[$package->getId()]);
|
||||||
$isInstalled = (isset($this->installedMap[$package->getId()]));
|
$isInstalled = (isset($this->installedMap[$package->getId()]));
|
||||||
|
@ -375,9 +374,9 @@ class Solver
|
||||||
* be added
|
* be added
|
||||||
* @param bool $allowAll Whether downgrades are allowed
|
* @param bool $allowAll Whether downgrades are allowed
|
||||||
*/
|
*/
|
||||||
private function addRulesForUpdatePackages(PackageInterface $package, $allowAll)
|
private function addRulesForUpdatePackages(PackageInterface $package)
|
||||||
{
|
{
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package, $allowAll);
|
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
||||||
|
|
||||||
$this->addRulesForPackage($package);
|
$this->addRulesForPackage($package);
|
||||||
|
|
||||||
|
@ -508,7 +507,7 @@ class Solver
|
||||||
|
|
||||||
// push all of our rules (can only be feature or job rules)
|
// push all of our rules (can only be feature or job rules)
|
||||||
// asserting this literal on the problem stack
|
// asserting this literal on the problem stack
|
||||||
foreach ($this->rules->getIteratorFor(array(RuleSet::TYPE_JOB, RuleSet::TYPE_UPDATE, RuleSet::TYPE_FEATURE)) as $assertRule) {
|
foreach ($this->rules->getIteratorFor(array(RuleSet::TYPE_JOB, RuleSet::TYPE_FEATURE)) as $assertRule) {
|
||||||
if ($assertRule->isDisabled() || !$assertRule->isAssertion() || $assertRule->isWeak()) {
|
if ($assertRule->isDisabled() || !$assertRule->isAssertion() || $assertRule->isWeak()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -571,7 +570,7 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addChoiceRules()
|
protected function addChoiceRules()
|
||||||
{
|
{
|
||||||
|
|
||||||
// void
|
// void
|
||||||
|
@ -882,11 +881,6 @@ class Solver
|
||||||
|
|
||||||
protected function disableUpdateRule($package)
|
protected function disableUpdateRule($package)
|
||||||
{
|
{
|
||||||
// find update & feature rule and disable
|
|
||||||
if (isset($this->packageToUpdateRule[$package->getId()])) {
|
|
||||||
$this->packageToUpdateRule[$package->getId()]->disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
||||||
$this->packageToFeatureRule[$package->getId()]->disable();
|
$this->packageToFeatureRule[$package->getId()]->disable();
|
||||||
}
|
}
|
||||||
|
@ -944,20 +938,6 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($this->jobs as $job) {
|
||||||
switch ($job['cmd']) {
|
|
||||||
case 'update-all':
|
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
$this->updateMap[$package->getId()] = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'fix-all':
|
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
$this->fixMap[$package->getId()] = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($job['packages'] as $package) {
|
foreach ($job['packages'] as $package) {
|
||||||
switch ($job['cmd']) {
|
switch ($job['cmd']) {
|
||||||
case 'fix':
|
case 'fix':
|
||||||
|
@ -972,6 +952,14 @@ class Solver
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ($job['cmd']) {
|
||||||
|
case 'update-all':
|
||||||
|
foreach ($installedPackages as $package) {
|
||||||
|
$this->updateMap[$package->getId()] = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($installedPackages as $package) {
|
||||||
|
@ -979,11 +967,17 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($installedPackages as $package) {
|
||||||
$this->addRulesForUpdatePackages($package, true);
|
$this->addRulesForUpdatePackages($package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($this->jobs as $job) {
|
||||||
|
if (empty($job['packages']) && $job['cmd'] == 'install') {
|
||||||
|
$this->addRule(
|
||||||
|
RuleSet::TYPE_JOB,
|
||||||
|
$this->createImpossibleRule(static::RULE_JOB_INSTALL, $job)
|
||||||
|
);
|
||||||
|
}
|
||||||
foreach ($job['packages'] as $package) {
|
foreach ($job['packages'] as $package) {
|
||||||
switch ($job['cmd']) {
|
switch ($job['cmd']) {
|
||||||
case 'install':
|
case 'install':
|
||||||
|
@ -997,33 +991,12 @@ class Solver
|
||||||
// solver_addrpmrulesforweak(solv, &addedmap);
|
// solver_addrpmrulesforweak(solv, &addedmap);
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($installedPackages as $package) {
|
||||||
// create a feature rule which allows downgrades
|
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package, true);
|
|
||||||
$featureRule = $this->createUpdateRule($package, $updates, self::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
|
||||||
|
|
||||||
// create an update rule which does not allow downgrades
|
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package, false);
|
|
||||||
$rule = $this->createUpdateRule($package, $updates, self::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
$rule = $this->createUpdateRule($package, $updates, self::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
||||||
|
|
||||||
if ($rule->equals($featureRule)) {
|
|
||||||
if ($this->policy->allowUninstall()) {
|
|
||||||
$featureRule->setWeak(true);
|
|
||||||
$this->addRule(RuleSet::TYPE_FEATURE, $featureRule);
|
|
||||||
$this->packageToFeatureRule[$package->getId()] = $rule;
|
|
||||||
} else {
|
|
||||||
$this->addRule(RuleSet::TYPE_UPDATE, $rule);
|
|
||||||
$this->packageToUpdateRule[$package->getId()] = $rule;
|
|
||||||
}
|
|
||||||
} else if ($this->policy->allowUninstall()) {
|
|
||||||
$featureRule->setWeak(true);
|
|
||||||
$rule->setWeak(true);
|
$rule->setWeak(true);
|
||||||
|
$this->addRule(RuleSet::TYPE_FEATURE, $rule);
|
||||||
$this->addRule(RuleSet::TYPE_FEATURE, $featureRule);
|
|
||||||
$this->addRule(RuleSet::TYPE_UPDATE, $rule);
|
|
||||||
|
|
||||||
$this->packageToFeatureRule[$package->getId()] = $rule;
|
$this->packageToFeatureRule[$package->getId()] = $rule;
|
||||||
$this->packageToUpdateRule[$package->getId()] = $rule;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($this->jobs as $job) {
|
||||||
|
@ -1076,6 +1049,10 @@ class Solver
|
||||||
//findrecommendedsuggested(solv);
|
//findrecommendedsuggested(solv);
|
||||||
//solver_prepare_solutions(solv);
|
//solver_prepare_solutions(solv);
|
||||||
|
|
||||||
|
if ($this->problems) {
|
||||||
|
throw new SolverProblemsException($this->problems, $this->learnedPool);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->createTransaction();
|
return $this->createTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1091,9 +1068,6 @@ class Solver
|
||||||
if (!$literal->isWanted() && isset($this->installedMap[$package->getId()])) {
|
if (!$literal->isWanted() && isset($this->installedMap[$package->getId()])) {
|
||||||
$literals = array();
|
$literals = array();
|
||||||
|
|
||||||
if (isset($this->packageToUpdateRule[$package->getId()])) {
|
|
||||||
$literals = array_merge($literals, $this->packageToUpdateRule[$package->getId()]->getLiterals());
|
|
||||||
}
|
|
||||||
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
||||||
$literals = array_merge($literals, $this->packageToFeatureRule[$package->getId()]->getLiterals());
|
$literals = array_merge($literals, $this->packageToFeatureRule[$package->getId()]->getLiterals());
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1131,8 @@ class Solver
|
||||||
|
|
||||||
protected function addDecision(Literal $l, $level)
|
protected function addDecision(Literal $l, $level)
|
||||||
{
|
{
|
||||||
|
assert($this->decisionMap[$l->getPackageId()] == 0);
|
||||||
|
|
||||||
if ($l->isWanted()) {
|
if ($l->isWanted()) {
|
||||||
$this->decisionMap[$l->getPackageId()] = $level;
|
$this->decisionMap[$l->getPackageId()] = $level;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1167,6 +1143,9 @@ class Solver
|
||||||
protected function addDecisionId($literalId, $level)
|
protected function addDecisionId($literalId, $level)
|
||||||
{
|
{
|
||||||
$packageId = abs($literalId);
|
$packageId = abs($literalId);
|
||||||
|
|
||||||
|
assert($this->decisionMap[$packageId] == 0);
|
||||||
|
|
||||||
if ($literalId > 0) {
|
if ($literalId > 0) {
|
||||||
$this->decisionMap[$packageId] = $level;
|
$this->decisionMap[$packageId] = $level;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1209,8 +1188,8 @@ class Solver
|
||||||
{
|
{
|
||||||
$packageId = abs($literalId);
|
$packageId = abs($literalId);
|
||||||
return (
|
return (
|
||||||
$this->decisionMap[$packageId] > 0 && !($literalId < 0) ||
|
($this->decisionMap[$packageId] > 0 && $literalId < 0) ||
|
||||||
$this->decisionMap[$packageId] < 0 && $literalId > 0
|
($this->decisionMap[$packageId] < 0 && $literalId > 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1257,7 +1236,8 @@ class Solver
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($rule = $this->watches[$literal->getId()]; $rule !== null; $rule = $nextRule) {
|
$prevRule = null;
|
||||||
|
for ($rule = $this->watches[$literal->getId()]; $rule !== null; $prevRule = $rule, $rule = $nextRule) {
|
||||||
$nextRule = $rule->getNext($literal);
|
$nextRule = $rule->getNext($literal);
|
||||||
|
|
||||||
if ($rule->isDisabled()) {
|
if ($rule->isDisabled()) {
|
||||||
|
@ -1277,16 +1257,27 @@ class Solver
|
||||||
if ($otherWatch !== $ruleLiteral->getId() &&
|
if ($otherWatch !== $ruleLiteral->getId() &&
|
||||||
!$this->decisionsConflict($ruleLiteral)) {
|
!$this->decisionsConflict($ruleLiteral)) {
|
||||||
|
|
||||||
|
|
||||||
if ($literal->getId() === $rule->watch1) {
|
if ($literal->getId() === $rule->watch1) {
|
||||||
$rule->watch1 = $ruleLiteral->getId();
|
$rule->watch1 = $ruleLiteral->getId();
|
||||||
$rule->next1 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null ;
|
$rule->next1 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null;
|
||||||
} else {
|
} else {
|
||||||
$rule->watch2 = $ruleLiteral->getId();
|
$rule->watch2 = $ruleLiteral->getId();
|
||||||
$rule->next2 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null ;
|
$rule->next2 = (isset($this->watches[$ruleLiteral->getId()])) ? $this->watches[$ruleLiteral->getId()] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prevRule) {
|
||||||
|
if ($prevRule->next1 == $rule) {
|
||||||
|
$prevRule->next1 = $nextRule;
|
||||||
|
} else {
|
||||||
|
$prevRule->next2 = $nextRule;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->watches[$literal->getId()] = $nextRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->watches[$ruleLiteral->getId()] = $rule;
|
$this->watches[$ruleLiteral->getId()] = $rule;
|
||||||
|
|
||||||
|
$rule = $prevRule;
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1517,7 +1508,7 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
$why = count($this->learnedPool) - 1;
|
$why = count($this->learnedPool) - 1;
|
||||||
|
assert($learnedLiterals[0] !== null);
|
||||||
$newRule = new Rule($learnedLiterals, self::RULE_LEARNED, $why);
|
$newRule = new Rule($learnedLiterals, self::RULE_LEARNED, $why);
|
||||||
|
|
||||||
return array($ruleLevel, $newRule, $why);
|
return array($ruleLevel, $newRule, $why);
|
||||||
|
@ -1843,11 +1834,7 @@ class Solver
|
||||||
|
|
||||||
$rule = null;
|
$rule = null;
|
||||||
|
|
||||||
if (isset($this->packageToUpdateRule[$literal->getPackageId()])) {
|
if (isset($this->packageToFeatureRule[$literal->getPackageId()])) {
|
||||||
$rule = $this->packageToUpdateRule[$literal->getPackageId()];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!$rule || $rule->isDisabled()) && isset($this->packageToFeatureRule[$literal->getPackageId()])) {
|
|
||||||
$rule = $this->packageToFeatureRule[$literal->getPackageId()];
|
$rule = $this->packageToFeatureRule[$literal->getPackageId()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2057,8 +2044,10 @@ class Solver
|
||||||
}
|
}
|
||||||
if ($level > 0) {
|
if ($level > 0) {
|
||||||
echo ' +' . $this->pool->packageById($packageId)."\n";
|
echo ' +' . $this->pool->packageById($packageId)."\n";
|
||||||
} else {
|
} elseif ($level < 0) {
|
||||||
echo ' -' . $this->pool->packageById($packageId)."\n";
|
echo ' -' . $this->pool->packageById($packageId)."\n";
|
||||||
|
} else {
|
||||||
|
echo ' ?' . $this->pool->packageById($packageId)."\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo "\n";
|
echo "\n";
|
||||||
|
@ -2072,4 +2061,41 @@ class Solver
|
||||||
}
|
}
|
||||||
echo "\n";
|
echo "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function printWatches()
|
||||||
|
{
|
||||||
|
echo "\nWatches:\n";
|
||||||
|
foreach ($this->watches as $literalId => $watch) {
|
||||||
|
echo ' '.$this->literalFromId($literalId)."\n";
|
||||||
|
$queue = array(array(' ', $watch));
|
||||||
|
|
||||||
|
while (!empty($queue)) {
|
||||||
|
list($indent, $watch) = array_pop($queue);
|
||||||
|
|
||||||
|
echo $indent.$watch;
|
||||||
|
|
||||||
|
if ($watch) {
|
||||||
|
echo ' [id='.$watch->getId().',watch1='.$this->literalFromId($watch->watch1).',watch2='.$this->literalFromId($watch->watch2)."]";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n";
|
||||||
|
|
||||||
|
if ($watch && ($watch->next1 == $watch || $watch->next2 == $watch)) {
|
||||||
|
if ($watch->next1 == $watch) {
|
||||||
|
echo $indent." 1 *RECURSION*";
|
||||||
|
}
|
||||||
|
if ($watch->next2 == $watch) {
|
||||||
|
echo $indent." 2 *RECURSION*";
|
||||||
|
}
|
||||||
|
} elseif ($watch && ($watch->next1 || $watch->next2)) {
|
||||||
|
$indent = str_replace(array('1', '2'), ' ', $indent);
|
||||||
|
|
||||||
|
array_push($queue, array($indent.' 2 ', $watch->next2));
|
||||||
|
array_push($queue, array($indent.' 1 ', $watch->next1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?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 SolverProblemsException extends \RuntimeException
|
||||||
|
{
|
||||||
|
protected $problems;
|
||||||
|
|
||||||
|
public function __construct(array $problems, array $learnedPool)
|
||||||
|
{
|
||||||
|
$message = '';
|
||||||
|
foreach ($problems as $i => $problem) {
|
||||||
|
$message .= '[';
|
||||||
|
foreach ($problem as $why) {
|
||||||
|
|
||||||
|
if (is_int($why) && isset($learnedPool[$why])) {
|
||||||
|
$rules = $learnedPool[$why];
|
||||||
|
} else {
|
||||||
|
$rules = $why;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($rules['packages'])) {
|
||||||
|
$message .= $this->jobToText($rules);
|
||||||
|
} else {
|
||||||
|
$message .= '(';
|
||||||
|
foreach ($rules as $rule) {
|
||||||
|
if ($rule instanceof Rule) {
|
||||||
|
if ($rule->getType() == RuleSet::TYPE_LEARNED) {
|
||||||
|
$message .= 'learned: ';
|
||||||
|
}
|
||||||
|
$message .= $rule . ', ';
|
||||||
|
} else {
|
||||||
|
$message .= 'String(' . $rule . '), ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$message .= ')';
|
||||||
|
}
|
||||||
|
$message .= ', ';
|
||||||
|
}
|
||||||
|
$message .= "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jobToText($job)
|
||||||
|
{
|
||||||
|
//$output = serialize($job);
|
||||||
|
$output = 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.implode(', ', $job['packages']).'])';
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,11 +24,13 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
{
|
{
|
||||||
protected $io;
|
protected $io;
|
||||||
protected $process;
|
protected $process;
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
public function __construct(IOInterface $io, ProcessExecutor $process = null)
|
public function __construct(IOInterface $io, ProcessExecutor $process = null, Filesystem $fs = null)
|
||||||
{
|
{
|
||||||
$this->io = $io;
|
$this->io = $io;
|
||||||
$this->process = $process ?: new ProcessExecutor;
|
$this->process = $process ?: new ProcessExecutor;
|
||||||
|
$this->filesystem = $fs ?: new Filesystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,8 +76,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
public function remove(PackageInterface $package, $path)
|
public function remove(PackageInterface $package, $path)
|
||||||
{
|
{
|
||||||
$this->enforceCleanDirectory($path);
|
$this->enforceCleanDirectory($path);
|
||||||
$fs = new Filesystem();
|
$this->filesystem->removeDirectory($path);
|
||||||
$fs->removeDirectory($path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -78,11 +78,9 @@ class LibraryInstaller implements InstallerInterface
|
||||||
*/
|
*/
|
||||||
public function install(PackageInterface $package)
|
public function install(PackageInterface $package)
|
||||||
{
|
{
|
||||||
|
$this->initializeDirs();
|
||||||
$downloadPath = $this->getInstallPath($package);
|
$downloadPath = $this->getInstallPath($package);
|
||||||
|
|
||||||
$this->filesystem->ensureDirectoryExists($this->vendorDir);
|
|
||||||
$this->filesystem->ensureDirectoryExists($this->binDir);
|
|
||||||
|
|
||||||
// remove the binaries if it appears the package files are missing
|
// remove the binaries if it appears the package files are missing
|
||||||
if (!is_readable($downloadPath) && $this->repository->hasPackage($package)) {
|
if (!is_readable($downloadPath) && $this->repository->hasPackage($package)) {
|
||||||
$this->removeBinaries($package);
|
$this->removeBinaries($package);
|
||||||
|
@ -104,11 +102,9 @@ class LibraryInstaller implements InstallerInterface
|
||||||
throw new \InvalidArgumentException('Package is not installed: '.$initial);
|
throw new \InvalidArgumentException('Package is not installed: '.$initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->initializeDirs();
|
||||||
$downloadPath = $this->getInstallPath($initial);
|
$downloadPath = $this->getInstallPath($initial);
|
||||||
|
|
||||||
$this->filesystem->ensureDirectoryExists($this->vendorDir);
|
|
||||||
$this->filesystem->ensureDirectoryExists($this->binDir);
|
|
||||||
|
|
||||||
$this->removeBinaries($initial);
|
$this->removeBinaries($initial);
|
||||||
$this->downloadManager->update($initial, $target, $downloadPath);
|
$this->downloadManager->update($initial, $target, $downloadPath);
|
||||||
$this->installBinaries($target);
|
$this->installBinaries($target);
|
||||||
|
@ -191,6 +187,14 @@ class LibraryInstaller implements InstallerInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function initializeDirs()
|
||||||
|
{
|
||||||
|
$this->filesystem->ensureDirectoryExists($this->vendorDir);
|
||||||
|
$this->filesystem->ensureDirectoryExists($this->binDir);
|
||||||
|
$this->vendorDir = realpath($this->vendorDir);
|
||||||
|
$this->binDir = realpath($this->binDir);
|
||||||
|
}
|
||||||
|
|
||||||
private function generateWindowsProxyCode($bin, $link)
|
private function generateWindowsProxyCode($bin, $link)
|
||||||
{
|
{
|
||||||
$binPath = $this->filesystem->findShortestPath($link, $bin);
|
$binPath = $this->filesystem->findShortestPath($link, $bin);
|
||||||
|
|
|
@ -15,6 +15,7 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
protected $branches;
|
protected $branches;
|
||||||
protected $rootIdentifier;
|
protected $rootIdentifier;
|
||||||
protected $infoCache = array();
|
protected $infoCache = array();
|
||||||
|
protected $isLocal = false;
|
||||||
|
|
||||||
public function __construct($url, IOInterface $io, ProcessExecutor $process = null)
|
public function __construct($url, IOInterface $io, ProcessExecutor $process = null)
|
||||||
{
|
{
|
||||||
|
@ -30,11 +31,16 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
{
|
{
|
||||||
$url = escapeshellarg($this->url);
|
$url = escapeshellarg($this->url);
|
||||||
$tmpDir = escapeshellarg($this->tmpDir);
|
$tmpDir = escapeshellarg($this->tmpDir);
|
||||||
|
|
||||||
|
if (static::isLocalUrl($url)) {
|
||||||
|
$this->isLocal = true;
|
||||||
|
} else {
|
||||||
if (is_dir($this->tmpDir)) {
|
if (is_dir($this->tmpDir)) {
|
||||||
$this->process->execute(sprintf('cd %s && git fetch origin', $tmpDir), $output);
|
$this->process->execute(sprintf('cd %s && git fetch origin', $tmpDir), $output);
|
||||||
} else {
|
} else {
|
||||||
$this->process->execute(sprintf('git clone %s %s', $url, $tmpDir), $output);
|
$this->process->execute(sprintf('git clone %s %s', $url, $tmpDir), $output);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->getTags();
|
$this->getTags();
|
||||||
$this->getBranches();
|
$this->getBranches();
|
||||||
|
@ -47,6 +53,21 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
{
|
{
|
||||||
if (null === $this->rootIdentifier) {
|
if (null === $this->rootIdentifier) {
|
||||||
$this->rootIdentifier = 'master';
|
$this->rootIdentifier = 'master';
|
||||||
|
|
||||||
|
if ($this->isLocal) {
|
||||||
|
// select currently checked out branch if master is not available
|
||||||
|
$this->process->execute(sprintf('cd %s && git branch --no-color', escapeshellarg($this->tmpDir)), $output);
|
||||||
|
$branches = $this->process->splitLines($output);
|
||||||
|
if (!in_array('* master', $branches)) {
|
||||||
|
foreach ($branches as $branch) {
|
||||||
|
if ($branch && preg_match('{^\* +(\S+)}', $branch, $match)) {
|
||||||
|
$this->rootIdentifier = $match[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// try to find a non-master remote HEAD branch
|
||||||
$this->process->execute(sprintf('cd %s && git branch --no-color -r', escapeshellarg($this->tmpDir)), $output);
|
$this->process->execute(sprintf('cd %s && git branch --no-color -r', escapeshellarg($this->tmpDir)), $output);
|
||||||
foreach ($this->process->splitLines($output) as $branch) {
|
foreach ($this->process->splitLines($output) as $branch) {
|
||||||
if ($branch && preg_match('{/HEAD +-> +[^/]+/(\S+)}', $branch, $match)) {
|
if ($branch && preg_match('{/HEAD +-> +[^/]+/(\S+)}', $branch, $match)) {
|
||||||
|
@ -55,6 +76,7 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->rootIdentifier;
|
return $this->rootIdentifier;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +123,7 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
|
|
||||||
if (!isset($composer['time'])) {
|
if (!isset($composer['time'])) {
|
||||||
$this->process->execute(sprintf('cd %s && git log -1 --format=%%at %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
$this->process->execute(sprintf('cd %s && git log -1 --format=%%at %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
||||||
$date = new \DateTime('@'.$output[0]);
|
$date = new \DateTime('@'.trim($output));
|
||||||
$composer['time'] = $date->format('Y-m-d H:i:s');
|
$composer['time'] = $date->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
$this->infoCache[$identifier] = $composer;
|
$this->infoCache[$identifier] = $composer;
|
||||||
|
@ -132,7 +154,11 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
if (null === $this->branches) {
|
if (null === $this->branches) {
|
||||||
$branches = array();
|
$branches = array();
|
||||||
|
|
||||||
$this->process->execute(sprintf('cd %s && git branch --no-color -rv', escapeshellarg($this->tmpDir)), $output);
|
$this->process->execute(sprintf(
|
||||||
|
'cd %s && git branch --no-color --no-abbrev -v %s',
|
||||||
|
escapeshellarg($this->tmpDir),
|
||||||
|
$this->isLocal ? '' : '-r'
|
||||||
|
), $output);
|
||||||
foreach ($this->process->splitLines($output) as $branch) {
|
foreach ($this->process->splitLines($output) as $branch) {
|
||||||
if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
|
if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
|
||||||
preg_match('{^ *[^/]+/(\S+) *([a-f0-9]+) .*$}', $branch, $match);
|
preg_match('{^ *[^/]+/(\S+) *([a-f0-9]+) .*$}', $branch, $match);
|
||||||
|
@ -169,6 +195,15 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// local filesystem
|
||||||
|
if (static::isLocalUrl($url)) {
|
||||||
|
$process = new ProcessExecutor();
|
||||||
|
// check whether there is a git repo in that path
|
||||||
|
if ($process->execute(sprintf('cd %s && git show', escapeshellarg($url)), $output) === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$deep) {
|
if (!$deep) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ class HgDriver extends VcsDriver implements VcsDriverInterface
|
||||||
|
|
||||||
if (!isset($composer['time'])) {
|
if (!isset($composer['time'])) {
|
||||||
$this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
$this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
||||||
$date = new \DateTime($output[0]);
|
$date = new \DateTime(trim($output));
|
||||||
$composer['time'] = $date->format('Y-m-d H:i:s');
|
$composer['time'] = $date->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
$this->infoCache[$identifier] = $composer;
|
$this->infoCache[$identifier] = $composer;
|
||||||
|
|
|
@ -68,4 +68,9 @@ abstract class VcsDriver
|
||||||
$rfs = new RemoteFilesystem($this->io);
|
$rfs = new RemoteFilesystem($this->io);
|
||||||
return $rfs->getContents($this->url, $url, false);
|
return $rfs->getContents($this->url, $url, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function isLocalUrl($url)
|
||||||
|
{
|
||||||
|
return (Boolean) preg_match('{^(file://|/|[a-z]:[\\\\/])}i', $url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,6 @@ class VcsRepository extends ArrayRepository
|
||||||
|
|
||||||
public function __construct(array $config, IOInterface $io, array $drivers = null)
|
public function __construct(array $config, IOInterface $io, array $drivers = null)
|
||||||
{
|
{
|
||||||
if (!filter_var($config['url'], FILTER_VALIDATE_URL)) {
|
|
||||||
throw new \UnexpectedValueException('Invalid url given for VCS repository: '.$config['url']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->drivers = $drivers ?: array(
|
$this->drivers = $drivers ?: array(
|
||||||
'Composer\Repository\Vcs\GitHubDriver',
|
'Composer\Repository\Vcs\GitHubDriver',
|
||||||
'Composer\Repository\Vcs\GitBitbucketDriver',
|
'Composer\Repository\Vcs\GitBitbucketDriver',
|
||||||
|
|
|
@ -30,4 +30,65 @@ class PoolTest extends TestCase
|
||||||
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
||||||
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \RuntimeException
|
||||||
|
*/
|
||||||
|
public function testGetPriorityForNotRegisteredRepository()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
|
||||||
|
$pool->getPriority($repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetPriorityWhenRepositoryIsRegistered()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$firstRepository = new ArrayRepository;
|
||||||
|
$pool->addRepository($firstRepository);
|
||||||
|
$secondRepository = new ArrayRepository;
|
||||||
|
$pool->addRepository($secondRepository);
|
||||||
|
|
||||||
|
$firstPriority = $pool->getPriority($firstRepository);
|
||||||
|
$secondPriority = $pool->getPriority($secondRepository);
|
||||||
|
|
||||||
|
$this->assertEquals(0, $firstPriority);
|
||||||
|
$this->assertEquals(1, $secondPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPackageById()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
$package = $this->getPackage('foo', '1');
|
||||||
|
|
||||||
|
$repository->addPackage($package);
|
||||||
|
$pool->addRepository($repository);
|
||||||
|
|
||||||
|
$this->assertSame($package, $pool->packageById(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWhatProvidesWhenPackageCannotBeFound()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
|
||||||
|
$this->assertEquals(array(), $pool->whatProvides('foo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetMaxId()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
$firstPackage = $this->getPackage('foo', '1');
|
||||||
|
$secondPackage = $this->getPackage('foo1', '1');
|
||||||
|
|
||||||
|
$this->assertEquals(0, $pool->getMaxId());
|
||||||
|
|
||||||
|
$repository->addPackage($firstPackage);
|
||||||
|
$repository->addPackage($secondPackage);
|
||||||
|
$pool->addRepository($repository);
|
||||||
|
|
||||||
|
$this->assertEquals(2, $pool->getMaxId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,4 +46,16 @@ class RequestTest extends TestCase
|
||||||
),
|
),
|
||||||
$request->getJobs());
|
$request->getJobs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUpdateAll()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$request = new Request($pool);
|
||||||
|
|
||||||
|
$request->updateAll();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array(array('cmd' => 'update-all', 'packages' => array())),
|
||||||
|
$request->getJobs());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
new Rule(array(), 'job1', null),
|
new Rule(array(), 'job1', null),
|
||||||
new Rule(array(), 'job2', null),
|
new Rule(array(), 'job2', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_UPDATE => array(
|
RuleSet::TYPE_FEATURE => array(
|
||||||
new Rule(array(), 'update1', null),
|
new Rule(array(), 'update1', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_PACKAGE => array(),
|
RuleSet::TYPE_PACKAGE => array(),
|
||||||
|
@ -39,15 +39,32 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
$ruleSetIterator = new RuleSetIterator($this->rules);
|
$ruleSetIterator = new RuleSetIterator($this->rules);
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
foreach ($ruleSetIterator as $rule)
|
foreach ($ruleSetIterator as $rule) {
|
||||||
{
|
|
||||||
$result[] = $rule;
|
$result[] = $rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
$expected = array(
|
$expected = array(
|
||||||
$this->rules[RuleSet::TYPE_JOB][0],
|
$this->rules[RuleSet::TYPE_JOB][0],
|
||||||
$this->rules[RuleSet::TYPE_JOB][1],
|
$this->rules[RuleSet::TYPE_JOB][1],
|
||||||
$this->rules[RuleSet::TYPE_UPDATE][0],
|
$this->rules[RuleSet::TYPE_FEATURE][0],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testKeys()
|
||||||
|
{
|
||||||
|
$ruleSetIterator = new RuleSetIterator($this->rules);
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach ($ruleSetIterator as $key => $rule) {
|
||||||
|
$result[] = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
RuleSet::TYPE_JOB,
|
||||||
|
RuleSet::TYPE_JOB,
|
||||||
|
RuleSet::TYPE_FEATURE,
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
|
|
|
@ -14,8 +14,10 @@ namespace Composer\Test\DependencyResolver;
|
||||||
|
|
||||||
use Composer\DependencyResolver\Rule;
|
use Composer\DependencyResolver\Rule;
|
||||||
use Composer\DependencyResolver\RuleSet;
|
use Composer\DependencyResolver\RuleSet;
|
||||||
|
use Composer\DependencyResolver\Literal;
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
class RuleSetTest extends \PHPUnit_Framework_TestCase
|
class RuleSetTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testAdd()
|
public function testAdd()
|
||||||
{
|
{
|
||||||
|
@ -25,10 +27,9 @@ class RuleSetTest extends \PHPUnit_Framework_TestCase
|
||||||
new Rule(array(), 'job1', null),
|
new Rule(array(), 'job1', null),
|
||||||
new Rule(array(), 'job2', null),
|
new Rule(array(), 'job2', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_UPDATE => array(
|
RuleSet::TYPE_FEATURE => array(
|
||||||
new Rule(array(), 'update1', null),
|
new Rule(array(), 'update1', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_FEATURE => array(),
|
|
||||||
RuleSet::TYPE_LEARNED => array(),
|
RuleSet::TYPE_LEARNED => array(),
|
||||||
RuleSet::TYPE_CHOICE => array(),
|
RuleSet::TYPE_CHOICE => array(),
|
||||||
);
|
);
|
||||||
|
@ -36,9 +37,133 @@ class RuleSetTest extends \PHPUnit_Framework_TestCase
|
||||||
$ruleSet = new RuleSet;
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
$ruleSet->add($rules[RuleSet::TYPE_JOB][0], RuleSet::TYPE_JOB);
|
$ruleSet->add($rules[RuleSet::TYPE_JOB][0], RuleSet::TYPE_JOB);
|
||||||
$ruleSet->add($rules[RuleSet::TYPE_UPDATE][0], RuleSet::TYPE_UPDATE);
|
$ruleSet->add($rules[RuleSet::TYPE_FEATURE][0], RuleSet::TYPE_FEATURE);
|
||||||
$ruleSet->add($rules[RuleSet::TYPE_JOB][1], RuleSet::TYPE_JOB);
|
$ruleSet->add($rules[RuleSet::TYPE_JOB][1], RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
$this->assertEquals($rules, $ruleSet->getRules());
|
$this->assertEquals($rules, $ruleSet->getRules());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OutOfBoundsException
|
||||||
|
*/
|
||||||
|
public function testAddWhenTypeIsNotRecognized()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$ruleSet->add(new Rule(array(), 'job1', null), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCount()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$ruleSet->add(new Rule(array(), 'job1', null), RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add(new Rule(array(), 'job2', null), RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
$this->assertEquals(2, $ruleSet->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRuleById()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$ruleSet->add($rule, RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
$this->assertSame($rule, $ruleSet->ruleById(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetIterator()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
||||||
|
|
||||||
|
$iterator = $ruleSet->getIterator();
|
||||||
|
|
||||||
|
$this->assertSame($rule1, $iterator->current());
|
||||||
|
$iterator->next();
|
||||||
|
$this->assertSame($rule2, $iterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetIteratorFor()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
|
||||||
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
||||||
|
|
||||||
|
$iterator = $ruleSet->getIteratorFor(RuleSet::TYPE_FEATURE);
|
||||||
|
|
||||||
|
$this->assertSame($rule2, $iterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetIteratorWithout()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
|
||||||
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
||||||
|
|
||||||
|
$iterator = $ruleSet->getIteratorWithout(RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
$this->assertSame($rule2, $iterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testContainsEqual()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$rule = $this->getRuleMock();
|
||||||
|
$rule->expects($this->any())
|
||||||
|
->method('getHash')
|
||||||
|
->will($this->returnValue('rule_1_hash'));
|
||||||
|
$rule->expects($this->any())
|
||||||
|
->method('equals')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$rule2 = $this->getRuleMock();
|
||||||
|
$rule2->expects($this->any())
|
||||||
|
->method('getHash')
|
||||||
|
->will($this->returnValue('rule_2_hash'));
|
||||||
|
|
||||||
|
$rule3 = $this->getRuleMock();
|
||||||
|
$rule3->expects($this->any())
|
||||||
|
->method('getHash')
|
||||||
|
->will($this->returnValue('rule_1_hash'));
|
||||||
|
$rule3->expects($this->any())
|
||||||
|
->method('equal')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$ruleSet->add($rule, RuleSet::TYPE_FEATURE);
|
||||||
|
|
||||||
|
$this->assertTrue($ruleSet->containsEqual($rule));
|
||||||
|
$this->assertFalse($ruleSet->containsEqual($rule2));
|
||||||
|
$this->assertFalse($ruleSet->containsEqual($rule3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToString()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
||||||
|
$rule = new Rule(array($literal), 'job1', null);
|
||||||
|
|
||||||
|
$ruleSet->add($rule, RuleSet::TYPE_FEATURE);
|
||||||
|
|
||||||
|
$this->assertContains('FEATURE : (+foo-2.1.0.0)', $ruleSet->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRuleMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Composer\DependencyResolver\Rule')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
<?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\Test\DependencyResolver;
|
||||||
|
|
||||||
|
use Composer\DependencyResolver\Rule;
|
||||||
|
use Composer\DependencyResolver\Literal;
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
|
class RuleTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetHash()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
|
||||||
|
$this->assertEquals('123', $rule->getHash());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetAndGetId()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->setId(666);
|
||||||
|
|
||||||
|
$this->assertEquals(666, $rule->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithDifferentHashes()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2->ruleHash = '321';
|
||||||
|
|
||||||
|
$this->assertFalse($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithDifferentLiterals()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(1));
|
||||||
|
$rule = new Rule(array($literal), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(12));
|
||||||
|
$rule2 = new Rule(array($literal), 'job1', null);
|
||||||
|
$rule2->ruleHash = '123';
|
||||||
|
|
||||||
|
$this->assertFalse($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithDifferLiteralsQuantity()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(1));
|
||||||
|
$literal2 = $this->getLiteralMock();
|
||||||
|
$literal2->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(12));
|
||||||
|
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
$rule2 = new Rule(array($literal), 'job1', null);
|
||||||
|
$rule2->ruleHash = '123';
|
||||||
|
|
||||||
|
$this->assertFalse($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithThisSameLiterals()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(1));
|
||||||
|
$literal2 = $this->getLiteralMock();
|
||||||
|
$literal2->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(12));
|
||||||
|
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
$rule2 = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
|
||||||
|
$this->assertTrue($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetAndGetType()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->setType('someType');
|
||||||
|
|
||||||
|
$this->assertEquals('someType', $rule->getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnable()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->disable();
|
||||||
|
$rule->enable();
|
||||||
|
|
||||||
|
$this->assertTrue($rule->isEnabled());
|
||||||
|
$this->assertFalse($rule->isDisabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisable()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->enable();
|
||||||
|
$rule->disable();
|
||||||
|
|
||||||
|
$this->assertTrue($rule->isDisabled());
|
||||||
|
$this->assertFalse($rule->isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetWeak()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->setWeak(true);
|
||||||
|
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2->setWeak(false);
|
||||||
|
|
||||||
|
$this->assertTrue($rule->isWeak());
|
||||||
|
$this->assertFalse($rule2->isWeak());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAssertions()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal2 = $this->getLiteralMock();
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
$rule2 = new Rule(array($literal), 'job1', null);
|
||||||
|
|
||||||
|
$this->assertFalse($rule->isAssertion());
|
||||||
|
$this->assertTrue($rule2->isAssertion());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToString()
|
||||||
|
{
|
||||||
|
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
||||||
|
$literal2 = new Literal($this->getPackage('baz', '1.1'), false);
|
||||||
|
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
|
||||||
|
$this->assertEquals('(-baz-1.1.0.0|+foo-2.1.0.0)', $rule->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLiteralMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Composer\DependencyResolver\Literal')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ use Composer\DependencyResolver\DefaultPolicy;
|
||||||
use Composer\DependencyResolver\Pool;
|
use Composer\DependencyResolver\Pool;
|
||||||
use Composer\DependencyResolver\Request;
|
use Composer\DependencyResolver\Request;
|
||||||
use Composer\DependencyResolver\Solver;
|
use Composer\DependencyResolver\Solver;
|
||||||
|
use Composer\DependencyResolver\SolverProblemsException;
|
||||||
use Composer\Package\Link;
|
use Composer\Package\Link;
|
||||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||||
use Composer\Test\TestCase;
|
use Composer\Test\TestCase;
|
||||||
|
@ -54,13 +55,30 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInstallNonExistingPackageFails()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Reporting this failure is not implemented/working yet');
|
||||||
|
|
||||||
|
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('B');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$transaction = $this->solver->solve($this->request);
|
||||||
|
$this->fail('Unsolvable conflict did not resolve in exception.');
|
||||||
|
} catch (SolverProblemsException $e) {
|
||||||
|
// TODO assert problem properties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function testSolverInstallWithDeps()
|
public function testSolverInstallWithDeps()
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||||
|
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('<', '1.1'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('<', '1.1'), 'requires')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -122,12 +140,12 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0.0.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0.0.0'), 'requires')));
|
||||||
|
|
||||||
$this->request->install('A', new VersionConstraint('=', '1.0.0.0'));
|
$this->request->install('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||||
$this->request->install('B', new VersionConstraint('=', '1.1.0.0'));
|
$this->request->install('B', $this->getVersionConstraint('=', '1.1.0.0'));
|
||||||
$this->request->update('A', new VersionConstraint('=', '1.0.0.0'));
|
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||||
$this->request->update('B', new VersionConstraint('=', '1.0.0.0'));
|
$this->request->update('B', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||||
|
|
||||||
$this->checkSolverResult(array(
|
$this->checkSolverResult(array(
|
||||||
array('job' => 'update', 'from' => $packageB, 'to' => $newPackageB),
|
array('job' => 'update', 'from' => $packageB, 'to' => $newPackageB),
|
||||||
|
@ -147,6 +165,26 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSolverUpdateAll()
|
||||||
|
{
|
||||||
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.1'));
|
||||||
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||||
|
|
||||||
|
$packageA->setRequires(array(new Link('A', 'B', null, 'requires')));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
|
$this->request->updateAll();
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'update', 'from' => $packageB, 'to' => $newPackageB),
|
||||||
|
array('job' => 'update', 'from' => $packageA, 'to' => $newPackageA),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSolverUpdateCurrent()
|
public function testSolverUpdateCurrent()
|
||||||
{
|
{
|
||||||
$this->repoInstalled->addPackage($this->getPackage('A', '1.0'));
|
$this->repoInstalled->addPackage($this->getPackage('A', '1.0'));
|
||||||
|
@ -158,6 +196,22 @@ class SolverTest extends TestCase
|
||||||
$this->checkSolverResult(array());
|
$this->checkSolverResult(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSolverUpdateOnlyUpdatesSelectedPackage()
|
||||||
|
{
|
||||||
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($packageAnewer = $this->getPackage('A', '1.1'));
|
||||||
|
$this->repo->addPackage($packageBnewer = $this->getPackage('B', '1.1'));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->update('A');
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'update', 'from' => $packageA, 'to' => $packageAnewer),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSolverUpdateConstrained()
|
public function testSolverUpdateConstrained()
|
||||||
{
|
{
|
||||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
@ -165,7 +219,7 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
$this->request->install('A', new VersionConstraint('<', '2.0.0.0'));
|
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||||
$this->request->update('A');
|
$this->request->update('A');
|
||||||
|
|
||||||
$this->checkSolverResult(array(array(
|
$this->checkSolverResult(array(array(
|
||||||
|
@ -182,8 +236,26 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
$this->request->install('A', new VersionConstraint('<', '2.0.0.0'));
|
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||||
$this->request->update('A', new VersionConstraint('=', '1.0.0.0'));
|
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(array(
|
||||||
|
'job' => 'update',
|
||||||
|
'from' => $packageA,
|
||||||
|
'to' => $newPackageA,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSolverUpdateFullyConstrainedPrunesInstalledPackages()
|
||||||
|
{
|
||||||
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repoInstalled->addPackage($this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
||||||
|
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||||
|
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||||
|
|
||||||
$this->checkSolverResult(array(array(
|
$this->checkSolverResult(array(array(
|
||||||
'job' => 'update',
|
'job' => 'update',
|
||||||
|
@ -202,7 +274,7 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||||
$this->repo->addPackage($packageC = $this->getPackage('C', '1.1'));
|
$this->repo->addPackage($packageC = $this->getPackage('C', '1.1'));
|
||||||
$this->repo->addPackage($this->getPackage('D', '1.0'));
|
$this->repo->addPackage($this->getPackage('D', '1.0'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('<', '1.1'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('<', '1.1'), 'requires')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -224,8 +296,8 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($middlePackageB = $this->getPackage('B', '1.0'));
|
$this->repo->addPackage($middlePackageB = $this->getPackage('B', '1.0'));
|
||||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||||
$this->repo->addPackage($oldPackageB = $this->getPackage('B', '0.9'));
|
$this->repo->addPackage($oldPackageB = $this->getPackage('B', '0.9'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('<', '1.1'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('<', '1.1'), 'requires')));
|
||||||
$packageA->setConflicts(array(new Link('A', 'B', new VersionConstraint('<', '1.0'), 'conflicts')));
|
$packageA->setConflicts(array(new Link('A', 'B', $this->getVersionConstraint('<', '1.0'), 'conflicts')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -271,8 +343,8 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
||||||
$this->repo->addPackage($packageB = $this->getPackage('B', '0.8'));
|
$this->repo->addPackage($packageB = $this->getPackage('B', '0.8'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageQ->setProvides(array(new Link('Q', 'B', new VersionConstraint('=', '1.0'), 'provides')));
|
$packageQ->setProvides(array(new Link('Q', 'B', $this->getVersionConstraint('=', '1.0'), 'provides')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -289,8 +361,8 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
||||||
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageQ->setReplaces(array(new Link('Q', 'B', new VersionConstraint('>=', '1.0'), 'replaces')));
|
$packageQ->setReplaces(array(new Link('Q', 'B', $this->getVersionConstraint('>=', '1.0'), 'replaces')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -306,8 +378,8 @@ class SolverTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageQ->setReplaces(array(new Link('Q', 'B', new VersionConstraint('>=', '1.0'), 'replaces')));
|
$packageQ->setReplaces(array(new Link('Q', 'B', $this->getVersionConstraint('>=', '1.0'), 'replaces')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -324,8 +396,8 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
|
||||||
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageQ->setReplaces(array(new Link('Q', 'B', new VersionConstraint('>=', '1.0'), 'replaces')));
|
$packageQ->setReplaces(array(new Link('Q', 'B', $this->getVersionConstraint('>=', '1.0'), 'replaces')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -342,24 +414,24 @@ class SolverTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageX = $this->getPackage('X', '1.0'));
|
$this->repo->addPackage($packageX = $this->getPackage('X', '1.0'));
|
||||||
$packageX->setRequires(array(
|
$packageX->setRequires(array(
|
||||||
new Link('X', 'A', new VersionConstraint('>=', '2.0.0.0'), 'requires'),
|
new Link('X', 'A', $this->getVersionConstraint('>=', '2.0.0.0'), 'requires'),
|
||||||
new Link('X', 'B', new VersionConstraint('>=', '2.0.0.0'), 'requires')));
|
new Link('X', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'requires')));
|
||||||
|
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0.0'));
|
||||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '2.1.0'));
|
$this->repo->addPackage($newPackageA = $this->getPackage('A', '2.1.0'));
|
||||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '2.1.0'));
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '2.1.0'));
|
||||||
|
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '2.0.0.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'requires')));
|
||||||
|
|
||||||
// new package A depends on version of package B that does not exist
|
// new package A depends on version of package B that does not exist
|
||||||
// => new package A is not installable
|
// => new package A is not installable
|
||||||
$newPackageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '2.2.0.0'), 'requires')));
|
$newPackageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '2.2.0.0'), 'requires')));
|
||||||
|
|
||||||
// add a package S replacing both A and B, so that S and B or S and A cannot be simultaneously installed
|
// add a package S replacing both A and B, so that S and B or S and A cannot be simultaneously installed
|
||||||
// but an alternative option for A and B both exists
|
// but an alternative option for A and B both exists
|
||||||
// this creates a more difficult so solve conflict
|
// this creates a more difficult so solve conflict
|
||||||
$this->repo->addPackage($packageS = $this->getPackage('S', '2.0.0'));
|
$this->repo->addPackage($packageS = $this->getPackage('S', '2.0.0'));
|
||||||
$packageS->setReplaces(array(new Link('S', 'A', new VersionConstraint('>=', '2.0.0.0'), 'replaces'), new Link('S', 'B', new VersionConstraint('>=', '2.0.0.0'), 'replaces')));
|
$packageS->setReplaces(array(new Link('S', 'A', $this->getVersionConstraint('>=', '2.0.0.0'), 'replaces'), new Link('S', 'B', $this->getVersionConstraint('>=', '2.0.0.0'), 'replaces')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -377,8 +449,8 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repo->addPackage($packageB1 = $this->getPackage('B', '0.9'));
|
$this->repo->addPackage($packageB1 = $this->getPackage('B', '0.9'));
|
||||||
$this->repo->addPackage($packageB2 = $this->getPackage('B', '1.1'));
|
$this->repo->addPackage($packageB2 = $this->getPackage('B', '1.1'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageB2->setRequires(array(new Link('B', 'A', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageB2->setRequires(array(new Link('B', 'A', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -398,10 +470,10 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
$this->repo->addPackage($packageC = $this->getPackage('C', '1.0'));
|
$this->repo->addPackage($packageC = $this->getPackage('C', '1.0'));
|
||||||
$this->repo->addPackage($packageD = $this->getPackage('D', '1.0'));
|
$this->repo->addPackage($packageD = $this->getPackage('D', '1.0'));
|
||||||
$packageA->setRequires(array(new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageB->setRequires(array(new Link('B', 'Virtual', new VersionConstraint('>=', '1.0'), 'requires')));
|
$packageB->setRequires(array(new Link('B', 'Virtual', $this->getVersionConstraint('>=', '1.0'), 'requires')));
|
||||||
$packageC->setRequires(array(new Link('C', 'Virtual', new VersionConstraint('==', '1.0'), 'provides')));
|
$packageC->setRequires(array(new Link('C', 'Virtual', $this->getVersionConstraint('==', '1.0'), 'provides')));
|
||||||
$packageD->setRequires(array(new Link('D', 'Virtual', new VersionConstraint('==', '1.0'), 'provides')));
|
$packageD->setRequires(array(new Link('D', 'Virtual', $this->getVersionConstraint('==', '1.0'), 'provides')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -414,6 +486,119 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a replacer D replaces B and C with C not otherwise available,
|
||||||
|
* D must be installed instead of the original B.
|
||||||
|
*/
|
||||||
|
public function testUseReplacerIfNecessary()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($packageD = $this->getPackage('D', '1.0'));
|
||||||
|
$this->repo->addPackage($packageD2 = $this->getPackage('D', '1.1'));
|
||||||
|
|
||||||
|
$packageA->setRequires(array(
|
||||||
|
new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires'),
|
||||||
|
new Link('A', 'C', $this->getVersionConstraint('>=', '1.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageD->setReplaces(array(
|
||||||
|
new Link('D', 'B', $this->getVersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
new Link('D', 'C', $this->getVersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageD2->setReplaces(array(
|
||||||
|
new Link('D', 'B', $this->getVersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
new Link('D', 'C', $this->getVersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'install', 'package' => $packageD2),
|
||||||
|
array('job' => 'install', 'package' => $packageA),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIssue265()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA1 = $this->getPackage('A', '2.0.999999-dev'));
|
||||||
|
$this->repo->addPackage($packageA2 = $this->getPackage('A', '2.1-dev'));
|
||||||
|
$this->repo->addPackage($packageA3 = $this->getPackage('A', '2.2-dev'));
|
||||||
|
$this->repo->addPackage($packageB1 = $this->getPackage('B', '2.0.10'));
|
||||||
|
$this->repo->addPackage($packageB2 = $this->getPackage('B', '2.0.9'));
|
||||||
|
$this->repo->addPackage($packageC = $this->getPackage('C', '2.0-dev'));
|
||||||
|
$this->repo->addPackage($packageD = $this->getPackage('D', '2.0.9'));
|
||||||
|
|
||||||
|
$packageC->setRequires(array(
|
||||||
|
new Link('C', 'A', $this->getVersionConstraint('>=', '2.0'), 'requires'),
|
||||||
|
new Link('C', 'D', $this->getVersionConstraint('>=', '2.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageD->setRequires(array(
|
||||||
|
new Link('D', 'A', $this->getVersionConstraint('>=', '2.1'), 'requires'),
|
||||||
|
new Link('D', 'B', $this->getVersionConstraint('>=', '2.0-dev'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageB1->setRequires(array(new Link('B', 'A', $this->getVersionConstraint('==', '2.1.0.0-dev'), 'requires')));
|
||||||
|
$packageB2->setRequires(array(new Link('B', 'A', $this->getVersionConstraint('==', '2.1.0.0-dev'), 'requires')));
|
||||||
|
|
||||||
|
$packageB2->setReplaces(array(new Link('B', 'D', $this->getVersionConstraint('==', '2.0.9.0'), 'replaces')));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('C', $this->getVersionConstraint('==', '2.0.0.0-dev'));
|
||||||
|
|
||||||
|
$this->setExpectedException('Composer\DependencyResolver\SolverProblemsException');
|
||||||
|
|
||||||
|
$this->solver->solve($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConflictResultEmpty()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));;
|
||||||
|
|
||||||
|
$packageA->setConflicts(array(
|
||||||
|
new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'conflicts'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
|
$this->request->install('B');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$transaction = $this->solver->solve($this->request);
|
||||||
|
$this->fail('Unsolvable conflict did not resolve in exception.');
|
||||||
|
} catch (SolverProblemsException $e) {
|
||||||
|
// TODO assert problem properties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUnsatisfiableRequires()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
|
||||||
|
$packageA->setRequires(array(
|
||||||
|
new Link('A', 'B', $this->getVersionConstraint('>=', '2.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$transaction = $this->solver->solve($this->request);
|
||||||
|
$this->fail('Unsolvable conflict did not resolve in exception.');
|
||||||
|
} catch (SolverProblemsException $e) {
|
||||||
|
// TODO assert problem properties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function reposComplete()
|
protected function reposComplete()
|
||||||
{
|
{
|
||||||
$this->pool->addRepository($this->repoInstalled);
|
$this->pool->addRepository($this->repoInstalled);
|
||||||
|
@ -443,5 +628,4 @@ class SolverTest extends TestCase
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?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\Test\Downloader;
|
||||||
|
|
||||||
|
use Composer\Downloader\GitDownloader;
|
||||||
|
|
||||||
|
class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testDownloadForPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->download($packageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDownload()
|
||||||
|
{
|
||||||
|
$expectedGitCommand = $this->getCmd('git clone \'https://github.com/l3l0/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://github.com/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->once())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitCommand));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->download($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testUpdateforPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$initialPackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->update($initialPackageMock, $sourcePackageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdate()
|
||||||
|
{
|
||||||
|
$expectedGitUpdateCommand = $this->getCmd('cd \'composerPath\' && git fetch && git checkout \'ref\' && git reset --hard \'ref\'');
|
||||||
|
$expectedGitResetCommand = $this->getCmd('cd \'composerPath\' && git status --porcelain');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://github.com/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->at(0))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitResetCommand));
|
||||||
|
$processExecutor->expects($this->at(1))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitUpdateCommand));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->update($packageMock, $packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemove()
|
||||||
|
{
|
||||||
|
$expectedGitResetCommand = $this->getCmd('cd \'composerPath\' && git status --porcelain');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->any())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitResetCommand));
|
||||||
|
$filesystem = $this->getMock('Composer\Util\Filesystem');
|
||||||
|
$filesystem->expects($this->any())
|
||||||
|
->method('removeDirectory')
|
||||||
|
->with($this->equalTo('composerPath'));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor, $filesystem);
|
||||||
|
$downloader->remove($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInstallationSource()
|
||||||
|
{
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
|
||||||
|
$this->assertEquals('source', $downloader->getInstallationSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCmd($cmd)
|
||||||
|
{
|
||||||
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
|
return strtr($cmd, "'", '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?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\Test\Downloader;
|
||||||
|
|
||||||
|
use Composer\Downloader\HgDownloader;
|
||||||
|
|
||||||
|
class HgDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testDownloadForPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->download($packageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDownload()
|
||||||
|
{
|
||||||
|
$expectedGitCommand = $this->getCmd('hg clone \'https://mercurial.dev/l3l0/composer\' \'composerPath\' && cd \'composerPath\' && hg up \'ref\'');
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://mercurial.dev/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->once())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitCommand));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->download($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testUpdateforPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$initialPackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->update($initialPackageMock, $sourcePackageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdate()
|
||||||
|
{
|
||||||
|
$expectedUpdateCommand = $this->getCmd('cd \'composerPath\' && hg pull && hg up \'ref\'');
|
||||||
|
$expectedResetCommand = $this->getCmd('cd \'composerPath\' && hg st');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://github.com/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->at(0))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedResetCommand));
|
||||||
|
$processExecutor->expects($this->at(1))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedUpdateCommand));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->update($packageMock, $packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemove()
|
||||||
|
{
|
||||||
|
$expectedResetCommand = $this->getCmd('cd \'composerPath\' && hg st');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->any())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedResetCommand));
|
||||||
|
$filesystem = $this->getMock('Composer\Util\Filesystem');
|
||||||
|
$filesystem->expects($this->any())
|
||||||
|
->method('removeDirectory')
|
||||||
|
->with($this->equalTo('composerPath'));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor, $filesystem);
|
||||||
|
$downloader->remove($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInstallationSource()
|
||||||
|
{
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
|
||||||
|
$this->assertEquals('source', $downloader->getInstallationSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCmd($cmd)
|
||||||
|
{
|
||||||
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
|
return strtr($cmd, "'", '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
<?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\Test\IO;
|
||||||
|
|
||||||
|
use Composer\IO\ConsoleIO;
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
|
class ConsoleIOTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testIsInteractive()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$inputMock->expects($this->at(0))
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$inputMock->expects($this->at(1))
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
|
||||||
|
$this->assertTrue($consoleIO->isInteractive());
|
||||||
|
$this->assertFalse($consoleIO->isInteractive());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWrite()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$outputMock->expects($this->once())
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo('some information about something'), $this->equalTo(false));
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->write('some information about something', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOverwrite()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$outputMock->expects($this->at(0))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(19))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(20))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo('some information'), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(21))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo(' '), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(24))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo(' '), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(25))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(28))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(29))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo(''));
|
||||||
|
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->overwrite('some information', true, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsk()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$dialogMock->expects($this->once())
|
||||||
|
->method('ask')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
|
||||||
|
$this->equalTo('Why?'),
|
||||||
|
$this->equalTo('default'));
|
||||||
|
$helperMock->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('dialog'))
|
||||||
|
->will($this->returnValue($dialogMock));
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->ask('Why?', 'default');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAskConfirmation()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$dialogMock->expects($this->once())
|
||||||
|
->method('askConfirmation')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
|
||||||
|
$this->equalTo('Why?'),
|
||||||
|
$this->equalTo('default'));
|
||||||
|
$helperMock->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('dialog'))
|
||||||
|
->will($this->returnValue($dialogMock));
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->askConfirmation('Why?', 'default');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAskAndValidate()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$dialogMock->expects($this->once())
|
||||||
|
->method('askAndValidate')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
|
||||||
|
$this->equalTo('Why?'),
|
||||||
|
$this->equalTo('validator'),
|
||||||
|
$this->equalTo(10),
|
||||||
|
$this->equalTo('default'));
|
||||||
|
$helperMock->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('dialog'))
|
||||||
|
->will($this->returnValue($dialogMock));
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->askAndValidate('Why?', 'validator', 10, 'default');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetAndGetAuthorization()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->setAuthorization('repoName', 'l3l0', 'passwd');
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array('username' => 'l3l0', 'password' => 'passwd'),
|
||||||
|
$consoleIO->getAuthorization('repoName')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetAuthorizationWhenDidNotSet()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array('username' => null, 'password' => null),
|
||||||
|
$consoleIO->getAuthorization('repoName')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasAuthorization()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->setAuthorization('repoName', 'l3l0', 'passwd');
|
||||||
|
|
||||||
|
$this->assertTrue($consoleIO->hasAuthorization('repoName'));
|
||||||
|
$this->assertFalse($consoleIO->hasAuthorization('repoName2'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetLastUsername()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->setAuthorization('repoName', 'l3l0', 'passwd');
|
||||||
|
$consoleIO->setAuthorization('repoName2', 'l3l02', 'passwd2');
|
||||||
|
|
||||||
|
$this->assertEquals('l3l02', $consoleIO->getLastUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetLastPassword()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->setAuthorization('repoName', 'l3l0', 'passwd');
|
||||||
|
$consoleIO->setAuthorization('repoName2', 'l3l02', 'passwd2');
|
||||||
|
|
||||||
|
$this->assertEquals('passwd2', $consoleIO->getLastPassword());
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,6 +133,9 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testUnicode()
|
public function testUnicode()
|
||||||
{
|
{
|
||||||
|
if (!function_exists('mb_convert_encoding')) {
|
||||||
|
$this->markTestSkipped('Test requires the mbstring extension');
|
||||||
|
}
|
||||||
$data = array("Žluťoučký \" kůň" => "úpěl ďábelské ódy za €");
|
$data = array("Žluťoučký \" kůň" => "úpěl ďábelské ódy za €");
|
||||||
$json = '{
|
$json = '{
|
||||||
"Žluťoučký \" kůň": "úpěl ďábelské ódy za €"
|
"Žluťoučký \" kůň": "úpěl ďábelské ódy za €"
|
||||||
|
@ -143,6 +146,9 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testEscapedSlashes()
|
public function testEscapedSlashes()
|
||||||
{
|
{
|
||||||
|
if (!function_exists('mb_convert_encoding')) {
|
||||||
|
$this->markTestSkipped('Test requires the mbstring extension');
|
||||||
|
}
|
||||||
$data = "\\/fooƌ";
|
$data = "\\/fooƌ";
|
||||||
|
|
||||||
$this->assertJsonFormat('"\\\\\\/fooƌ"', $data, JSON_UNESCAPED_UNICODE);
|
$this->assertJsonFormat('"\\\\\\/fooƌ"', $data, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Test;
|
||||||
|
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Package\MemoryPackage;
|
use Composer\Package\MemoryPackage;
|
||||||
|
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||||
|
|
||||||
abstract class TestCase extends \PHPUnit_Framework_TestCase
|
abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
@ -26,6 +27,14 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getVersionConstraint($operator, $version)
|
||||||
|
{
|
||||||
|
return new VersionConstraint(
|
||||||
|
$operator,
|
||||||
|
self::$versionParser->normalize($version)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getPackage($name, $version)
|
protected function getPackage($name, $version)
|
||||||
{
|
{
|
||||||
$normVersion = self::$versionParser->normalize($version);
|
$normVersion = self::$versionParser->normalize($version);
|
||||||
|
|
Loading…
Reference in New Issue