composer / composer

Dependency Manager for PHP
https://getcomposer.org/
MIT License
28.59k stars 4.55k forks source link

Inconsistent stability with ~ versions #1855

Closed simensen closed 11 years ago

simensen commented 11 years ago

I wanted to upgrade some of my dependencies now that 2.3.0-BETA1 of Symfony was released. It has exposed some really weird version conflicts when using ~ syntax.

The above does not actually work. When I try this I get the following output:

Problem 1
  - The requested package symfony/console ~2.3@beta could not be found.

If I change the Sculpin require dependency to ~2.3-beta it seems to work as advertised in that I get symfony/console at 2.3.0-BETA1. However, it drops my composer/composer dependency back to 1.0.0-alpha6. I think that it does this because the version constraint created by ~2.3-beta (in Sculpin's composer.json) is not compatible with ~2.3@dev (in Composer's composer.json).

The whole reason I need to have Sculpin require symfony/console at 2.3.* is because Composer requires it. So it is kinda funny that the hoops I have to jump through to get to 2.3 end up dropping my Composer version back to a version that doesn't actually require symfony/console at 2.3. :)

Anyway, I'm not sure what the issue is here.

First off, it seems like if I can do ~2.3@dev I should be able to do ~2.3@beta but it seems like that is not a valid version. At the very least Composer doesn't seem to know what to do with it. Should we make it so that the likes of @beta, @rc, etc. work for ~ versions?

Second, the existing solution of doing something like ~2.3-beta doesn't really seem to do what I'd expect. Am I doing it wrong or is it buggy?

Here is a minimal composer.json that shows this in action:

{
    "require": {
        "symfony/console": "~2.3@beta"
    }
}
simensen commented 11 years ago

Here is another example composer.json showing what I thought would be an OK temporary workaround but it does not work at all:

{
    "require": {
        "composer/composer": "1.0.*@dev",
        "symfony/console": "2.3.*@beta"
    }
}

This actually gets me symfony/console at the correct version (2.3.0-BETA1) but even in this case I get dropped back to composer/composer at 1.0.0-alpha6.

Seldaek commented 11 years ago

OK in the second example if you change the composer require to 1.0.x-dev to force it to output why it's not selected, you see:

  Problem 1
    - Installation request for composer/composer 1.0.x-dev -> satisfiable by composer/composer[1.0.x-dev].
    - composer/composer 1.0.x-dev requires symfony/console >=2.3,<3.0 -> no matching package found.

So yeah the problem is that ~2.3 means >=2.3 (not dev, not beta) up to 3.0. I suspect it works with ~2.3@dev in composer because 2.3.x-dev is bigger than 2.3, but 2.3-beta1 is smaller.

If you allow symfony/console 2.3.*@dev then it'll be fine.

The question is whether we should parse ~2.3@dev as >=2.3-dev,<3.0 or not. I'd tend to say yes because it's kinda what you mean even though technically you should write ~2.3-dev.

simensen commented 11 years ago

Well, it seems like ~2.3@dev works as expected. I don't have any problem with @dev (though I'll admit maybe somehow it is broken too and I just don't understand why).

The problem is when I try another stability level like @beta. Here are a few examples:

@dev

{
    "require": {
        "composer/composer": "1.0.*@dev",
        "symfony/console": "@dev"
    }
}

results are more or less what I expect:

  - Installing symfony/console (dev-master v2.3.0-BETA1)
    Cloning v2.3.0-BETA1

  - Installing composer/composer (dev-master 4b26c62)
    Cloning 4b26c627ff087380975881a18787e6a760b60e09

2.3.*@dev

{
    "require": {
        "composer/composer": "1.0.*@dev",
        "symfony/console": "2.3.*@dev"
    }
}

again, results are more or less what i'd expect:

  - Installing symfony/console (dev-master v2.3.0-BETA1)
    Cloning v2.3.0-BETA1

  - Installing composer/composer (dev-master 4b26c62)
    Cloning 4b26c627ff087380975881a18787e6a760b60e09

@beta

{
    "require": {
        "composer/composer": "1.0.*@dev",
        "symfony/console": "@beta"
    }
}

... results in something very different from what I'd expect...

  - Installing symfony/console (v2.3.0-BETA1)
    Downloading: 100%

  - Installing composer/composer (1.0.0-alpha6)
    Downloading: 100%

2.3.*@beta

I really thought this would be my answer... but alas, not even this works.

{
    "require": {
        "composer/composer": "1.0.*@dev",
        "symfony/console": "2.3.*@beta"
    }
}

results in the same unexpected solution:

  - Installing symfony/console (v2.3.0-BETA1)
    Loading from cache

  - Installing composer/composer (1.0.0-alpha6)
    Loading from cache

~2.3-beta

The question is whether we should parse ~2.3@dev as >=2.3-dev,<3.0 or not. I'd tend to say yes because it's kinda what you mean even though technically you should write ~2.3-dev.

What is the difference between ~2.3@beta and ~2.3-beta? I'm not sure what the latter means. I'm used to seeing stability specified as @stability so I don't fully understand all of the impact doing *-stability will have on my dependencies.

Said another way, under what circumstances should someone use the *-stability format over the @stability format?

In any event, ~2.3-beta doesn't work either:

{
    "require": {
        "composer/composer": "1.0.*@dev",
        "symfony/console": "~2.3-beta"
    }
}

... results in the same unexpected solution as @beta...

  - Installing symfony/console (v2.3.0-BETA1)
    Loading from cache

  - Installing composer/composer (1.0.0-alpha6)
    Loading from cache
sminnee commented 11 years ago

@Seldaek - it seems to me that "~3.1" should accept pre-stable versions of 3.1.0, provided that they don't conflict with the project's min-stability setting. Assuming you agree with that, I would expect that the VersionParserTest would need to be amended as follows:

diff --git a/tests/Composer/Test/Package/Version/VersionParserTest.php b/tests/Composer/Test/Package/Version/VersionParserTest.php
index c46d47f..ca29f17 100644
--- a/tests/Composer/Test/Package/Version/VersionParserTest.php
+++ b/tests/Composer/Test/Package/Version/VersionParserTest.php
@@ -265,10 +265,10 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
     public function tildeConstraints()
     {
         return array(
-            array('~1',       new VersionConstraint('>=', '1.0.0.0'), new VersionConstraint('<', '2.0.0.0-dev')),
-            array('~1.2',     new VersionConstraint('>=', '1.2.0.0'), new VersionConstraint('<', '2.0.0.0-dev')),
-            array('~1.2.3',   new VersionConstraint('>=', '1.2.3.0'), new VersionConstraint('<', '1.3.0.0-dev')),
-            array('~1.2.3.4', new VersionConstraint('>=', '1.2.3.4'), new VersionConstraint('<', '1.2.4.0-dev')),
+            array('~1',       new VersionConstraint('>', '0.9999999.9999999.9999999'), new VersionConstraint('<', '2.0.0.0-dev')),
+            array('~1.2',     new VersionConstraint('>', '1.1.9999999.9999999'), new VersionConstraint('<', '2.0.0.0-dev')),
+            array('~1.2.3',   new VersionConstraint('>', '1.2.2.9999999'), new VersionConstraint('<', '1.3.0.0-dev')),
+            array('~1.2.3.4', new VersionConstraint('>', '1.2.3.3'), new VersionConstraint('<', '1.2.4.0-dev')),
             array('~1.2-beta',new VersionConstraint('>=', '1.2.0.0-beta'), new VersionConstraint('<', '2.0.0.0-dev')),
             array('~1.2-b2',  new VersionConstraint('>=', '1.2.0.0-beta2'), new VersionConstraint('<', '2.0.0.0-dev')),
             array('~1.2-BETA2', new VersionConstraint('>=', '1.2.0.0-beta2'), new VersionConstraint('<', '2.0.0.0-dev')),

Before any fix is made I want to confirm that I'm not muddying the semantics. My reading of "~3.1@dev" is that is must be a dev package, and so a dev package would be used, even if min-stability was at stable.

Can you confirm that my change to the test is legitimate?

simensen commented 11 years ago

@sminnee please keep in mind that as far as I can tell @dev works pretty well. It is any other stability that's proving to be difficult. That said, dev might be brown some too... But I can actually currently get dev to work but beta falls over itself pretty hard in all cases listed above.

I mention this because the tests you have posted as changed are all non stability related tests.

sminnee commented 11 years ago

@simensen The purpose of my test changes was to edit the "lower constraint" of a ~2.1 requirement to match that of a `2.1.* requirement. Specifically, it's designed to include all levels of stability in the version constraint where no @ is provided.

Given that 2.1.* works in that way, it seems more logical for ~2.1 to do that also. Perhaps it's a different issue from the one you've raised in this ticket (in which case I'll submit a separate PR) but I still think it's a change worth making.

sminnee commented 11 years ago

OK, I've put a PR up at https://github.com/composer/composer/pull/1881