phar-io / phive

The Phar Installation and Verification Environment (PHIVE)
https://phar.io
BSD 3-Clause "New" or "Revised" License
581 stars 45 forks source link

install multi version #219

Open saeideng opened 4 years ago

saeideng commented 4 years ago

my phive.xml

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="7.*" location="phpunit7" copy="false"/>
  <phar name="phpunit" version="8.*" location="phpunit8" copy="false"/>
</phive>

I run phive update result

# phive update
Phive 0.13.2 - Copyright (C) 2015-2019 by Arne Blankerts, Sebastian Heuer and Contributors
Linking /home/.../.phive/phars/phpunit-7.5.18.phar to /home/.../bin/phpunit7
Linking /home/.../.phive/phars/phpunit-8.5.0.phar to /home/.../bin/phpunit7

I want to link second phar file to bin/phpunit8 not bin/phpunit7

my phive.xml after update

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="8.*" location="phpunit7" copy="false" installed="8.5.0"/>
  <phar name="phpunit" version="8.*" location="phpunit8" copy="false"/>
</phive>
theseer commented 4 years ago

Interesting issue.

This approach is indeed bound to fail since we use the name attribute as primary key, so the result is expected.

I'm not sure yet as to what approach would be best though, because I don't yet understand your use case: What's the reason you want two versions of the same package installed concurrently?

I do understand the potential need to install a different version based on the OS or PHP Version - and that currently phive does not yet have an answer to that.

So, what's your use case for multiple concurrent versions?

saeideng commented 4 years ago

when you have several application with different requirements you need to have several version of a tool
for example about phpunit that there are applications that phpunit requirement at them is not same and they are not compatible well with latest version of phpunit yet

I do this manually right now , but I like the phive supports this feature a day thanks for your good tool

theseer commented 4 years ago

Okay, I believe I do understand. We'll have to discuss how to implement something like that.

filips123 commented 4 years ago

I do understand the potential need to install a different version based on the OS or PHP Version - and that currently phive does not yet have an answer to that.

Can this be supported eventually? It is very useful tor tools like PHPUnit which only support latest two versions. This means that you will need both PHPUnit 8 and PHPUnit 9 (separately) if you want to support and test PHP 7.2-8.0.

I think that this could be done with supporting more version constraints, like how Composer supportes them. So you could have version="^8.5|^9.2" to support both PHPUnit versions.

In addition to this, it might also be good to split version, installed and copy keys into different files, similarly to composer.json and composer.lock. This is because if you have version="^8.5|^9.2" installed="9.2.6" in the same file, and then use that file on older PHP version, it could cause problems. If you use Git, you also can't just remove installed key and commit it because it will reappear on next install and cause messy diffs. It is also similar for copy, because this is most likely reference of user and not of project. However, location should stay in main file, because project's build tools may depend on specific location.

If you have two files, main one could be commited to Git and would contain PHAR name, requested/supported version and file location, and PHIVE won't try to edit it unless requested (i.e. by adding or removing new PHAR). Lock file could be ignored by Git (or included if project wants it), would only generate on install and would contain which specific version is currently installed.

theseer commented 4 years ago

Thank you for providing additional input to this.

I still disagree though: Neither you nor the original poster need to install multiple versions of the same phar at the same time, as the issue title and the overall wording in the descriptions suggest. As said before, I don't see a use case for this. What I understood before and find reconfirmed in your addition is that there is a need to have conditional installations. One such condition could be the PHP Version or the OS it's running on.

I also strongly disagree with having a combined constrained. It doesn't specify when to choose which version and, given we do not have any meta data for phars before downloading them, we cannot possibly resolve such a configuration without downloading multiple phars first (e.g. for every fragment of the combined version constraint) and try to figure out which one might actually work.

This is inherently getting worse if we are to support extension installation, which also suffers from not having meta-data available - but that's a different topic (#88).

Last but not least, I don't agree with the reasoning regarding single versus multiple files. Even for composer it is highly recommended to commit both, the composer.json as well as the composer.lock file to ensure you get exactly the previously selected versions of your dependencies.

If you always have to commit both files though, separating them is not helping. It only leads to additional complexity - for instance the case that composer complains about that the lock file is out of sync.

Again, what we need is conditional installations. For example, it could look like this:

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="^8.5" installed="8.5.1" location="./tools/phpunit" copy="true" condition="phpunit-8" />       

   <condition name="phpunit-8">
      <php constraint="^7.4" />
      <env var="foo" value="bar" />
   </condition>
</phive>

The above has not yet been implemented and is just a brain-dump ;)

hollodotme commented 3 years ago

I do also have this problem for the testing environment of hollodotme/fast-cgi-client where I need 3 different versions of PHPUnit to run tests against all supported PHP versions. But I want to add 3 more cents here:

1. The phars.xml gets altered when using phive install (not update), too.

IMO this should not happen at all and is maybe worth a separate issue.

When running phive install the phars.xml should be treated as a lock file, like composer.lock when running composer install. Only phive update or the user should be allowed to change the phars.xml.

Before:

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="7.5.19" installed="7.5.19" location="./.tools/phpunit-7.phar" copy="true"/>
  <phar name="phpunit" version="8.5.19" installed="8.5.19" location="./.tools/phpunit-8.phar" copy="true"/>
  <phar name="phpunit" version="9.5.8" installed="9.5.8" location="./.tools/phpunit-9.phar" copy="true"/>
  <phar name="phpstan" version="^0.12.94" installed="0.12.94" location="./.tools/phpstan.phar" copy="true"/>
  <phar name="composer" version="^2.1.5" installed="2.1.5" location="./.tools/composer.phar" copy="true"/>
</phive>

Run phive install: (Works as expected on the first run only)

Phive 0.15.0 - Copyright (C) 2015-2021 by Arne Blankerts, Sebastian Heuer and Contributors
Fetching repository list
Downloading https://phar.phpunit.de/phive.xml
Downloading https://phar.phpunit.de/phpunit-7.5.19.phar
Downloading https://phar.phpunit.de/phpunit-7.5.19.phar.asc
Copying phpunit-7.5.19.phar to /Users/hollodotme/Sites/hollodotme/fast-cgi-client/.tools/phpunit-7.phar
Downloading https://phar.phpunit.de/phpunit-8.5.19.phar
Downloading https://phar.phpunit.de/phpunit-8.5.19.phar.asc
Copying phpunit-8.5.19.phar to /Users/hollodotme/Sites/hollodotme/fast-cgi-client/.tools/phpunit-8.phar
Downloading https://phar.phpunit.de/phpunit-9.5.8.phar
Downloading https://phar.phpunit.de/phpunit-9.5.8.phar.asc
Copying phpunit-9.5.8.phar to /Users/hollodotme/Sites/hollodotme/fast-cgi-client/.tools/phpunit-9.phar
Downloading https://github.com/phpstan/phpstan/releases/download/0.12.94/phpstan.phar
Downloading https://github.com/phpstan/phpstan/releases/download/0.12.94/phpstan.phar.asc
Copying phpstan-0.12.94.phar to /Users/hollodotme/Sites/hollodotme/fast-cgi-client/.tools/phpstan.phar
Downloading https://github.com/composer/composer/releases/download/2.1.5/composer.phar
Downloading https://github.com/composer/composer/releases/download/2.1.5/composer.phar.asc
Copying composer-2.1.5.phar to /Users/hollodotme/Sites/hollodotme/fast-cgi-client/.tools/composer.phar

After phive install:

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="9.5.8" installed="9.5.8" location="./.tools/phpunit-9.phar" copy="true"/>
  <phar name="phpunit" version="8.5.19" installed="8.5.19" location="./.tools/phpunit-8.phar" copy="true"/>
  <phar name="phpunit" version="9.5.8" installed="9.5.8" location="./.tools/phpunit-9.phar" copy="true"/>
  <phar name="phpstan" version="^0.12.94" installed="0.12.94" location="./.tools/phpstan.phar" copy="true"/>
  <phar name="composer" version="^2.1.5" installed="2.1.5" location="./.tools/composer.phar" copy="true"/>
</phive>

2. Maintaining conditions

My use case is that I install all needed PHARs in one go and use them later in different docker containers, in order to run the test suites against different PHP (and PHPUnit) versions. This happens ins a build matrix on github actions which executes make tasks for the current PHP version.

I run phive via docker container, too.

So I maintain the conditions what version of a PHAR is used in a specific make task and don't want to maintain this additionally in the phars.xml in the form of conditionals as proposed in the comments here. This would lead to (unnecessary) multiple calls of phive install during the process and adds the complexity of WHY a PHAR must be installed to the phive configuration.


3. How I would like it to function

Configuring the desired PHARs for installing & updating as listed in the phars.xml above should remain a dead simple list.

As already said, phive install should not change the phars.xml and phive update should update one PHAR after the other according to their version constraints. In my case this would lead to no updates for PHPUnit PHARs at all, because the versions are pinned. Only PHPStan and composer should be updated automatically.

I don't know the internals of phive or why the name attribute must be unique. If that is a prerequisite, I can also imagine a config structure like this:

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit">
    <version required="7.5.19" installed="7.5.19" location="./.tools/phpunit-7.phar" copy="true"/>
    <version required="8.5.19" installed="8.5.19" location="./.tools/phpunit-8.phar" copy="true"/>
    <version required="9.5.8" installed="9.5.8" location="./.tools/phpunit-9.phar" copy="true" />
  </phar>
</phive>

IMO phive should not know why or when to install a phar (conditions), it should only know which PHARs to install.

theseer commented 3 years ago

I do also have this problem for the testing environment of hollodotme/fast-cgi-client where I need 3 different versions of PHPUnit to run tests against all supported PHP versions. But I want to add 3 more cents here:

1. The phars.xml gets altered when using phive install (not update), too.

That's not correct - or at least I cannot reproduce that:

theseer@nyda /tmp/x6 main $ cat .phive/phars.xml 
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="^9.5.8" installed="9.5.8" location="./tools/phpunit" copy="false"/>
</phive>
theseer@nyda /tmp/x6 main $ rm -rf tools
theseer@nyda /tmp/x6 main $ git status
On branch main
nothing to commit, working tree clean
theseer@nyda /tmp/x6 main $ phive install
Phive 0.15.0-7-g17cf2ee - Copyright (C) 2015-2021 by Arne Blankerts, Sebastian Heuer and Contributors
Fetching repository list
Downloading https://phar.phpunit.de/phpunit-9.5.8.phar
Downloading https://phar.phpunit.de/phpunit-9.5.8.phar.asc
Linking /home/theseer/.phive/phars/phpunit-9.5.8.phar to /tmp/x6/tools/phpunit

theseer@nyda /tmp/x6 main $ git status
On branch main
nothing to commit, working tree clean
theseer@nyda /tmp/x6 main $ 

IMO this should not happen at all and is maybe worth a separate issue.

It doesn't ;) - see above.

When running phive install the phars.xml should be treated as a lock file, like composer.lock when running composer install. Only phive update or the user should be allowed to change the phars.xml.

Phive only updates the phars.xml when a change is made: Either by having a new phar added via explicit install call or when an update is performed.

Before:

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="7.5.19" installed="7.5.19" location="./.tools/phpunit-7.phar" copy="true"/>
  <phar name="phpunit" version="8.5.19" installed="8.5.19" location="./.tools/phpunit-8.phar" copy="true"/>
  <phar name="phpunit" version="9.5.8" installed="9.5.8" location="./.tools/phpunit-9.phar" copy="true"/>
  <phar name="phpstan" version="^0.12.94" installed="0.12.94" location="./.tools/phpstan.phar" copy="true"/>
  <phar name="composer" version="^2.1.5" installed="2.1.5" location="./.tools/composer.phar" copy="true"/>
</phive>

Having multiple entries with the same name is explicitly not supported as - at least currently - this is a primary key. I assume that phive gets confused and tries to update the first entrty for phpunit with whatever happend last as it sees that as a change to be recorded.

2. Maintaining conditions

My use case is that I install all needed PHARs in one go and use them later in different docker containers, in order to run the test suites against different PHP (and PHPUnit) versions. This happens ins a build matrix on github actions which executes make tasks for the current PHP version.

I run phive via docker container, too.

While I of course do understand the general setup described as well as the need to have different versions of tools installed depending on the PHP-Versions, I don't understand why one would want the added complexity of having differing names for the executables or paths?

IMHO, having a fixed name for the executable and thus identical build targets would make maintaining the build logic a lot easier.

Not sure how github actions do that but when you cache phive's source library (usually ~/.phive), a "local" phive install using a specific PHP version would make phive pick the appropriate version - assuming we would implement my suggestion above or something comparable to that - without any additional downloads. You can even specify to "prefer offline".

So I maintain the conditions what version of a PHAR is used in a specific make task and don't want to maintain this additionally in the phars.xml in the form of conditionals as proposed in the comments here. This would lead to (unnecessary) multiple calls of phive install during the process and adds the complexity of WHY a PHAR must be installed to the phive configuration.

I do understand that line of thought but I consider it backwards: In your setup, we have a split brain: The phive configuration has the location and version constraint but which version to actually use is somewhere else. I don't think you do need that "somewhere else" but should have phive handle all of that and just run the build target as needed.

3. How I would like it to function

Configuring the desired PHARs for installing & updating as listed in the phars.xml above should remain a dead simple list.

As already said, phive install should not change the phars.xml and phive update should update one PHAR after the other according to their version constraints.

That's how it's actually implemented.

In my case this would lead to no updates for PHPUnit PHARs at all, because the versions are pinned. Only PHPStan and composer should be updated automatically.

Just to repeat: We do not support having the same phar name appear more than once. Other than that, that's how things are implemented.

I don't know the internals of phive or why the name attribute must be unique. If that is a prerequisite, I can also imagine a config structure like this:

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit">
    <version required="7.5.19" installed="7.5.19" location="./.tools/phpunit-7.phar" copy="true"/>
    <version required="8.5.19" installed="8.5.19" location="./.tools/phpunit-8.phar" copy="true"/>
    <version required="9.5.8" installed="9.5.8" location="./.tools/phpunit-9.phar" copy="true" />
  </phar>
</phive>

IMO phive should not know why or when to install a phar (conditions), it should only know which PHARs to install.

I honestly consider your approach an edge case. The default scenario is, as far as I believe at least, to have one build target to run the tests and one would expect the matching version of PHPUnit to be installed depending on the PHP version in use.

With the proposed structure, there is no simple installation via CLI anymore: Assuming you have the above config, what would phive install phpunit@^10.0 do? Add it to the list because somehow that's what you implicitly mean? Replace the list with only ^10.0? If we'd add it to the list, how do we determine the location name? And, if we have only one version installed, how do we explicitly install a different version? Do we assume, if you only have one version currently, you want it swapped out?

And, worse, when the phar to be installed contains a manifest, we'll perform compatibility checks for it. That would horribly break if we'd attempt your implementation idea.

tl;dr:

I'm not sure what the best approach is, but I'm fairly certain, this isn't it ;) So far, among all the potentially sub optimal ideas, the conditionals are imho the best.