Commit dd271560 authored by alexpott's avatar alexpott

Issue #3082866 by Mile23, Mixologic, greg.1.anderson, alexpott, rfay: composer...

Issue #3082866 by Mile23, Mixologic, greg.1.anderson, alexpott, rfay: composer complains "Skipped installation of bin bin/composer for package composer/composer: file not found in package"
parent 1786bc19
......@@ -6,6 +6,7 @@
"require": {
"composer/installers": "^1.0.24",
"drupal/core": "self.version",
"drupal/core-vendor-hardening": "self.version",
"wikimedia/composer-merge-plugin": "^1.4"
},
"require-dev": {
......@@ -72,9 +73,6 @@
"pre-install-cmd": "Drupal\\Core\\Composer\\Composer::ensureComposerVersion",
"pre-update-cmd": "Drupal\\Core\\Composer\\Composer::ensureComposerVersion",
"pre-autoload-dump": "Drupal\\Core\\Composer\\Composer::preAutoloadDump",
"post-autoload-dump": "Drupal\\Core\\Composer\\Composer::ensureHtaccess",
"post-package-install": "Drupal\\Core\\Composer\\Composer::vendorTestCodeCleanup",
"post-package-update": "Drupal\\Core\\Composer\\Composer::vendorTestCodeCleanup",
"phpcs": "phpcs --standard=core/phpcs.xml.dist --runtime-set installed_paths $($COMPOSER_BINARY config vendor-dir)/drupal/coder/coder_sniffer --",
"phpcbf": "phpcbf --standard=core/phpcs.xml.dist --runtime-set installed_paths $($COMPOSER_BINARY config vendor-dir)/drupal/coder/coder_sniffer --"
},
......@@ -86,6 +84,10 @@
{
"type": "path",
"url": "core"
},
{
"type": "path",
"url": "composer/Plugin/VendorHardening"
}
]
}
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "bc036f74a7ef48097e813b50a2d5aea8",
"content-hash": "63b940ec40ef24930a101dfce6eed82a",
"packages": [
{
"name": "asm89/stack-cors",
......@@ -911,6 +911,36 @@
],
"description": "Drupal is an open source content management platform powering millions of websites and applications."
},
{
"name": "drupal/core-vendor-hardening",
"version": "9.0.x-dev",
"dist": {
"type": "path",
"url": "composer/Plugin/VendorHardening",
"reference": "2db54f089065dedbe4a040b01f7b527f2bad68f6"
},
"require": {
"composer-plugin-api": "^1.1",
"php": ">=7.0.8"
},
"type": "composer-plugin",
"extra": {
"class": "Drupal\\Composer\\Plugin\\VendorHardening\\VendorHardeningPlugin"
},
"autoload": {
"psr-4": {
"Drupal\\Composer\\Plugin\\VendorHardening\\": "."
}
},
"license": [
"GPL-2.0-or-later"
],
"description": "Hardens the vendor directory for when it's in the docroot.",
"homepage": "https://www.drupal.org/project/drupal",
"keywords": [
"drupal"
]
},
{
"name": "easyrdf/easyrdf",
"version": "0.9.1",
......@@ -6229,6 +6259,7 @@
"minimum-stability": "dev",
"stability-flags": {
"drupal/core": 20,
"drupal/core-vendor-hardening": 20,
"behat/mink": 20,
"behat/mink-selenium2-driver": 20
},
......
......@@ -5,12 +5,13 @@
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Installer\PackageEvent;
use Composer\Installer\PackageEvents;
use Composer\IO\IOInterface;
use Composer\Package\CompletePackage;
use Composer\Plugin\PluginInterface;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;
use Composer\Util\Filesystem;
use Composer\Script\Event;
use Composer\Installer\PackageEvents;
/**
* A Composer plugin to clean out your project's vendor directory.
......@@ -70,6 +71,8 @@ public static function getSubscribedEvents() {
ScriptEvents::POST_AUTOLOAD_DUMP => 'onPostAutoloadDump',
ScriptEvents::POST_UPDATE_CMD => 'onPostCmd',
ScriptEvents::POST_INSTALL_CMD => 'onPostCmd',
PackageEvents::PRE_PACKAGE_INSTALL => 'onPrePackageInstall',
PackageEvents::PRE_PACKAGE_UPDATE => 'onPrePackageUpdate',
PackageEvents::POST_PACKAGE_INSTALL => 'onPostPackageInstall',
PackageEvents::POST_PACKAGE_UPDATE => 'onPostPackageUpdate',
];
......@@ -95,6 +98,28 @@ public function onPostCmd(Event $event) {
$this->cleanAllPackages($this->composer->getConfig()->get('vendor-dir'));
}
/**
* PRE_PACKAGE_INSTALL event handler.
*
* @param \Composer\Installer\PackageEvent $event
*/
public function onPrePackageInstall(PackageEvent $event) {
/** @var \Composer\Package\CompletePackage $package */
$package = $event->getOperation()->getPackage();
$this->removeBinBeforeCleanup($package);
}
/**
* PRE_PACKAGE_UPDATE event handler.
*
* @param \Composer\Installer\PackageEvent $event
*/
public function onPrePackageUpdate(PackageEvent $event) {
/** @var \Composer\Package\CompletePackage $package */
$package = $event->getOperation()->getTargetPackage();
$this->removeBinBeforeCleanup($package);
}
/**
* POST_PACKAGE_INSTALL event handler.
*
......@@ -119,6 +144,84 @@ public function onPostPackageUpdate(PackageEvent $event) {
$this->cleanPackage($this->composer->getConfig()->get('vendor-dir'), $package_name);
}
/**
* Remove bin config for packages that would have the bin file removed.
*
* Where the configured bin files are in the directories to be removed, remove
* the bin config.
*
* @param \Composer\Package\CompletePackage $package
* The package we're cleaning up.
*/
protected function removeBinBeforeCleanup(CompletePackage $package) {
// Only do this if there are binaries and cleanup paths.
$binaries = $package->getBinaries();
$clean_paths = $this->config->getPathsForPackage($package->getName());
if (!$binaries || !$clean_paths) {
return;
}
if ($unset_these_binaries = $this->findBinOverlap($binaries, $clean_paths)) {
$this->io->writeError(
sprintf('%sModifying bin config for <info>%s</info> which overlaps with cleanup directories.', str_repeat(' ', 4), $package->getName()),
TRUE,
IOInterface::VERBOSE
);
$modified_binaries = [];
foreach ($binaries as $binary) {
if (!in_array($binary, $unset_these_binaries)) {
$modified_binaries[] = $binary;
}
}
$package->setBinaries($modified_binaries);
}
}
/**
* Find bin files which are inside cleanup directories.
*
* @param string[] $binaries
* 'Bin' configuration from the package we're cleaning up.
* @param string[] $clean_paths
* The paths we're cleaning up.
*
* @return string[]
* Bin files to remove, with the file as both the key and the value.
*/
protected function findBinOverlap($binaries, $clean_paths) {
// Make a filesystem model to explore. This is a keyed array that looks like
// all the places that will be removed by cleanup. 'tests/src' becomes
// $filesystem['tests']['src'] = TRUE;
$filesystem = [];
foreach ($clean_paths as $clean_path) {
$clean_pieces = explode("/", $clean_path);
$current = &$filesystem;
foreach ($clean_pieces as $clean_piece) {
$current = &$current[$clean_piece];
}
$current = TRUE;
}
// Explore the filesystem with our bin config.
$unset_these_binaries = [];
foreach ($binaries as $binary) {
$binary_pieces = explode('/', $binary);
$current = &$filesystem;
foreach ($binary_pieces as $binary_piece) {
if (!isset($current[$binary_piece])) {
break;
}
else {
// Value of TRUE means we're at the end of the path.
if ($current[$binary_piece] === TRUE) {
$unset_these_binaries[$binary] = $binary;
break;
}
}
$current = &$filesystem[$binary_piece];
}
}
return $unset_these_binaries;
}
/**
* Gets a list of all installed packages from Composer.
*
......
......@@ -122,6 +122,9 @@ public function testCleanAllPackages() {
$this->assertFileNotExists(vfsStream::url('vendor/drupal/package/tests'));
}
/**
* @covers ::writeAccessRestrictionFiles
*/
public function testWriteAccessRestrictionFiles() {
$dir = vfsStream::url('vendor');
......@@ -148,4 +151,64 @@ public function testWriteAccessRestrictionFiles() {
$this->assertFileExists($dir . '/web.config');
}
public function providerFindBinOverlap() {
return [
[
[],
['bin/script'],
['tests'],
],
[
['bin/composer' => 'bin/composer'],
['bin/composer'],
['bin', 'tests'],
],
[
['bin/composer' => 'bin/composer'],
['bin/composer'],
['bin/composer'],
],
[
[],
['bin/composer'],
['bin/something_else'],
],
[
[],
['test/script'],
['test/longer'],
],
[
['bin/very/long/path/script' => 'bin/very/long/path/script'],
['bin/very/long/path/script'],
['bin'],
],
[
['bin/bin/bin' => 'bin/bin/bin'],
['bin/bin/bin'],
['bin/bin'],
],
[
[],
['bin/bin'],
['bin/bin/bin'],
],
];
}
/**
* @covers ::findBinOverlap
* @dataProvider providerFindBinOverlap
*/
public function testFindBinOverlap($expected, $binaries, $clean_paths) {
$plugin = $this->getMockBuilder(VendorHardeningPlugin::class)
->disableOriginalConstructor()
->getMock();
$ref_find_bin_overlap = new \ReflectionMethod($plugin, 'findBinOverlap');
$ref_find_bin_overlap->setAccessible(TRUE);
$this->assertSame($expected, $ref_find_bin_overlap->invokeArgs($plugin, [$binaries, $clean_paths]));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment