From bec76367dbc9e591e3d04408a5d37423372ce990 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 11 May 2021 13:23:18 +0200 Subject: [PATCH 1/4] Speedup extracting on Windows --- src/Composer/Downloader/ZipDownloader.php | 29 ++++++++++++++++------- src/Composer/Util/Filesystem.php | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index 8e899366b..4feef75c9 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -26,7 +26,8 @@ use ZipArchive; class ZipDownloader extends ArchiveDownloader { protected static $hasSystemUnzip; - private static $hasZipArchive; + private static $unzipCommands; + private static $hasZipArchive = false; private static $isWindows; /** @var ZipArchive|null */ @@ -37,16 +38,22 @@ class ZipDownloader extends ArchiveDownloader */ public function download(PackageInterface $package, $path, PackageInterface $prevPackage = null, $output = true) { - if (null === self::$hasSystemUnzip) { + if (null === self::$unzipCommands) { + self::$unzipCommands = array(); $finder = new ExecutableFinder; - self::$hasSystemUnzip = (bool) $finder->find('unzip'); + if (Platform::isWindows() && ($cmd = $finder->find('7z', null, array('C:\Program Files\7-Zip')))) { + self::$unzipCommands[] = ProcessExecutor::escape($cmd).' x -y %s -o%s'; + } + if ($cmd = $finder->find('unzip')) { + self::$unzipCommands[] = ProcessExecutor::escape($cmd).' %s -d %s'; + } } if (null === self::$hasZipArchive) { self::$hasZipArchive = class_exists('ZipArchive'); } - if (!self::$hasZipArchive && !self::$hasSystemUnzip) { + if (!self::$hasZipArchive && !self::$unzipCommands) { // php.ini path is added to the error message to help users find the correct file $iniMessage = IniHelper::getMessage(); $error = "The zip extension and unzip command are both missing, skipping.\n" . $iniMessage; @@ -57,7 +64,7 @@ class ZipDownloader extends ArchiveDownloader if (null === self::$isWindows) { self::$isWindows = Platform::isWindows(); - if (!self::$isWindows && !self::$hasSystemUnzip) { + if (!self::$isWindows && !self::$unzipCommands) { $this->io->writeError("As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension."); $this->io->writeError("This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost."); $this->io->writeError("Installing 'unzip' may remediate them."); @@ -82,7 +89,7 @@ class ZipDownloader extends ArchiveDownloader $isLastChance = true; } - if (!self::$hasSystemUnzip && !$isLastChance) { + if (!self::$unzipCommands && !$isLastChance) { // This was call as the favorite extract way, but is not available // We switch to the alternative return $this->extractWithZipArchive($package, $file, $path, true); @@ -90,7 +97,11 @@ class ZipDownloader extends ArchiveDownloader // When called after a ZipArchive failed, perhaps there is some files to overwrite $overwrite = $isLastChance ? '-o' : ''; - $command = 'unzip -qq '.$overwrite.' '.ProcessExecutor::escape($file).' -d '.ProcessExecutor::escape($path); + foreach (self::$unzipCommands as $command) { + echo $command, "\n"; + $command = sprintf($command, ProcessExecutor::escape($file), ProcessExecutor::escape($path)); + break; + } if ($async) { $self = $this; @@ -166,7 +177,7 @@ class ZipDownloader extends ArchiveDownloader */ public function extractWithZipArchive(PackageInterface $package, $file, $path, $isLastChance) { - if (!self::$hasSystemUnzip) { + if (!self::$unzipCommands) { // Force Exception throwing if the Other alternative is not available $isLastChance = true; } @@ -226,7 +237,7 @@ class ZipDownloader extends ArchiveDownloader { // Each extract calls its alternative if not available or fails if (self::$isWindows) { - return $this->extractWithZipArchive($package, $file, $path, false); + //return $this->extractWithZipArchive($package, $file, $path, false); } return $this->extractWithSystemUnzip($package, $file, $path, false, true); diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 8335052c7..c83df2797 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -188,7 +188,7 @@ class Filesystem throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.'); } - if (!\function_exists('proc_open')) { + if (1||!\function_exists('proc_open')) { return $this->removeDirectoryPhp($directory); } From d864c5743a0be8a70ad32c33be8bd4db5cc4350d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 2 Jun 2021 13:39:26 +0200 Subject: [PATCH 2/4] Add 7-zip presence check to diagnose command --- src/Composer/Command/DiagnoseCommand.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index 401b01a46..f36ee3343 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -24,6 +24,7 @@ use Composer\Util\IniHelper; use Composer\Util\ProcessExecutor; use Composer\Util\HttpDownloader; use Composer\Util\StreamContextFactory; +use Composer\Util\Platform; use Composer\SelfUpdate\Keys; use Composer\SelfUpdate\Versions; use Composer\IO\NullIO; @@ -176,9 +177,17 @@ EOT $finder = new ExecutableFinder; $hasSystemUnzip = (bool) $finder->find('unzip'); + if (Platform::isWindows()) { + $hasSystem7zip = (bool) $finder->find('7z', null, array('C:\Program Files\7-Zip')); + $windows7z = ', ' . ($hasSystem7zip ? '7-Zip present' : '7-Zip not available'); + } else { + $windows7z = ''; + } + $io->write( 'zip: ' . (extension_loaded('zip') ? 'extension present' : 'extension not loaded') . ', ' . ($hasSystemUnzip ? 'unzip present' : 'unzip not available') + . $windows7z ); return $this->exitCode; From 28c7d0ea5d4477d3f74236c72d9548fa9760c2f1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 2 Jun 2021 13:46:51 +0200 Subject: [PATCH 3/4] Avoid creating new processes to remove directories which we know are empty, which speeds things up a lot on windows --- src/Composer/Downloader/ArchiveDownloader.php | 2 +- src/Composer/Downloader/FileDownloader.php | 2 +- src/Composer/Util/Filesystem.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index cc667e692..27b86cf9d 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -137,7 +137,7 @@ abstract class ArchiveDownloader extends FileDownloader }; $renameAsOne = false; - if (!file_exists($path) || ($filesystem->isDirEmpty($path) && $filesystem->removeDirectory($path))) { + if (!file_exists($path) || ($filesystem->isDirEmpty($path) && $filesystem->removeDirectoryPhp($path))) { $renameAsOne = true; } diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 63cba2e3c..0062d22b8 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -306,7 +306,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface foreach ($dirsToCleanUp as $dir) { if (is_dir($dir) && $this->filesystem->isDirEmpty($dir) && realpath($dir) !== getcwd()) { - $this->filesystem->removeDirectory($dir); + $this->filesystem->removeDirectoryPhp($dir); } } diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index c83df2797..8335052c7 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -188,7 +188,7 @@ class Filesystem throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.'); } - if (1||!\function_exists('proc_open')) { + if (!\function_exists('proc_open')) { return $this->removeDirectoryPhp($directory); } From 8bf0ddf905aedcc76a1ec24f772373cf5adf9ac2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 2 Jun 2021 15:00:31 +0200 Subject: [PATCH 4/4] Clean up ZipDownloader, always do async first if possible then fallback to non-async --- src/Composer/Downloader/ZipDownloader.php | 149 ++++++------------ .../Test/Downloader/ZipDownloaderTest.php | 70 +------- .../functional/installed-versions.test | 2 +- .../functional/installed-versions2.test | 2 +- 4 files changed, 51 insertions(+), 172 deletions(-) diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index 4feef75c9..694ad7cc3 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -25,9 +25,8 @@ use ZipArchive; */ class ZipDownloader extends ArchiveDownloader { - protected static $hasSystemUnzip; private static $unzipCommands; - private static $hasZipArchive = false; + private static $hasZipArchive; private static $isWindows; /** @var ZipArchive|null */ @@ -42,10 +41,10 @@ class ZipDownloader extends ArchiveDownloader self::$unzipCommands = array(); $finder = new ExecutableFinder; if (Platform::isWindows() && ($cmd = $finder->find('7z', null, array('C:\Program Files\7-Zip')))) { - self::$unzipCommands[] = ProcessExecutor::escape($cmd).' x -y %s -o%s'; + self::$unzipCommands[] = array('7z', ProcessExecutor::escape($cmd).' x -bb0 -y %s -o%s'); } if ($cmd = $finder->find('unzip')) { - self::$unzipCommands[] = ProcessExecutor::escape($cmd).' %s -d %s'; + self::$unzipCommands[] = array('unzip', ProcessExecutor::escape($cmd).' -qq %s -d %s'); } } @@ -56,7 +55,7 @@ class ZipDownloader extends ArchiveDownloader if (!self::$hasZipArchive && !self::$unzipCommands) { // php.ini path is added to the error message to help users find the correct file $iniMessage = IniHelper::getMessage(); - $error = "The zip extension and unzip command are both missing, skipping.\n" . $iniMessage; + $error = "The zip extension and unzip/7z commands are both missing, skipping.\n" . $iniMessage; throw new \RuntimeException($error); } @@ -65,9 +64,9 @@ class ZipDownloader extends ArchiveDownloader self::$isWindows = Platform::isWindows(); if (!self::$isWindows && !self::$unzipCommands) { - $this->io->writeError("As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension."); + $this->io->writeError("As there is no 'unzip' nor '7z' command installed zip files are being unpacked using the PHP zip extension."); $this->io->writeError("This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost."); - $this->io->writeError("Installing 'unzip' may remediate them."); + $this->io->writeError("Installing 'unzip' or '7z' may remediate them."); } } @@ -79,89 +78,59 @@ class ZipDownloader extends ArchiveDownloader * * @param string $file File to extract * @param string $path Path where to extract file - * @param bool $isLastChance If true it is called as a fallback and should throw an exception * @return PromiseInterface */ - private function extractWithSystemUnzip(PackageInterface $package, $file, $path, $isLastChance, $async = false) + private function extractWithSystemUnzip(PackageInterface $package, $file, $path) { - if (!self::$hasZipArchive) { - // Force Exception throwing if the Other alternative is not available - $isLastChance = true; - } + // Force Exception throwing if the other alternative extraction method is not available + $isLastChance = !self::$hasZipArchive; - if (!self::$unzipCommands && !$isLastChance) { + if (!self::$unzipCommands) { // This was call as the favorite extract way, but is not available // We switch to the alternative - return $this->extractWithZipArchive($package, $file, $path, true); + return $this->extractWithZipArchive($package, $file, $path); } - // When called after a ZipArchive failed, perhaps there is some files to overwrite - $overwrite = $isLastChance ? '-o' : ''; - foreach (self::$unzipCommands as $command) { - echo $command, "\n"; - $command = sprintf($command, ProcessExecutor::escape($file), ProcessExecutor::escape($path)); - break; - } + $commandSpec = reset(self::$unzipCommands); + $command = sprintf($commandSpec[1], ProcessExecutor::escape($file), ProcessExecutor::escape($path)); + $executable = $commandSpec[0]; - if ($async) { - $self = $this; - $io = $this->io; - $tryFallback = function ($processError) use ($isLastChance, $io, $self, $file, $path, $package) { - if ($isLastChance) { - throw $processError; - } - - if (!is_file($file)) { - $io->writeError(' '.$processError->getMessage().''); - $io->writeError(' This most likely is due to a custom installer plugin not handling the returned Promise from the downloader'); - $io->writeError(' See https://github.com/composer/installers/commit/5006d0c28730ade233a8f42ec31ac68fb1c5c9bb for an example fix'); - } else { - $io->writeError(' '.$processError->getMessage().''); - $io->writeError(' The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems)'); - $io->writeError(' Unzip with unzip command failed, falling back to ZipArchive class'); - } - - return $self->extractWithZipArchive($package, $file, $path, true); - }; - - try { - $promise = $this->process->executeAsync($command); - - return $promise->then(function ($process) use ($tryFallback, $command, $package, $file) { - if (!$process->isSuccessful()) { - $output = $process->getErrorOutput(); - $output = str_replace(', '.$file.'.zip or '.$file.'.ZIP', '', $output); - - return $tryFallback(new \RuntimeException('Failed to extract '.$package->getName().': ('.$process->getExitCode().') '.$command."\n\n".$output)); - } - }); - } catch (\Exception $e) { - return $tryFallback($e); - } catch (\Throwable $e) { - return $tryFallback($e); + $self = $this; + $io = $this->io; + $tryFallback = function ($processError) use ($isLastChance, $io, $self, $file, $path, $package, $executable) { + if ($isLastChance) { + throw $processError; } - } - $processError = null; + if (!is_file($file)) { + $io->writeError(' '.$processError->getMessage().''); + $io->writeError(' This most likely is due to a custom installer plugin not handling the returned Promise from the downloader'); + $io->writeError(' See https://github.com/composer/installers/commit/5006d0c28730ade233a8f42ec31ac68fb1c5c9bb for an example fix'); + } else { + $io->writeError(' '.$processError->getMessage().''); + $io->writeError(' The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems)'); + $io->writeError(' Unzip with '.$executable.' command failed, falling back to ZipArchive class'); + } + + return $self->extractWithZipArchive($package, $file, $path); + }; + try { - if (0 === $exitCode = $this->process->execute($command, $ignoredOutput)) { - return \React\Promise\resolve(); - } + $promise = $this->process->executeAsync($command); - $processError = new \RuntimeException('Failed to execute ('.$exitCode.') '.$command."\n\n".$this->process->getErrorOutput()); + return $promise->then(function ($process) use ($tryFallback, $command, $package, $file) { + if (!$process->isSuccessful()) { + $output = $process->getErrorOutput(); + $output = str_replace(', '.$file.'.zip or '.$file.'.ZIP', '', $output); + + return $tryFallback(new \RuntimeException('Failed to extract '.$package->getName().': ('.$process->getExitCode().') '.$command."\n\n".$output)); + } + }); } catch (\Exception $e) { - $processError = $e; + return $tryFallback($e); + } catch (\Throwable $e) { + return $tryFallback($e); } - - if ($isLastChance) { - throw $processError; - } - - $this->io->writeError(' '.$processError->getMessage().''); - $this->io->writeError(' The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems)'); - $this->io->writeError(' Unzip with unzip command failed, falling back to ZipArchive class'); - - return $this->extractWithZipArchive($package, $file, $path, true); } /** @@ -169,25 +138,13 @@ class ZipDownloader extends ArchiveDownloader * * @param string $file File to extract * @param string $path Path where to extract file - * @param bool $isLastChance If true it is called as a fallback and should throw an exception * @return PromiseInterface * * TODO v3 should make this private once we can drop PHP 5.3 support * @protected */ - public function extractWithZipArchive(PackageInterface $package, $file, $path, $isLastChance) + public function extractWithZipArchive(PackageInterface $package, $file, $path) { - if (!self::$unzipCommands) { - // Force Exception throwing if the Other alternative is not available - $isLastChance = true; - } - - if (!self::$hasZipArchive && !$isLastChance) { - // This was call as the favorite extract way, but is not available - // We switch to the alternative - return $this->extractWithSystemUnzip($package, $file, $path, true); - } - $processError = null; $zipArchive = $this->zipArchiveObject ?: new ZipArchive(); @@ -213,14 +170,7 @@ class ZipDownloader extends ArchiveDownloader $processError = $e; } - if ($isLastChance) { - throw $processError; - } - - $this->io->writeError(' '.$processError->getMessage().''); - $this->io->writeError(' Unzip with ZipArchive class failed, falling back to unzip command'); - - return $this->extractWithSystemUnzip($package, $file, $path, true); + throw $processError; } /** @@ -235,12 +185,7 @@ class ZipDownloader extends ArchiveDownloader */ public function extract(PackageInterface $package, $file, $path) { - // Each extract calls its alternative if not available or fails - if (self::$isWindows) { - //return $this->extractWithZipArchive($package, $file, $path, false); - } - - return $this->extractWithSystemUnzip($package, $file, $path, false, true); + return $this->extractWithSystemUnzip($package, $file, $path); } /** diff --git a/tests/Composer/Test/Downloader/ZipDownloaderTest.php b/tests/Composer/Test/Downloader/ZipDownloaderTest.php index 4d8b8460b..986c46e4a 100644 --- a/tests/Composer/Test/Downloader/ZipDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ZipDownloaderTest.php @@ -44,7 +44,6 @@ class ZipDownloaderTest extends TestCase { $fs = new Filesystem; $fs->removeDirectory($this->testDir); - $this->setPrivateProperty('hasSystemUnzip', null); $this->setPrivateProperty('hasZipArchive', null); } @@ -86,7 +85,6 @@ class ZipDownloaderTest extends TestCase $downloader = new ZipDownloader($this->io, $this->config, $this->httpDownloader); - $this->setPrivateProperty('hasSystemUnzip', false); try { $loop = new Loop($this->httpDownloader); @@ -107,7 +105,6 @@ class ZipDownloaderTest extends TestCase $this->markTestSkipped('zip extension missing'); } - $this->setPrivateProperty('hasSystemUnzip', false); $this->setPrivateProperty('hasZipArchive', true); $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader); $zipArchive = $this->getMockBuilder('ZipArchive')->getMock(); @@ -130,7 +127,6 @@ class ZipDownloaderTest extends TestCase $this->markTestSkipped('zip extension missing'); } - $this->setPrivateProperty('hasSystemUnzip', false); $this->setPrivateProperty('hasZipArchive', true); $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader); $zipArchive = $this->getMockBuilder('ZipArchive')->getMock(); @@ -152,7 +148,6 @@ class ZipDownloaderTest extends TestCase $this->markTestSkipped('zip extension missing'); } - $this->setPrivateProperty('hasSystemUnzip', false); $this->setPrivateProperty('hasZipArchive', true); $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader); $zipArchive = $this->getMockBuilder('ZipArchive')->getMock(); @@ -172,8 +167,8 @@ class ZipDownloaderTest extends TestCase { $this->setExpectedException('Exception', 'Failed to extract : (1) unzip'); $this->setPrivateProperty('isWindows', false); - $this->setPrivateProperty('hasSystemUnzip', true); $this->setPrivateProperty('hasZipArchive', false); + $this->setPrivateProperty('unzipCommands', array(array('unzip', 'unzip -qq %s -d %s'))); $procMock = $this->getMockBuilder('Symfony\Component\Process\Process')->disableOriginalConstructor()->getMock(); $procMock->expects($this->any()) @@ -199,8 +194,8 @@ class ZipDownloaderTest extends TestCase public function testSystemUnzipOnlyGood() { $this->setPrivateProperty('isWindows', false); - $this->setPrivateProperty('hasSystemUnzip', true); $this->setPrivateProperty('hasZipArchive', false); + $this->setPrivateProperty('unzipCommands', array(array('unzip', 'unzip -qq %s -d %s'))); $procMock = $this->getMockBuilder('Symfony\Component\Process\Process')->disableOriginalConstructor()->getMock(); $procMock->expects($this->any()) @@ -230,7 +225,6 @@ class ZipDownloaderTest extends TestCase } $this->setPrivateProperty('isWindows', false); - $this->setPrivateProperty('hasSystemUnzip', true); $this->setPrivateProperty('hasZipArchive', true); $procMock = $this->getMockBuilder('Symfony\Component\Process\Process')->disableOriginalConstructor()->getMock(); @@ -271,7 +265,6 @@ class ZipDownloaderTest extends TestCase } $this->setPrivateProperty('isWindows', false); - $this->setPrivateProperty('hasSystemUnzip', true); $this->setPrivateProperty('hasZipArchive', true); $procMock = $this->getMockBuilder('Symfony\Component\Process\Process')->disableOriginalConstructor()->getMock(); @@ -304,65 +297,6 @@ class ZipDownloaderTest extends TestCase $this->wait($promise); } - public function testWindowsFallbackGood() - { - if (!class_exists('ZipArchive')) { - $this->markTestSkipped('zip extension missing'); - } - - $this->setPrivateProperty('isWindows', true); - $this->setPrivateProperty('hasSystemUnzip', true); - $this->setPrivateProperty('hasZipArchive', true); - - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->atLeastOnce()) - ->method('execute') - ->will($this->returnValue(0)); - - $zipArchive = $this->getMockBuilder('ZipArchive')->getMock(); - $zipArchive->expects($this->at(0)) - ->method('open') - ->will($this->returnValue(true)); - $zipArchive->expects($this->at(1)) - ->method('extractTo') - ->will($this->returnValue(false)); - - $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, null, $processExecutor); - $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); - $this->wait($promise); - } - - public function testWindowsFallbackFailed() - { - $this->setExpectedException('Exception', 'Failed to execute (1) unzip'); - if (!class_exists('ZipArchive')) { - $this->markTestSkipped('zip extension missing'); - } - - $this->setPrivateProperty('isWindows', true); - $this->setPrivateProperty('hasSystemUnzip', true); - $this->setPrivateProperty('hasZipArchive', true); - - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->atLeastOnce()) - ->method('execute') - ->will($this->returnValue(1)); - - $zipArchive = $this->getMockBuilder('ZipArchive')->getMock(); - $zipArchive->expects($this->at(0)) - ->method('open') - ->will($this->returnValue(true)); - $zipArchive->expects($this->at(1)) - ->method('extractTo') - ->will($this->returnValue(false)); - - $downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, null, $processExecutor); - $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader); - $promise = $downloader->extract($this->package, 'testfile.zip', 'vendor/dir'); - $this->wait($promise); - } - private function wait($promise) { if (null === $promise) { diff --git a/tests/Composer/Test/Fixtures/functional/installed-versions.test b/tests/Composer/Test/Fixtures/functional/installed-versions.test index 9591c935c..3232264b6 100644 --- a/tests/Composer/Test/Fixtures/functional/installed-versions.test +++ b/tests/Composer/Test/Fixtures/functional/installed-versions.test @@ -21,7 +21,7 @@ Lock file operations: 6 installs, 0 updates, 0 removals - Locking symfony/process (12345.1.2) Writing lock file Installing dependencies from lock file (including require-dev) -Package operations: 6 installs, 0 updates, 0 removals%(\nAs there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.\nThis may cause invalid reports of corrupted archives. Besides, any UNIX permissions \(e.g. executable\) defined in the archives will be lost.\nInstalling 'unzip' may remediate them.)?% +Package operations: 6 installs, 0 updates, 0 removals%(\nAs there is no 'unzip' nor '7z' command installed zip files are being unpacked using the PHP zip extension.\nThis may cause invalid reports of corrupted archives. Besides, any UNIX permissions \(e.g. executable\) defined in the archives will be lost.\nInstalling 'unzip' or '7z' may remediate them.)?% - Downloading symfony/polyfill-ctype (%v?[1-8]\.\d+\.\d+%) - Downloading symfony/filesystem (%v?[2-8]\.\d+\.\d+%) - Installing symfony/console (99999.1.2): Symlinking from symfony-console diff --git a/tests/Composer/Test/Fixtures/functional/installed-versions2.test b/tests/Composer/Test/Fixtures/functional/installed-versions2.test index 2012f38ba..d98870b26 100644 --- a/tests/Composer/Test/Fixtures/functional/installed-versions2.test +++ b/tests/Composer/Test/Fixtures/functional/installed-versions2.test @@ -26,7 +26,7 @@ Lock file operations: 0 installs, 5 updates, 0 removals - Upgrading symfony/process (12345.1.2 => 12345.1.3) Writing lock file Installing dependencies from lock file (including require-dev) -Package operations: 0 installs, 5 updates, 0 removals%(\nAs there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.\nThis may cause invalid reports of corrupted archives. Besides, any UNIX permissions \(e.g. executable\) defined in the archives will be lost.\nInstalling 'unzip' may remediate them.)?% +Package operations: 0 installs, 5 updates, 0 removals%(\nAs there is no 'unzip' nor '7z' command installed zip files are being unpacked using the PHP zip extension.\nThis may cause invalid reports of corrupted archives. Besides, any UNIX permissions \(e.g. executable\) defined in the archives will be lost.\nInstalling 'unzip' or '7z' may remediate them.)?% - Downloading symfony/filesystem (%v?[2-8]\.\d+\.\d+%) - Upgrading symfony/console (99999.1.2 => 99999.1.3): Mirroring from symfony-console - Upgrading plugin/a (1.1.1 => 1.1.2): Mirroring from plugin-a