Browse Source

Retry downloading when a corrupt zip is found, fixes #2133, fixes #2128, fixes #2125

Jordi Boggiano 12 years ago
parent
commit
7912253df6

+ 47 - 32
src/Composer/Downloader/ArchiveDownloader.php

@@ -28,45 +28,60 @@ abstract class ArchiveDownloader extends FileDownloader
      */
      */
     public function download(PackageInterface $package, $path)
     public function download(PackageInterface $package, $path)
     {
     {
-        parent::download($package, $path);
+        $temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
+        $retries = 3;
+        while ($retries--) {
+            parent::download($package, $path);
 
 
-        $fileName = $this->getFileName($package, $path);
-        if ($this->io->isVerbose()) {
-            $this->io->write('    Extracting archive');
-        }
+            $fileName = $this->getFileName($package, $path);
+            if ($this->io->isVerbose()) {
+                $this->io->write('    Extracting archive');
+            }
 
 
-        $temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
-        try {
-            $this->filesystem->ensureDirectoryExists($temporaryDir);
             try {
             try {
-                $this->extract($fileName, $temporaryDir);
+                $this->filesystem->ensureDirectoryExists($temporaryDir);
+                try {
+                    $this->extract($fileName, $temporaryDir);
+                } catch (\Exception $e) {
+                    // remove cache if the file was corrupted
+                    parent::clearCache($package, $path);
+                    throw $e;
+                }
+
+                unlink($fileName);
+
+                // get file list
+                $contentDir = $this->listFiles($temporaryDir);
+
+                // only one dir in the archive, extract its contents out of it
+                if (1 === count($contentDir) && !is_file($contentDir[0])) {
+                    $contentDir = $this->listFiles($contentDir[0]);
+                }
+
+                // move files back out of the temp dir
+                foreach ($contentDir as $file) {
+                    $this->filesystem->rename($file, $path . '/' . basename($file));
+                }
+
+                $this->filesystem->removeDirectory($temporaryDir);
             } catch (\Exception $e) {
             } catch (\Exception $e) {
-                // remove cache if the file was corrupted
-                parent::clearCache($package, $path);
-                throw $e;
-            }
+                // clean up
+                $this->filesystem->removeDirectory($path);
+                $this->filesystem->removeDirectory($temporaryDir);
+
+                // retry downloading if we have an invalid zip file
+                if ($retries && $e instanceof \UnexpectedValueException && $e->getCode() === \ZipArchive::ER_NOZIP) {
+                    if ($this->io->isVerbose()) {
+                        $this->io->write('    Invalid zip file, retrying...');
+                    }
+                    usleep(500000);
+                    continue;
+                }
 
 
-            unlink($fileName);
-
-            // get file list
-            $contentDir = $this->listFiles($temporaryDir);
-
-            // only one dir in the archive, extract its contents out of it
-            if (1 === count($contentDir) && !is_file($contentDir[0])) {
-                $contentDir = $this->listFiles($contentDir[0]);
-            }
-
-            // move files back out of the temp dir
-            foreach ($contentDir as $file) {
-                $this->filesystem->rename($file, $path . '/' . basename($file));
+                throw $e;
             }
             }
 
 
-            $this->filesystem->removeDirectory($temporaryDir);
-        } catch (\Exception $e) {
-            // clean up
-            $this->filesystem->removeDirectory($path);
-            $this->filesystem->removeDirectory($temporaryDir);
-            throw $e;
+            break;
         }
         }
 
 
         $this->io->write('');
         $this->io->write('');

+ 1 - 5
src/Composer/Downloader/ZipDownloader.php

@@ -68,11 +68,7 @@ class ZipDownloader extends ArchiveDownloader
         $zipArchive = new ZipArchive();
         $zipArchive = new ZipArchive();
 
 
         if (true !== ($retval = $zipArchive->open($file))) {
         if (true !== ($retval = $zipArchive->open($file))) {
-            if (ZipArchive::ER_NOZIP === $retval) {
-                @copy($file, $copy = sys_get_temp_dir().'/composer-zip-debug.zip');
-                throw new \UnexpectedValueException($this->getErrorMessage($retval, $file).' filesize: '.filesize($file).', file copied to '.$copy.' for debugging, please report this and email us the file if possible');
-            }
-            throw new \UnexpectedValueException($this->getErrorMessage($retval, $file));
+            throw new \UnexpectedValueException($this->getErrorMessage($retval, $file), $retval);
         }
         }
 
 
         if (true !== $zipArchive->extractTo($path)) {
         if (true !== $zipArchive->extractTo($path)) {

+ 1 - 1
tests/Composer/Test/Downloader/ZipDownloaderTest.php

@@ -33,7 +33,7 @@ class ZipDownloaderTest extends \PHPUnit_Framework_TestCase
 
 
         $io = $this->getMock('Composer\IO\IOInterface');
         $io = $this->getMock('Composer\IO\IOInterface');
         $config = $this->getMock('Composer\Config');
         $config = $this->getMock('Composer\Config');
-        $config->expects($this->once())
+        $config->expects($this->any())
             ->method('get')
             ->method('get')
             ->with('vendor-dir')
             ->with('vendor-dir')
             ->will($this->returnValue(sys_get_temp_dir().'/composer-zip-test-vendor'));
             ->will($this->returnValue(sys_get_temp_dir().'/composer-zip-test-vendor'));