diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index d9f55261b..5bbc5a04e 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -440,7 +440,8 @@ class Filesystem $commonPath = strtr(\dirname($commonPath), '\\', '/'); } - if (0 !== strpos($from, $commonPath) || '/' === $commonPath) { + // no commonality at all + if (0 !== strpos($from, $commonPath)) { return $to; } @@ -448,6 +449,11 @@ class Filesystem $sourcePathDepth = substr_count((string) substr($from, \strlen($commonPath)), '/'); $commonPathCode = str_repeat('../', $sourcePathDepth); + // allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups + if ('/' === $commonPath && $sourcePathDepth > 1) { + return $to; + } + $result = $commonPathCode . substr($to, \strlen($commonPath)); if (\strlen($result) === 0) { return './'; @@ -481,15 +487,22 @@ class Filesystem $commonPath = strtr(\dirname($commonPath), '\\', '/'); } - if (0 !== strpos($from, $commonPath) || '/' === $commonPath || '.' === $commonPath) { + // no commonality at all + if (0 !== strpos($from, $commonPath) || '.' === $commonPath) { return var_export($to, true); } $commonPath = rtrim($commonPath, '/') . '/'; - if (strpos($to, $from.'/') === 0) { + if (str_starts_with($to, $from.'/')) { return '__DIR__ . '.var_export((string) substr($to, \strlen($from)), true); } $sourcePathDepth = substr_count((string) substr($from, \strlen($commonPath)), '/') + (int) $directories; + + // allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups + if ('/' === $commonPath && $sourcePathDepth > 1) { + return var_export($to, true); + } + if ($staticCode) { $commonPathCode = "__DIR__ . '".str_repeat('/..', $sourcePathDepth)."'"; } else { diff --git a/tests/Composer/Test/Util/FilesystemTest.php b/tests/Composer/Test/Util/FilesystemTest.php index c738c8e68..e667161cf 100644 --- a/tests/Composer/Test/Util/FilesystemTest.php +++ b/tests/Composer/Test/Util/FilesystemTest.php @@ -72,6 +72,7 @@ class FilesystemTest extends TestCase ['c:\\bin\\run', 'd:/vendor/acme/bin/run', false, "'D:/vendor/acme/bin/run'"], ['/foo/bar', '/foo/bar', true, "__DIR__"], ['/foo/bar/', '/foo/bar', true, "__DIR__"], + ['/foo', '/baz', true, "dirname(__DIR__).'/baz'"], ['/foo/bar', '/foo/baz', true, "dirname(__DIR__).'/baz'"], ['/foo/bin/run', '/foo/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"], ['/foo/bin/run', '/bar/bin/run', true, "'/bar/bin/run'"], @@ -150,7 +151,8 @@ class FilesystemTest extends TestCase ['C:/Temp', 'c:\Temp\..\..\test', "../test", true], ['C:/Temp/../..', 'c:\Temp\..\..\test', "./test", true], ['C:/Temp/../..', 'D:\Temp\..\..\test', "D:/test", true], - ['/tmp', '/tmp/../../test', '/test', true], + ['/tmp', '/tmp/../../test', '../test', true], + ['/tmp', '/test', '../test', true], ['/foo/bar', '/foo/bar_vendor', '../bar_vendor', true], ['/foo/bar_vendor', '/foo/bar', '../bar', true], ['/foo/bar_vendor', '/foo/bar/src', '../bar/src', true],