diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php index 4d2e9c8f4..902e8beaf 100644 --- a/src/Composer/Downloader/DownloadManager.php +++ b/src/Composer/Downloader/DownloadManager.php @@ -250,11 +250,18 @@ class DownloadManager if ($initialType === $targetType) { $target->setInstallationSource($installationSource); - $downloader->update($initial, $target, $targetDir); - } else { - $downloader->remove($initial, $targetDir); - $this->download($target, $targetDir, 'source' === $installationSource); + try { + $downloader->update($initial, $target, $targetDir); + return; + } catch (\RuntimeException $ex) { + if (!$this->io->isInteractive() || + !$this->io->askConfirmation(' Updating failed. Would you like to try reinstalling instead [yes]? ', true)) { + throw $ex; + } + } } + $downloader->remove($initial, $targetDir); + $this->download($target, $targetDir, 'source' === $installationSource); } /** diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 48e0d4b39..c1d47c794 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -73,8 +73,7 @@ class GitDownloader extends VcsDownloader public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url) { GitUtil::cleanEnv(); - $path = $this->normalizePath($path); - if (!is_dir($path.'/.git')) { + if (!$this->hasMetadataRepository($path)) { throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } @@ -101,8 +100,7 @@ class GitDownloader extends VcsDownloader public function getLocalChanges(PackageInterface $package, $path) { GitUtil::cleanEnv(); - $path = $this->normalizePath($path); - if (!is_dir($path.'/.git')) { + if (!$this->hasMetadataRepository($path)) { return; } @@ -372,4 +370,17 @@ class GitDownloader extends VcsDownloader return $path; } + + /** + * Checks if VCS metadata repository has been initialized + * repository example: .git|.svn|.hg + * + * @param string $path + * @return bool + */ + protected function hasMetadataRepository($path) + { + $path = $this->normalizePath($path); + return is_dir($path.'/.git'); + } } diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index bec59175d..9c379a9e5 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -47,7 +47,7 @@ class HgDownloader extends VcsDownloader $ref = ProcessExecutor::escape($target->getSourceReference()); $this->io->writeError(" Updating to ".$target->getSourceReference()); - if (!is_dir($path.'/.hg')) { + if (!$this->hasMetadataRepository($path)) { throw new \RuntimeException('The .hg directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } @@ -84,4 +84,16 @@ class HgDownloader extends VcsDownloader return $output; } + + /** + * Checks if VCS metadata repository has been initialized + * repository example: .git|.svn|.hg + * + * @param string $path + * @return bool + */ + protected function hasMetadataRepository($path) + { + return is_dir($path . '/.hg'); + } } diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php index d99fc7997..77f82ac1e 100644 --- a/src/Composer/Downloader/PerforceDownloader.php +++ b/src/Composer/Downloader/PerforceDownloader.php @@ -104,4 +104,16 @@ class PerforceDownloader extends VcsDownloader { $this->perforce = $perforce; } + + /** + * Checks if VCS metadata repository has been initialized + * repository example: .git|.svn|.hg + * + * @param string $path + * @return bool + */ + protected function hasMetadataRepository($path) + { + return true; + } } diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index 0b4afa9a4..42ebf758e 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -52,7 +52,7 @@ class SvnDownloader extends VcsDownloader SvnUtil::cleanEnv(); $ref = $target->getSourceReference(); - if (!is_dir($path.'/.svn')) { + if (!$this->hasMetadataRepository($path)) { throw new \RuntimeException('The .svn directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } @@ -72,7 +72,7 @@ class SvnDownloader extends VcsDownloader */ public function getLocalChanges(PackageInterface $package, $path) { - if (!is_dir($path.'/.svn')) { + if (!$this->hasMetadataRepository($path)) { return; } @@ -188,4 +188,16 @@ class SvnDownloader extends VcsDownloader throw new \RuntimeException("Could not reset changes\n\n:".$this->process->getErrorOutput()); } } + + /** + * Checks if VCS metadata repository has been initialized + * repository example: .git|.svn|.hg + * + * @param string $path + * @return bool + */ + protected function hasMetadataRepository($path) + { + return is_dir($path.'/.svn'); + } } diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php index fe6c9b40f..37aa9042f 100644 --- a/src/Composer/Downloader/VcsDownloader.php +++ b/src/Composer/Downloader/VcsDownloader.php @@ -111,6 +111,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa $this->cleanChanges($initial, $path, true); $urls = $target->getSourceUrls(); + + $exception = null; while ($url = array_shift($urls)) { try { if (Filesystem::isLocalPath($url)) { @@ -118,24 +120,20 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa } $this->doUpdate($initial, $target, $path, $url); break; - } catch (\Exception $e) { + } catch (\Exception $exception) { if ($this->io->isDebug()) { - $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage()); + $this->io->writeError('Failed: ['.get_class($exception).'] '.$exception->getMessage()); } elseif (count($urls)) { $this->io->writeError(' Failed, trying the next URL'); - } else { - // in case of failed update, try to reapply the changes before aborting - $this->reapplyChanges($path); - - throw $e; } } } $this->reapplyChanges($path); - // print the commit logs if in verbose mode - if ($this->io->isVerbose()) { + // print the commit logs if in verbose mode and VCS metadata is present + // because in case of missing metadata code would trigger another exception + if ($this->io->isVerbose() && $this->hasMetadataRepository($path)) { $message = 'Pulling in changes:'; $logs = $this->getCommitLogs($initial->getSourceReference(), $target->getSourceReference(), $path); @@ -157,6 +155,10 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa } } + if (!$urls && $exception) { + throw $exception; + } + $this->io->writeError(''); } @@ -236,4 +238,13 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa * @return string */ abstract protected function getCommitLogs($fromReference, $toReference, $path); + + /** + * Checks if VCS metadata repository has been initialized + * repository example: .git|.svn|.hg + * + * @param string $path + * @return bool + */ + abstract protected function hasMetadataRepository($path); }