From bec76367dbc9e591e3d04408a5d37423372ce990 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 11 May 2021 13:23:18 +0200 Subject: [PATCH] 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); }