Browse Source

Merge remote-tracking branch 'RobberPhex/git-repo'

Jordi Boggiano 7 years ago
parent
commit
93cd9d874b

+ 22 - 9
src/Composer/Downloader/GitDownloader.php

@@ -12,13 +12,13 @@
 
 namespace Composer\Downloader;
 
+use Composer\Config;
+use Composer\IO\IOInterface;
 use Composer\Package\PackageInterface;
+use Composer\Util\Filesystem;
 use Composer\Util\Git as GitUtil;
 use Composer\Util\Platform;
 use Composer\Util\ProcessExecutor;
-use Composer\IO\IOInterface;
-use Composer\Util\Filesystem;
-use Composer\Config;
 
 /**
  * @author Jordi Boggiano <j.boggiano@seld.be>
@@ -43,30 +43,43 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
         GitUtil::cleanEnv();
         $path = $this->normalizePath($path);
         $cachePath = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $url).'/';
-        $cacheOptions = '';
         $ref = $package->getSourceReference();
         $flag = Platform::isWindows() ? '/D ' : '';
 
         // --dissociate option is only available since git 2.3.0-rc0
         $gitVersion = $this->gitUtil->getVersion();
         $msg = "Cloning ".$this->getShortHash($ref);
+
+        $command = 'git clone --no-checkout %url% %path% && cd '.$flag.'%path% && git remote add composer %url% && git fetch composer';
         if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=')) {
             $this->io->writeError('', true, IOInterface::DEBUG);
             $this->io->writeError(sprintf('    Cloning to cache at %s', ProcessExecutor::escape($cachePath)), true, IOInterface::DEBUG);
             try {
-                $this->gitUtil->syncMirror($url, $cachePath);
+                $cached = $this->gitUtil->fetchRef($url, $cachePath, $ref);
                 if (is_dir($cachePath)) {
-                    $cacheOptions = sprintf('--dissociate --reference %s ', ProcessExecutor::escape($cachePath));
+                    $command =
+                        'git clone --no-checkout %cachePath% %path% --dissociate --reference %cachePath% '
+                        . '&& cd '.$flag.'%path% '
+                        . '&& git remote set-url origin %url% && git remote add composer %url%';
+                    if (!$cached)
+                        $command .= ' && git fetch composer';
                     $msg = "Cloning ".$this->getShortHash($ref).' from cache';
                 }
             } catch (\RuntimeException $e) {
             }
         }
-        $command = 'git clone --no-checkout %s %s '.$cacheOptions.'&& cd '.$flag.'%2$s && git remote add composer %1$s && git fetch composer';
         $this->io->writeError($msg);
 
-        $commandCallable = function ($url) use ($ref, $path, $command) {
-            return sprintf($command, ProcessExecutor::escape($url), ProcessExecutor::escape($path), ProcessExecutor::escape($ref));
+        $commandCallable = function ($url) use ($path, $command, $cachePath) {
+            return str_replace(
+                array('%url%', '%path%', '%cachePath%'),
+                array(
+                    ProcessExecutor::escape($url),
+                    ProcessExecutor::escape($path),
+                    ProcessExecutor::escape($cachePath),
+                ),
+                $command
+            );
         };
 
         $this->gitUtil->runCommand($commandCallable, $url, $path, true);

+ 30 - 0
src/Composer/Util/Git.php

@@ -228,6 +228,36 @@ class Git
         return true;
     }
 
+    public function fetchRef($url, $dir, $ref)
+    {
+        if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
+            try {
+                $isTag = $isRef = $actualCommit = false;
+                $escapedRef = ProcessExecutor::escape($ref);
+                $exitCode = $this->process->execute(sprintf('git show-ref --tags %s', $escapedRef), $output, $dir);
+                if (!$exitCode)
+                    $isTag = true;
+                $exitCode = $this->process->execute(sprintf('git show-ref %s', $escapedRef), $output, $dir);
+                if (!$exitCode)
+                    $isRef = true;
+                $exitCode = $this->process->execute(sprintf('git cat-file -t %s', $escapedRef), $output, $dir);
+                if (!$exitCode && trim($output) == "commit")
+                    $actualCommit = true;
+
+                if ($isTag){
+                    return true;
+                }
+                if (!$isRef && $actualCommit) {
+                    return true;
+                }
+            } catch (\Exception $e) {
+            }
+        }
+
+        $this->syncMirror($url, $dir);
+        return false;
+    }
+
     private function isAuthenticationFailure($url, &$match)
     {
         if (!preg_match('{(https?://)([^/]+)(.*)$}i', $url, $match)) {

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

@@ -173,7 +173,7 @@ class GitDownloaderTest extends TestCase
                 return 0;
             }));
 
-        $expectedGitCommand = $this->winCompat(sprintf("git clone --no-checkout 'https://example.com/composer/composer' 'composerPath' --dissociate --reference '%s' && cd 'composerPath' && git remote add composer 'https://example.com/composer/composer' && git fetch composer", $cachePath));
+        $expectedGitCommand = $this->winCompat(sprintf("git clone --no-checkout '%1\$s' 'composerPath' --dissociate --reference '%1\$s' && cd 'composerPath' && git remote set-url origin 'https://example.com/composer/composer' && git remote add composer 'https://example.com/composer/composer' && git fetch composer", $cachePath));
         $processExecutor->expects($this->at(2))
             ->method('execute')
             ->with($this->equalTo($expectedGitCommand))