From 3d5f4757035f25e986b931637d829368eb375efe Mon Sep 17 00:00:00 2001 From: "Attia A. Ahmed" Date: Fri, 21 Jul 2023 11:58:54 +0300 Subject: [PATCH] Fix broken junctions leading to installation failure on Windows (#11550) --- src/Composer/Util/Filesystem.php | 6 ++++ tests/Composer/Test/Util/FilesystemTest.php | 33 +++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 91b1cbe48..04920d775 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -814,6 +814,12 @@ class Filesystem if (!is_dir($target)) { throw new IOException(sprintf('Cannot junction to "%s" as it is not a directory.', $target), 0, null, $target); } + + // Removing any previously junction to ensure clean execution. + if (!is_dir($junction) || $this->isJunction($junction)) { + @rmdir($junction); + } + $cmd = sprintf( 'mklink /J %s %s', ProcessExecutor::escape(str_replace('/', DIRECTORY_SEPARATOR, $junction)), diff --git a/tests/Composer/Test/Util/FilesystemTest.php b/tests/Composer/Test/Util/FilesystemTest.php index bdf6b7f16..9a991e4d9 100644 --- a/tests/Composer/Test/Util/FilesystemTest.php +++ b/tests/Composer/Test/Util/FilesystemTest.php @@ -12,6 +12,7 @@ namespace Composer\Test\Util; +use Composer\Util\Platform; use Composer\Util\Filesystem; use Composer\Test\TestCase; @@ -327,6 +328,38 @@ class FilesystemTest extends TestCase $this->assertFalse(is_dir($junction), $junction . ' is not a directory'); } + public function testOverrideJunctions() + { + if (!Platform::isWindows()) { + $this->markTestSkipped('Only runs on windows'); + } + + @mkdir($this->workingDir.'/real/nesting/testing', 0777, true); + $fs = new Filesystem(); + + $old_target = $this->workingDir.'/real/nesting/testing'; + $target = $this->workingDir.'/real/../real/nesting'; + $junction = $this->workingDir.'/junction'; + + // Override non-broken junction + $fs->junction($old_target, $junction); + $fs->junction($target, $junction); + + $this->assertTrue($fs->isJunction($junction), $junction.': is a junction'); + $this->assertTrue($fs->isJunction($target.'/../../junction'), $target.'/../../junction: is a junction'); + + //Remove junction + $this->assertTrue($fs->removeJunction($junction), $junction . ' has been removed'); + + // Override broken junction + $fs->junction($old_target, $junction); + $fs->removeDirectory($old_target); + $fs->junction($target, $junction); + + $this->assertTrue($fs->isJunction($junction), $junction.': is a junction'); + $this->assertTrue($fs->isJunction($target.'/../../junction'), $target.'/../../junction: is a junction'); + } + public function testCopy() { @mkdir($this->workingDir . '/foo/bar', 0777, true);