Skip to content
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

Fix for #18 - support running with --no-scripts flag #33

Merged
merged 6 commits into from Jul 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -9,6 +9,7 @@ env:
- DEPENDENCIES=""
- DEPENDENCIES="--prefer-lowest --prefer-stable"
- DEPENDENCIES="--classmap-authoritative"
- DEPENDENCIES="--no-scripts"

before_script:
- sh .travis.install.sh
Expand Down
78 changes: 78 additions & 0 deletions src/PackageVersions/FallbackVersions.php
@@ -0,0 +1,78 @@
<?php

namespace PackageVersions;

/**
* @internal
*
* This is a fallback for {@see \PackageVersions\Versions::getVersion()}
* Do not use this class directly: it is intended to be only used when
* {@see \PackageVersions\Versions} fails to be generated, which typically
* happens when running composer with `--no-scripts` flag)
*/
final class FallbackVersions
{
private function __construct()
{
}

/**
* @param string $packageName
*
* @return string
*
* @throws \OutOfBoundsException if a version cannot be located
* @throws \UnexpectedValueException if the composer.lock file could not be located
*/
public static function getVersion(string $packageName) : string
{
$versions = iterator_to_array(self::getVersions(self::getComposerLockPath()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why building an array of all versions when you could use a loop and break when the right package name is found, taking advantage of your generator ?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy-paste + laziness, mainly. Code can be improved, ofc, just didn't want to introduce bugs just by rewriting it


if (! array_key_exists($packageName, $versions)) {
throw new \OutOfBoundsException(
'Required package "' . $packageName . '" is not installed: cannot detect its version'
);
}

return $versions[$packageName];
}

/**
* @return string
*
* @throws \UnexpectedValueException
*/
private static function getComposerLockPath() : string
{
// bold assumption, but there's not here to fix everyone's problems.
$checkedPaths = [__DIR__ . '/../../../../../composer.lock', __DIR__ . '/../../composer.lock'];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius Perhaps some $path = dirname(__DIR__, $level++) . '/composer.lock'-based check as a better chance alternative? Of course with some reasonable threshold for $level increment.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikolaposa I don't trust intermediate levels


foreach ($checkedPaths as $path) {
if (file_exists($path)) {
return $path;
}
}

throw new \UnexpectedValueException(sprintf(
'PackageVersions could not locate your `composer.lock` location. This is assumed to be in %s. '
. 'If you customized your composer vendor directory and ran composer installation with --no-scripts, '
. 'then you are on your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.',
json_encode($checkedPaths)
));
}

private static function getVersions(string $composerLockFile) : \Generator
{
$lockData = json_decode(file_get_contents($composerLockFile), true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should actually check installed packages, not locked ones. packages-dev will always be there in Composer 1.0+, even dev deps are not installed

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an array key with the installed packages? I currently merge packages-dev + packages, and I know that dev packages may not have been installed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

installed packages are not in the lock file. they are in vendor/composer/installed.json (and btw, the path between your package and this folder will always be the same even when using custom vendor directories, as they are both inside it)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but what interests us is just the version of a package. For example,
I may have generated(in a CI/CD environment running with dev dependencies)
an asset management system that generates files. Even though the package
doesn't make it to production, the version of the asset manager used to
generate the files is relevant for signature verification purposes. That is
the primary purpose of this library, at least in how I envisioned it when I
built it for my own needs.

On 22 Jul 2016 17:17, "Christophe Coevoet" notifications@github.com wrote:

In src/PackageVersions/FallbackVersions.php
#33 (comment)
:

  •        if (file_exists($path)) {
    
  •            return $path;
    
  •        }
    
  •    }
    
  •    throw new \UnexpectedValueException(sprintf(
    
  •        'PackageVersions could not locate your `composer.lock` location. This is assumed to be in %s. '
    
  •        . 'If you customized your composer vendor directory and ran composer installation with --no-scripts, '
    
  •        . 'then you are on your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.',
    
  •        json_encode($checkedPaths)
    
  •    ));
    
  • }
  • private static function getVersions(string $composerLockFile) : \Generator
  • {
  •    $lockData = json_decode(file_get_contents($composerLockFile), true);
    

installed packages are not in the lock file. they are in
vendor/composer/installed.json (and btw, the path between your package
and this folder will always be the same even when using custom vendor
directories, as they are both inside it)


You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/Ocramius/PackageVersions/pull/33/files/0a1a91ea4d08baa225724845431bee542773fd1a#r71895649,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAJakC16NEtnqktbklFgVXJ032yDe_Jcks5qYN8SgaJpZM4JSv1j
.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so it is OK if the package is not there anymore ? This should be clearly documented then

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if the package is not installed (because of non-dev install) then the
version will still be retrievable

On 22 Jul 2016 18:12, "Christophe Coevoet" notifications@github.com wrote:

In src/PackageVersions/FallbackVersions.php
#33 (comment)
:

  •        if (file_exists($path)) {
    
  •            return $path;
    
  •        }
    
  •    }
    
  •    throw new \UnexpectedValueException(sprintf(
    
  •        'PackageVersions could not locate your `composer.lock` location. This is assumed to be in %s. '
    
  •        . 'If you customized your composer vendor directory and ran composer installation with --no-scripts, '
    
  •        . 'then you are on your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.',
    
  •        json_encode($checkedPaths)
    
  •    ));
    
  • }
  • private static function getVersions(string $composerLockFile) : \Generator
  • {
  •    $lockData = json_decode(file_get_contents($composerLockFile), true);
    

Oh, so it is OK if the package is not there anymore ? This should be
clearly documented then


You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/Ocramius/PackageVersions/pull/33/files/0a1a91ea4d08baa225724845431bee542773fd1a#r71904545,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAJakNm1YtoJ-XgYCngwzUo3k-RhKxvcks5qYOv7gaJpZM4JSv1j
.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The readme should explain it then


$lockData['packages-dev'] = $lockData['packages-dev'] ?? [];

foreach (array_merge($lockData['packages'], $lockData['packages-dev']) as $package) {
yield $package['name'] => $package['version'] . '@' . (
$package['source']['reference']?? $package['dist']['reference'] ?? ''
);
}

yield 'unknown/root-package@UNKNOWN';
}
}
29 changes: 29 additions & 0 deletions src/PackageVersions/Versions.php
@@ -0,0 +1,29 @@
<?php

namespace PackageVersions;

/**
* This is a stub class: it is in place only for scenarios where PackageVersions
* is installed with a `--no-scripts` flag, in which scenarios the Versions class
* is not being replaced.
*
* If you are reading this docBlock inside your `vendor/` dir, then this means
* that PackageVersions didn't correctly install, and is in "fallback" mode.
*/
final class Versions
{
const VERSIONS = [];

private function __construct()
{
}

/**
* @throws \OutOfBoundsException if a version cannot be located
* @throws \UnexpectedValueException if the composer.lock file could not be located
*/
public static function getVersion(string $packageName) : string
{
return FallbackVersions::getVersion($packageName);
}
}
61 changes: 61 additions & 0 deletions test/PackageVersionsTest/FallbackVersionsTest.php
@@ -0,0 +1,61 @@
<?php

namespace PackageVersionsTest;

use PackageVersions\FallbackVersions;
use PackageVersions\Versions;
use PHPUnit_Framework_TestCase;

/**
* @covers \PackageVersions\FallbackVersions
*/
final class FallbackVersionsTest extends PHPUnit_Framework_TestCase
{
public function testWillFailWithoutValidComposerLockLocation()
{
rename(__DIR__ . '/../../composer.lock', __DIR__ . '/../../composer.lock.backup');

try {
FallbackVersions::getVersion('phpunit/phpunit');

self::fail('An exception was supposed to be thrown');
} catch (\UnexpectedValueException $lockFileNotFound) {
$srcDir = realpath(__DIR__ . '/../../src/PackageVersions');

self::assertSame(
'PackageVersions could not locate your `composer.lock` location. '
. 'This is assumed to be in '
. json_encode([$srcDir . '/../../../../../composer.lock', $srcDir . '/../../composer.lock'])
. '. If you customized your composer vendor directory and ran composer installation with --no-scripts, '
. 'then you are on your own, and we can\'t really help you. '
. 'Fix your shit and cut the tooling some slack.',
$lockFileNotFound->getMessage()
);
}

rename(__DIR__ . '/../../composer.lock.backup', __DIR__ . '/../../composer.lock');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will not rename things properly when there is a test failure

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be done in a try/finally

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

public function testValidVersions()
{
$lockData = json_decode(file_get_contents(__DIR__ . '/../../composer.lock'), true);

$packages = array_merge($lockData['packages'], $lockData['packages-dev']);

self::assertNotEmpty($packages);

foreach ($packages as $package) {
self::assertSame(
$package['version'] . '@' . $package['source']['reference'],
Versions::getVersion($package['name'])
);
}
}

public function testInvalidVersionsAreRejected()
{
$this->expectException(\OutOfBoundsException::class);

Versions::getVersion(uniqid('', true) . '/' . uniqid('', true));
}
}