diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 9379e01b3..5f41d6842 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -48,15 +48,10 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface $flag = Platform::isWindows() ? '/D ' : ''; // --dissociate option is only available since git 2.3.0-rc0 - if (version_compare($this->gitUtil->getVersion(), '2.3.0-rc0', '>=')) { - if (!file_exists($cachePath)) { - $this->io->writeError(sprintf(' Cloning to cache at %s', ProcessExecutor::escape($cachePath))); - $mirrorCommand = 'git clone --mirror %s %s'; - $mirrorCommandCallable = function ($url) use ($cachePath, $mirrorCommand) { - return sprintf($mirrorCommand, ProcessExecutor::escape($url), ProcessExecutor::escape($cachePath)); - }; - $this->gitUtil->runCommand($mirrorCommandCallable, $url, $path, true); - } + $gitVersion = $this->gitUtil->getVersion(); + if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=')) { + $this->io->writeError(sprintf(' Cloning to cache at %s', ProcessExecutor::escape($cachePath)), true, IOInterface::DEBUG); + $this->gitUtil->syncMirror($url, $cachePath); $cacheOptions = sprintf('--dissociate --reference %s ', ProcessExecutor::escape($cachePath)); } $command = 'git clone --no-checkout %s %s '.$cacheOptions.'&& cd '.$flag.'%2$s && git remote add composer %1$s && git fetch composer'; diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index e98858abc..bacad4d2c 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -58,27 +58,8 @@ class GitDriver extends VcsDriver } $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs); - - // update the repo if it is a valid git repository - if (is_dir($this->repoDir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $this->repoDir) && trim($output) === '.') { - try { - $commandCallable = function ($url) { - return sprintf('git remote set-url origin %s && git remote update --prune origin', ProcessExecutor::escape($url)); - }; - $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir); - } catch (\Exception $e) { - $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated ('.$e->getMessage().')'); - } - } else { - // clean up directory and do a fresh clone into it - $fs->removeDirectory($this->repoDir); - - $repoDir = $this->repoDir; - $commandCallable = function ($url) use ($repoDir) { - return sprintf('git clone --mirror %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); - }; - - $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir, true); + if (!$gitUtil->syncMirror($this->url, $this->repoDir)) { + $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated'); } $cacheUrl = $this->url; diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 9ddb13c80..596188fe6 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -20,6 +20,8 @@ use Composer\IO\IOInterface; */ class Git { + private static $version; + /** @var IOInterface */ protected $io; /** @var Config */ @@ -198,6 +200,34 @@ class Git } } + public function syncMirror($url, $dir) + { + // update the repo if it is a valid git repository + if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') { + try { + $commandCallable = function ($url) { + return sprintf('git remote set-url origin %s && git remote update --prune origin', ProcessExecutor::escape($url)); + }; + $this->runCommand($commandCallable, $url, $dir); + } catch (\Exception $e) { + return false; + } + + return true; + } + + // clean up directory and do a fresh clone into it + $this->filesystem->removeDirectory($dir); + + $commandCallable = function ($url) use ($dir) { + return sprintf('git clone --mirror %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($dir)); + }; + + $this->runCommand($commandCallable, $url, $dir, true); + + return true; + } + private function isAuthenticationFailure($url, &$match) { if (!preg_match('{(https?://)([^/]+)(.*)$}i', $url, $match)) { @@ -277,16 +307,18 @@ class Git /** * Retrieves the current git version. * - * @return string - * The git version number. + * @return string|null The git version number. */ - public function getVersion() { + public function getVersion() + { + if (isset(self::$version)) { + return self::$version; + } if (0 !== $this->process->execute('git --version', $output)) { - throw new \RuntimeException(self::sanitizeUrl('Failed retrieve git version, git was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput())); + return; } - if (preg_match('/^git version (.*)/', $output, $matches) !== 1) { - throw new \RuntimeException('git --version output seems to have changed, expected "git version x.y.z".'); + if (preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { + return self::$version = $matches[1]; } - return $matches[1]; } } diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index b1a0446d1..297362a44 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -36,6 +36,11 @@ class GitDownloaderTest extends TestCase if (is_dir($this->workingDir)) { $this->fs->removeDirectory($this->workingDir); } + + // reset the static version cache + $refl = new \ReflectionProperty('Composer\Util\Git', 'version'); + $refl->setAccessible(true); + $refl->setValue(null, null); } protected function setupConfig($config = null) {