这是indexloc提供的服务,不要输入任何密码
Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
},
"require-dev": {
"phpunit/phpunit": "^5.4.7",
"composer/composer": "^1.2.0"
"composer/composer": "^1.3",
"ext-zip": "*"
},
"autoload": {
"psr-4": {
Expand Down
18 changes: 12 additions & 6 deletions src/PackageVersions/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,27 +80,33 @@ public static function getSubscribedEvents()
*/
public static function dumpVersionsClass(Event $composerEvent)
{
$io = $composerEvent->getIO();
$composer = $composerEvent->getComposer();
$versions = iterator_to_array(self::getVersions($composer->getLocker(), $composer->getPackage()));

$io->write('<info>ocramius/package-versions:</info> Generating version class...');
if (!array_key_exists('ocramius/package-versions', $versions)) {
//plugin must be globally installed - we only want to generate versions for projects which specifically
Copy link
Owner

Choose a reason for hiding this comment

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

@AydinHassan just a doubt, given that there's no real way to know from the code: what about when the package is indirectly depending on package-versions? Will it still run?

Copy link
Owner

Choose a reason for hiding this comment

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

Also: what about when we are currently operating in package-versions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Ocramius will run in both contexts as it would be in the lock file - is that expected?

The first is actually my use case - A globally installed tool depends on PackageVersions.

Copy link
Owner

Choose a reason for hiding this comment

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

@AydinHassan great, thanks!

//require ocramius/package-versions
return;
}

$composer = $composerEvent->getComposer();
$io = $composerEvent->getIO();
$io->write('<info>ocramius/package-versions:</info> Generating version class...');
Copy link
Owner

Choose a reason for hiding this comment

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

I'll add an info message in the previous block as well. Otherwise, users may get confused on why this isn't running.


self::writeVersionClassToFile(
self::generateVersionsClass($composer),
self::generateVersionsClass($versions),
$composer->getConfig(),
$composer->getPackage()
);

$io->write('<info>ocramius/package-versions:</info> ...done generating version class');
}

private static function generateVersionsClass(Composer $composer) : string
private static function generateVersionsClass(array $versions) : string
{
return sprintf(
self::$generatedClassTemplate,
'fin' . 'al ' . 'cla' . 'ss ' . 'Versions', // note: workaround for regex-based code parsers :-(
var_export(iterator_to_array(self::getVersions($composer->getLocker(), $composer->getPackage())), true)
var_export($versions, true)
);
}

Expand Down
245 changes: 245 additions & 0 deletions test/PackageVersionsTest/E2EInstallerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
<?php

namespace PackageVersionsTest;

use PHPUnit_Framework_TestCase;
use RecursiveCallbackFilterIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
use ZipArchive;

/**
* @coversNothing
*/
class E2EInstaller extends PHPUnit_Framework_TestCase
Copy link
Owner

Choose a reason for hiding this comment

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

Going to rename/move this class around. Also will add @coversNothing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure thing - wasn't really sure how to name it

{
/**
* @var string
*/
private $tempGlobalComposerHome;
Copy link
Owner

Choose a reason for hiding this comment

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

To be added: docblocks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added


/**
* @var string
*/
private $tempLocalComposerHome;

/**
* @var string
*/
private $tempArtifact;

public function setUp()
{
$this->tempGlobalComposerHome = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/global';
$this->tempLocalComposerHome = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/local';
$this->tempArtifact = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/artifacts';
mkdir($this->tempGlobalComposerHome, 0700, true);
mkdir($this->tempLocalComposerHome, 0700, true);
mkdir($this->tempArtifact, 0700, true);

putenv('COMPOSER_HOME=' . $this->tempGlobalComposerHome);
Copy link
Owner

Choose a reason for hiding this comment

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

This environment variable must be reset in tearDown

}

public function tearDown()
{
$this->rmDir($this->tempGlobalComposerHome);
$this->rmDir($this->tempLocalComposerHome);
$this->rmDir($this->tempArtifact);

putenv('COMPOSER_HOME');
}

public function testGloballyInstalledPluginDoesNotGenerateVersionsForLocalProject()
{
$this->createPackageVersionsArtifact();

$this->writeComposerJsonFile(
[
'name' => 'package-versions/e2e-global',
'require' => [
'ocramius/package-versions' => '1.0.0'
],
'repositories' => [
[
'packagist' => false,
],
[
'type' => 'artifact',
'url' => $this->tempArtifact,
]
]
],
$this->tempGlobalComposerHome
);

$this->execComposerInDir('global update', $this->tempGlobalComposerHome);

$this->createArtifact();
$this->writeComposerJsonFile(
[
'name' => 'package-versions/e2e-local',
'require' => [
'test/package' => '2.0.0'
],
'repositories' => [
[
'packagist' => false,
],
[
'type' => 'artifact',
'url' => $this->tempArtifact,
]
]
],
$this->tempLocalComposerHome
);

$this->execComposerInDir('update', $this->tempLocalComposerHome);
$this->assertFileNotExists(
$this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
);
}

public function testRemovingPluginDoesNotAttemptToGenerateVersions()
{
$this->createPackageVersionsArtifact();
$this->createArtifact();

$this->writeComposerJsonFile(
[
'name' => 'package-versions/e2e-local',
'require' => [
'test/package' => '2.0.0',
'ocramius/package-versions' => '1.0.0'
],
'repositories' => [
[
'packagist' => false,
],
[
'type' => 'artifact',
'url' => $this->tempArtifact,
]
]
],
$this->tempLocalComposerHome
);

$this->execComposerInDir('update', $this->tempLocalComposerHome);
$this->assertFileExists(
$this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
);

$this->execComposerInDir('remove ocramius/package-versions', $this->tempLocalComposerHome);

$this->assertFileNotExists(
$this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
);
}

private function createPackageVersionsArtifact()
Copy link
Owner

Choose a reason for hiding this comment

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

Should this return the path to the generated artifact?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I dont think so - the path to the zip isn't used for anything, just the folder where they reside

{
$zip = new ZipArchive();

$zip->open($this->tempArtifact . '/ocramius-package-versions-1.0.0.zip', ZipArchive::CREATE);

$files = array_filter(
iterator_to_array(new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(realpath(__DIR__ . '/../../'), RecursiveDirectoryIterator::SKIP_DOTS),
function (SplFileInfo $file, $key, RecursiveDirectoryIterator $iterator) {
return $iterator->getSubPathname()[0] !== '.' && $iterator->getSubPathname() !== 'vendor';
}
),
RecursiveIteratorIterator::LEAVES_ONLY
)),
function (SplFileInfo $file) {
return !$file->isDir();
}
);

array_walk(
$files,
function (SplFileInfo $file) use ($zip) {
if ($file->getFilename() === 'composer.json') {
$contents = json_decode(file_get_contents($file->getRealPath()), true);
$contents['version'] = '1.0.0';

return $zip->addFromString('composer.json', json_encode($contents));
}

$zip->addFile(
$file->getRealPath(),
substr($file->getRealPath(), strlen(realpath(__DIR__ . '/../../')) + 1)
);
}
);

$zip->close();
}

private function createArtifact()
{
$zip = new ZipArchive();

$zip->open($this->tempArtifact . '/test-package-2.0.0.zip', ZipArchive::CREATE);
$zip->addFromString(
'composer.json',
json_encode(
[
'name' => 'test/package',
'version' => '2.0.0'
],
JSON_PRETTY_PRINT
)
);
$zip->close();
}

private function writeComposerJsonFile(array $config, string $directory)
{
file_put_contents(
$directory . '/composer.json',
json_encode($config, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
);
}

private function execComposerInDir(string $command, string $dir) : array
{
$currentDir = getcwd();
chdir($dir);
exec(__DIR__ . '/../../vendor/bin/composer ' . $command . ' 2> /dev/null', $output, $exitCode);
$this->assertEquals(0, $exitCode);
chdir($currentDir);
return $output;
}

/**
* @param string $directory
*
* @return void
*/
private function rmDir(string $directory)
{
if (! is_dir($directory)) {
unlink($directory);

return;
}

array_map(
function ($item) use ($directory) {
$this->rmDir($directory . '/' . $item);
},
array_filter(
scandir($directory),
function (string $dirItem) {
return ! in_array($dirItem, ['.', '..'], true);
}
)
);

rmdir($directory);
}
}
Loading