Pārlūkot izejas kodu

Fully implemented junctioning on Windows for path repositories.

Niels Keurentjes 9 gadi atpakaļ
vecāks
revīzija
5489586436

+ 10 - 3
src/Composer/Downloader/PathDownloader.php

@@ -48,9 +48,16 @@ class PathDownloader extends FileDownloader
         }
 
         try {
-            $shortestPath = $this->filesystem->findShortestPath($path, $realUrl);
-            $fileSystem->symlink($shortestPath, $path);
-            $this->io->writeError(sprintf('    Symlinked from %s', $url));
+            if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+                // Implement symlinks as junctions on Windows, with magic shell hackery
+                $this->filesystem->junction($realUrl, $path);
+                $this->io->writeError(sprintf('    Junctioned from %s', $url));
+
+            } else {
+                $shortestPath = $this->filesystem->findShortestPath($path, $realUrl);
+                $fileSystem->symlink($shortestPath, $path);
+                $this->io->writeError(sprintf('    Symlinked from %s', $url));
+            }
         } catch (IOException $e) {
             $fileSystem->mirror($realUrl, $path);
             $this->io->writeError(sprintf('    Mirrored from %s', $url));

+ 19 - 0
src/Composer/Util/Filesystem.php

@@ -14,6 +14,7 @@ namespace Composer\Util;
 
 use RecursiveDirectoryIterator;
 use RecursiveIteratorIterator;
+use Symfony\Component\Filesystem\Exception\IOException;
 use Symfony\Component\Finder\Finder;
 
 /**
@@ -581,6 +582,24 @@ class Filesystem
         return $resolved;
     }
 
+    /**
+     * Creates an NTFS junction.
+     *
+     * @param string $originDir
+     * @param string $targetDir
+     */
+    public function junction($originDir, $targetDir)
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $cmd = sprintf('mklink /J %s %s',
+                           ProcessExecutor::escape(str_replace('/', DIRECTORY_SEPARATOR, $targetDir)),
+                           ProcessExecutor::escape(realpath($originDir)));
+            if ($this->getProcess()->execute($cmd, $output) === 0)
+                return;
+        }
+        throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
+    }
+
     /**
      * Returns whether the target directory is a Windows NTFS Junction.
      *