-
-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add PHAR constraint check #116
Conversation
d340b33
to
9cea332
Compare
@MacFJA as promised here's the script. It's still a big WIP, but that's a gist of it. As there is still much to do and because it's quite fragile (it requires manual autoloading so right it's very coupled to the FS) I don't think it will be easily portable. Tbh I'm more worried about making it work properly and testing it properly (I still have no idea on how to automate that) before considering making it a portable standalone. |
3f36857
to
e12b31a
Compare
@theofidry Thanks to keep me in touch! In your checklist, for the entry "Make the PHP check work: right now Here a example on how it can be used: <?php
require_once __DIR__ . '/src/Semver.php';
require_once __DIR__ . '/src/VersionParser.php';
require_once __DIR__ . '/src/Constraint/ConstraintInterface.php';
require_once __DIR__ . '/src/Constraint/Constraint.php';
require_once __DIR__ . '/src/Constraint/MultiConstraint.php';
use Composer\Semver\Semver;
var_dump(Semver::satisfies('5.3', '^7.2')); // Return false
var_dump(Semver::satisfies('7.2', '^7.2')); // Return true
var_dump(Semver::satisfies('7.3', '^7.2')); // Return true (As you see, 5 files will need to be added) |
Do you have an idea on how, I remember there was a similar thing in
PhpScoper but it was not working correctly with the different PHP versions:
humbug/php-scoper#154
…On Sat 14 Apr 2018 at 13:52, MacFJA ***@***.***> wrote:
@theofidry <https://github.com/theofidry> Thanks to keep me in touch!
In your checklist, for the entry "Make the PHP check work: right now compare_version(PHP_VERSION?,
'^7.2', '>=') will return true on PHP 5.3...", maybe you can the package
composer/semver
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#116 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AE76gY7NGUBNw0GeaGn3CY3wY_jm1Im2ks5tofELgaJpZM4TQw6x>
.
|
src/RequirementChecker/Checker.php
Outdated
|
||
$checkPassed = self::evaluateRequirements($requirements); | ||
|
||
if (false === $checkPassed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, the test can be change to:
if ($checkPassed === true && $verbose === false) {
return true;
}
And if we don't enter into this condition then the verbosity is always true
(because of an error, or because it was asked)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored this piece with different level of verbosity which I believe is cleaner and more in line with the verbosity of the console in general
public function isFulfilled() | ||
{ | ||
if (null === $this->isFulfilled) { | ||
$this->isFulfilled = eval($this->checkIsFulfilled); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of eval
and a lot of company will block this function.
We know in advance that we have 2 types of checks: version_compare
(for php) and extension_loaded
(for extensions), maybe we can found an alternative way to do our checks
|
||
private static function configurePhpVersionRequirements(LazyRequirementCollection $requirements, array $composerLockContents): void | ||
{ | ||
$installedPhpVersion = PHP_VERSION; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need the version of PHP of the machine that make the phar?
The generated content will have nothing to do with it later on, as the runner machine is not the same as the maker machine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. The evaluation is right as it's using the PHP version of the runner but the message generated is wrong as uses the PHP version used when building the PHAR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I "fixed" it by simply not displaying it: the PHP version is now showed in the output and the PHP version requirement check is the first one coming in the list so it should be pretty user friendly still without introducing the need to lazily evaluate the help message
Oh right, I didn't think about this case. Maybe a normalization step can be added to remove backport/system additionnal data. In Composer code they cleanup the version to handle this case. It will be something like: <?php
require_once __DIR__ . '/src/Semver.php';
require_once __DIR__ . '/src/VersionParser.php';
require_once __DIR__ . '/src/Constraint/ConstraintInterface.php';
require_once __DIR__ . '/src/Constraint/Constraint.php';
require_once __DIR__ . '/src/Constraint/MultiConstraint.php';
use Composer\Semver\Semver;
var_dump(Semver::satisfies('5.3', '^7.2')); // Return false
var_dump(Semver::satisfies('7.2', '^7.2')); // Return true
var_dump(Semver::satisfies('7.3', '^7.2')); // Return true
//var_dump(Semver::satisfies('7.0.28-0ubuntu0.16.04.1', '^7.2')); // Throw an UnexpectedValueException
$phpVersion = preg_replace('#^([^~+-]+).*$#', '$1', '7.0.28-0ubuntu0.16.04.1');
var_dump($phpVersion); // Return "7.0.28"
var_dump(Semver::satisfies($phpVersion, '^7.2')); // Return false
var_dump(Semver::satisfies(preg_replace('#^([^~+-]+).*$#', '$1', '7.1.11-0ubuntu0.17.10.1'), '^7.1')); // Return true |
======================== | ||
|
||
> PHP is using the following php.ini file: | ||
/Users/tfidry/.phpbrew/php/php-7.1.10/etc/php.ini |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the dependency on the local path; Same for the others
src/Box.php
Outdated
Assertion::readable($file); | ||
|
||
$contents = null === $contents ? file_get_contents($file) : $contents; | ||
if (null === $contents) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be a bug fixed in another PR
I've pushed a new implementation:
Thanks for the help, I'll try to find a way to handle the PHP version thing |
src/RequirementChecker/IO.php
Outdated
*/ | ||
private function parseInput() | ||
{ | ||
$this->tokens = $_SERVER['argv']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't use getopt function ?
It can handle short and long argument syntax, remove the use of global variable $_SERVER
, simplify the class. And IMHO, here, the arguments management is not fancy enough to need an external/custom implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree the arguments management is not as complex as a regular input and is bound to be simpler because it can't know about the input definitions. So I simplified the implementation to reflect on that.
I admit I'm not familiar enough with the getopt()
function. I added the tests for the IO class so it should be easier to change whilst ensuring the same feature set.
Would it be possible for you to take a look at it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a quick test getopt
have some issue for this case:
- It can not be UnitTested (cf. this message)
- It can not handle option
-vv
and-vvv
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too bad, well I hope the current implementation appears simpler than previously then
Ok added some more tests/bugfixes, there is only a handful of things left to do now... |
To be honest I'm not sure on how to do that one. One way would be to execute the tests in a container so we could have a fixed PHP version & php.ini file path, however I couldn't find how to hook the docker run logs on a host FS. Maybe @Simperfit or @sanmai you have an idea? For a bit of context, I'm executing the PHAR and put the output in a |
634a02d
to
7464289
Compare
Updated the list of what's left to do. Looks like I won't be able to make it work without some patching in PHP-Parser & PHP-Scoper |
7464289
to
3483f31
Compare
So there is a small bit missing from PHP-Scoper but I think this can be re-worked later. I need to update a couple of things in PHP-Scoper to simplify Box and vice-versa. So now we're just waiting on that PHP-Parser issue. The real problem remaining is that dependency to the local paths. Ideally we would run those commands (the check requirements) inside the docker containers so that the path is controlled, but I don't know how to log the output of the command on a host file still |
9c31192
to
5c014d9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides the comments, we are still missing:
- Configure Travis to run those containers, check if there is a way to cache those images
- Run the CS: this warrants a dedicated configuration for the 5.3 only code
@@ -105,6 +106,28 @@ an octal value e.g. `0750`. By default the permissions of the created PHAR are u | |||
Check the following [link](https://secure.php.net/manual/en/function.chmod.php) for more on the possible values. | |||
|
|||
|
|||
## Check requirements (`check-requirements`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any opinion about the name? Maybe this should be requirements-checker
instead
src/Box.php
Outdated
@@ -240,7 +241,10 @@ public function addFile(string $file, string $contents = null, bool $binary = fa | |||
} | |||
|
|||
if ($binary) { | |||
$this->phar->addFile($file, $local); | |||
true === file_exists($file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this could be extracted in a separate PR
src/Configuration.php
Outdated
@@ -307,6 +326,16 @@ public function getBasePath(): string | |||
return $this->basePath; | |||
} | |||
|
|||
public function getComposerJson(): ?string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be extracted in a separate PR and tests added about the values gotten from those, e.g. when the file does not exists, is a directory and so on
{ | ||
// TODO: emit warning when stub is not generated and check requirements is explicitly set to true | ||
// TODO: emit warning when no composer lock is found but check requirements is explicitely set to true | ||
if (false === $hasComposerLock) { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@@ -365,15 +380,41 @@ private function registerMainScript(Configuration $config, Box $box, BuildLogger | |||
return $localMain; | |||
} | |||
|
|||
private function registerStub(Configuration $config, Box $box, string $main, BuildLogger $logger): void | |||
private function registerRequirementsChecker(Configuration $config, Box $box, BuildLogger $logger): bool |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
src/RequirementChecker/IO.php
Outdated
} | ||
|
||
/** | ||
* {@inheritdoc} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invalid inheritdoc
doc block
* | ||
* @private | ||
*/ | ||
final class Requirement |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
* | ||
* @private | ||
*/ | ||
final class RequirementCollection implements IteratorAggregate, Countable |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@@ -2663,6 +2663,20 @@ public function testIsPrivateKeyPromptSetString(): void | |||
$this->assertFalse($this->config->isPrivateKeyPrompt()); | |||
} | |||
|
|||
public function test_the_requirement_checker_is_enabled_by_default(): void |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
tests/StubGeneratorTest.php
Outdated
@@ -218,6 +260,9 @@ public function test_it_can_generate_a_complete_stub(): void | |||
|
|||
Phar::mapPhar('test.phar'); | |||
Phar::interceptFileFuncs(); | |||
|
|||
require 'phar://test.phar/.box/check_requirements.php'; | |||
|
|||
require 'phar://test.phar/index.php'; |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@MacFJA almost done. There is not much to do I believe I might be able to finish that this weekend. Maybe you want to do a review now or I can ping you when everything is green for a final review. As you wish :) |
04d3bff
to
3f18a30
Compare
Ready for review. The build failure looks like an issue in Infection itself rather that here, so I'm fine with it for now |
foreach ($packages as $packageInfo) { | ||
$packageRequire = $packageInfo['require'] ?? []; | ||
|
||
if (1 === preg_match('/symfony\/polyfill-(?<extension>.+)/', $packageInfo['name'], $matches)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be interesting to add the ability to have another polyfill format: the current implementation only allow polyfill from Symfony.
There are other polyfill like mcrypt_compat or random_compat (with the name containing FEATURE_compat
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! For now I just added this one because it was easy to do, but we could definitely add support for more polyfills. I would do in another PR though as it's already a lot here. I opened #131 for this to not be forgotten
|
||
private static function generatePhpCheckStatement(string $requiredPhpVersion): string | ||
{ | ||
return "return require_once 'Semver.php'; \\_HumbugBox\Composer\Semver::satisfies(preg_replace('#^([^~+-]+).*$#', '$1', \PHP_VERSION), '$requiredPhpVersion');"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some research, as our minimum PHP version is 5.3, this part can be simplify to:
return "return require_once 'Semver.php'; \\_HumbugBox\Composer\Semver::satisfies(sprintf('%d.%d.%d', \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, \PHP_RELEASE_VERSION), '$requiredPhpVersion');";
No need of a RegExp to parse the version. Those constants have been added in PHP 5.2.7.
Tested on:
- Ubuntu:
echo PHP_VERSION; // output: 7.0.28-0ubuntu0.16.04.1
echo sprintf('%d.%d.%d', \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, \PHP_RELEASE_VERSION); // output: 7.0.28
- Docker (dockette/php71):
echo PHP_VERSION; // output: 7.1.15-1+0~20180306120016.15+stretch~1.gbp78327e
echo sprintf('%d.%d.%d', \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, \PHP_RELEASE_VERSION); // output: 7.1.15
6466261
to
16d41fd
Compare
33a1b00
to
70f04fb
Compare
70f04fb
to
18ab77a
Compare
821ff94
to
7933bef
Compare
7933bef
to
e49382a
Compare
@MacFJA a few notes as I ended up changing a lot of things. Indeed the PHP version check was not working due to missing classes, but adding those classes was a real pain. In the end I ended up doing something simpler: I created a sub-project for the requirement checker for which I create a PHAR (which allows to filter only the necessary files as well as taking care of the scoping). Then extract this PHAR and add the extracted files to the Box PHAR, which then can add the requirement checker as usual. The big benefit of that is:
Feel free to do a final review, we can address the report points in new PRs. I'll be merge this now as I really need some of the stuff here and I think it's ok as a first iteration. |
This feature is about adding a check in the PHAR stub in order to gracefully fail with a human friendly error when the user is using the PHAR in a non-supported environment, e.g. invalid PHP version or missing extension. The goal is to gather those requirements without requiring any configuration from the user.
Here's a glimpse of how it looks like: