parent
1684f82a43
commit
39d9a5b6c5
|
@ -43,6 +43,9 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
{
|
{
|
||||||
$path = Filesystem::trimTrailingSlash($path);
|
$path = Filesystem::trimTrailingSlash($path);
|
||||||
$url = $package->getDistUrl();
|
$url = $package->getDistUrl();
|
||||||
|
if (null === $url) {
|
||||||
|
throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot download.');
|
||||||
|
}
|
||||||
$realUrl = realpath($url);
|
$realUrl = realpath($url);
|
||||||
if (false === $realUrl || !file_exists($realUrl) || !is_dir($realUrl)) {
|
if (false === $realUrl || !file_exists($realUrl) || !is_dir($realUrl)) {
|
||||||
throw new \RuntimeException(sprintf(
|
throw new \RuntimeException(sprintf(
|
||||||
|
@ -79,7 +82,13 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
{
|
{
|
||||||
$path = Filesystem::trimTrailingSlash($path);
|
$path = Filesystem::trimTrailingSlash($path);
|
||||||
$url = $package->getDistUrl();
|
$url = $package->getDistUrl();
|
||||||
|
if (null === $url) {
|
||||||
|
throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot install.');
|
||||||
|
}
|
||||||
$realUrl = realpath($url);
|
$realUrl = realpath($url);
|
||||||
|
if (false === $realUrl) {
|
||||||
|
throw new \RuntimeException('Failed to realpath '.$url);
|
||||||
|
}
|
||||||
|
|
||||||
if (realpath($path) === $realUrl) {
|
if (realpath($path) === $realUrl) {
|
||||||
if ($output) {
|
if ($output) {
|
||||||
|
@ -111,16 +120,16 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
}
|
}
|
||||||
$this->filesystem->junction($realUrl, $path);
|
$this->filesystem->junction($realUrl, $path);
|
||||||
} else {
|
} else {
|
||||||
$absolutePath = $path;
|
|
||||||
if (!$this->filesystem->isAbsolutePath($absolutePath)) {
|
|
||||||
$absolutePath = Platform::getCwd() . DIRECTORY_SEPARATOR . $path;
|
|
||||||
}
|
|
||||||
$shortestPath = $this->filesystem->findShortestPath($absolutePath, $realUrl);
|
|
||||||
$path = rtrim($path, "/");
|
$path = rtrim($path, "/");
|
||||||
if ($output) {
|
if ($output) {
|
||||||
$this->io->writeError(sprintf('Symlinking from %s', $url), false);
|
$this->io->writeError(sprintf('Symlinking from %s', $url), false);
|
||||||
}
|
}
|
||||||
if ($transportOptions['relative']) {
|
if ($transportOptions['relative'] === true) {
|
||||||
|
$absolutePath = $path;
|
||||||
|
if (!$this->filesystem->isAbsolutePath($absolutePath)) {
|
||||||
|
$absolutePath = Platform::getCwd() . DIRECTORY_SEPARATOR . $path;
|
||||||
|
}
|
||||||
|
$shortestPath = $this->filesystem->findShortestPath($absolutePath, $realUrl, false, true);
|
||||||
$symfonyFilesystem->symlink($shortestPath.'/', $path);
|
$symfonyFilesystem->symlink($shortestPath.'/', $path);
|
||||||
} else {
|
} else {
|
||||||
$symfonyFilesystem->symlink($realUrl.'/', $path);
|
$symfonyFilesystem->symlink($realUrl.'/', $path);
|
||||||
|
@ -185,13 +194,18 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
return \React\Promise\resolve(null);
|
return \React\Promise\resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$url = $package->getDistUrl();
|
||||||
|
if (null === $url) {
|
||||||
|
throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot remove.');
|
||||||
|
}
|
||||||
|
|
||||||
// ensure that the source path (dist url) is not the same as the install path, which
|
// ensure that the source path (dist url) is not the same as the install path, which
|
||||||
// can happen when using custom installers, see https://github.com/composer/composer/pull/9116
|
// can happen when using custom installers, see https://github.com/composer/composer/pull/9116
|
||||||
// not using realpath here as we do not want to resolve the symlink to the original dist url
|
// not using realpath here as we do not want to resolve the symlink to the original dist url
|
||||||
// it points to
|
// it points to
|
||||||
$fs = new Filesystem;
|
$fs = new Filesystem;
|
||||||
$absPath = $fs->isAbsolutePath($path) ? $path : Platform::getCwd() . '/' . $path;
|
$absPath = $fs->isAbsolutePath($path) ? $path : Platform::getCwd() . '/' . $path;
|
||||||
$absDistUrl = $fs->isAbsolutePath($package->getDistUrl()) ? $package->getDistUrl() : Platform::getCwd() . '/' . $package->getDistUrl();
|
$absDistUrl = $fs->isAbsolutePath($url) ? $url : Platform::getCwd() . '/' . $url;
|
||||||
if ($fs->normalizePath($absPath) === $fs->normalizePath($absDistUrl)) {
|
if ($fs->normalizePath($absPath) === $fs->normalizePath($absDistUrl)) {
|
||||||
if ($output) {
|
if ($output) {
|
||||||
$this->io->writeError(" - " . UninstallOperation::format($package).", source is still present in $path");
|
$this->io->writeError(" - " . UninstallOperation::format($package).", source is still present in $path");
|
||||||
|
@ -214,7 +228,8 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
$dumper = new ArrayDumper;
|
$dumper = new ArrayDumper;
|
||||||
|
|
||||||
$packageConfig = $dumper->dump($package);
|
$packageConfig = $dumper->dump($package);
|
||||||
if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) {
|
$packageVersion = $guesser->guessVersion($packageConfig, $path);
|
||||||
|
if ($packageVersion !== null) {
|
||||||
return $packageVersion['commit'];
|
return $packageVersion['commit'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +241,14 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
*/
|
*/
|
||||||
protected function getInstallOperationAppendix(PackageInterface $package, string $path): string
|
protected function getInstallOperationAppendix(PackageInterface $package, string $path): string
|
||||||
{
|
{
|
||||||
$realUrl = realpath($package->getDistUrl());
|
$url = $package->getDistUrl();
|
||||||
|
if (null === $url) {
|
||||||
|
throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot install.');
|
||||||
|
}
|
||||||
|
$realUrl = realpath($url);
|
||||||
|
if (false === $realUrl) {
|
||||||
|
throw new \RuntimeException('Failed to realpath '.$url);
|
||||||
|
}
|
||||||
|
|
||||||
if (realpath($path) === $realUrl) {
|
if (realpath($path) === $realUrl) {
|
||||||
return ': Source already present';
|
return ': Source already present';
|
||||||
|
@ -257,7 +279,7 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
||||||
$allowedStrategies = [self::STRATEGY_SYMLINK, self::STRATEGY_MIRROR];
|
$allowedStrategies = [self::STRATEGY_SYMLINK, self::STRATEGY_MIRROR];
|
||||||
|
|
||||||
$mirrorPathRepos = Platform::getEnv('COMPOSER_MIRROR_PATH_REPOS');
|
$mirrorPathRepos = Platform::getEnv('COMPOSER_MIRROR_PATH_REPOS');
|
||||||
if ($mirrorPathRepos) {
|
if ((bool) $mirrorPathRepos) {
|
||||||
$currentStrategy = self::STRATEGY_MIRROR;
|
$currentStrategy = self::STRATEGY_MIRROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -436,10 +436,11 @@ class Filesystem
|
||||||
* Returns the shortest path from $from to $to
|
* Returns the shortest path from $from to $to
|
||||||
*
|
*
|
||||||
* @param bool $directories if true, the source/target are considered to be directories
|
* @param bool $directories if true, the source/target are considered to be directories
|
||||||
|
* @param bool $preferRelative if true, relative paths will be preferred even if longer
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function findShortestPath(string $from, string $to, bool $directories = false)
|
public function findShortestPath(string $from, string $to, bool $directories = false, bool $preferRelative = false)
|
||||||
{
|
{
|
||||||
if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
|
if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
|
||||||
throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
|
throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
|
||||||
|
@ -471,7 +472,7 @@ class Filesystem
|
||||||
$commonPathCode = str_repeat('../', $sourcePathDepth);
|
$commonPathCode = str_repeat('../', $sourcePathDepth);
|
||||||
|
|
||||||
// allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups
|
// allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups
|
||||||
if ('/' === $commonPath && $sourcePathDepth > 1) {
|
if (!$preferRelative && '/' === $commonPath && $sourcePathDepth > 1) {
|
||||||
return $to;
|
return $to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,10 +488,11 @@ class Filesystem
|
||||||
* Returns PHP code that, when executed in $from, will return the path to $to
|
* Returns PHP code that, when executed in $from, will return the path to $to
|
||||||
*
|
*
|
||||||
* @param bool $directories if true, the source/target are considered to be directories
|
* @param bool $directories if true, the source/target are considered to be directories
|
||||||
|
* @param bool $preferRelative if true, relative paths will be preferred even if longer
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function findShortestPathCode(string $from, string $to, bool $directories = false, bool $staticCode = false)
|
public function findShortestPathCode(string $from, string $to, bool $directories = false, bool $staticCode = false, bool $preferRelative = false)
|
||||||
{
|
{
|
||||||
if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
|
if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
|
||||||
throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
|
throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
|
||||||
|
@ -520,7 +522,7 @@ class Filesystem
|
||||||
$sourcePathDepth = substr_count((string) substr($from, \strlen($commonPath)), '/') + (int) $directories;
|
$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
|
// allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups
|
||||||
if ('/' === $commonPath && $sourcePathDepth > 1) {
|
if (!$preferRelative && '/' === $commonPath && $sourcePathDepth > 1) {
|
||||||
return var_export($to, true);
|
return var_export($to, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,10 +54,10 @@ class FilesystemTest extends TestCase
|
||||||
/**
|
/**
|
||||||
* @dataProvider providePathCouplesAsCode
|
* @dataProvider providePathCouplesAsCode
|
||||||
*/
|
*/
|
||||||
public function testFindShortestPathCode(string $a, string $b, bool $directory, string $expected, bool $static = false): void
|
public function testFindShortestPathCode(string $a, string $b, bool $directory, string $expected, bool $static = false, bool $preferRelative = false): void
|
||||||
{
|
{
|
||||||
$fs = new Filesystem;
|
$fs = new Filesystem;
|
||||||
self::assertEquals($expected, $fs->findShortestPathCode($a, $b, $directory, $static));
|
self::assertEquals($expected, $fs->findShortestPathCode($a, $b, $directory, $static, $preferRelative));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function providePathCouplesAsCode(): array
|
public static function providePathCouplesAsCode(): array
|
||||||
|
@ -77,6 +77,7 @@ class FilesystemTest extends TestCase
|
||||||
['/foo/bar', '/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', '/foo/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"],
|
||||||
['/foo/bin/run', '/bar/bin/run', true, "'/bar/bin/run'"],
|
['/foo/bin/run', '/bar/bin/run', true, "'/bar/bin/run'"],
|
||||||
|
['/app/vendor/foo/bar', '/lib', true, "dirname(dirname(dirname(dirname(__DIR__)))).'/lib'", false, true],
|
||||||
['/bin/run', '/bin/run', true, "__DIR__"],
|
['/bin/run', '/bin/run', true, "__DIR__"],
|
||||||
['c:/bin/run', 'C:\\bin/run', true, "__DIR__"],
|
['c:/bin/run', 'C:\\bin/run', true, "__DIR__"],
|
||||||
['c:/bin/run', 'c:/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"],
|
['c:/bin/run', 'c:/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"],
|
||||||
|
@ -113,10 +114,10 @@ class FilesystemTest extends TestCase
|
||||||
/**
|
/**
|
||||||
* @dataProvider providePathCouples
|
* @dataProvider providePathCouples
|
||||||
*/
|
*/
|
||||||
public function testFindShortestPath(string $a, string $b, string $expected, bool $directory = false): void
|
public function testFindShortestPath(string $a, string $b, string $expected, bool $directory = false, bool $preferRelative = false): void
|
||||||
{
|
{
|
||||||
$fs = new Filesystem;
|
$fs = new Filesystem;
|
||||||
self::assertEquals($expected, $fs->findShortestPath($a, $b, $directory));
|
self::assertEquals($expected, $fs->findShortestPath($a, $b, $directory, $preferRelative));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function providePathCouples(): array
|
public static function providePathCouples(): array
|
||||||
|
@ -152,6 +153,7 @@ class FilesystemTest extends TestCase
|
||||||
['C:/Temp', 'c:\Temp\..\..\test', "../test", true],
|
['C:/Temp', 'c:\Temp\..\..\test', "../test", true],
|
||||||
['C:/Temp/../..', 'c:\Temp\..\..\test', "./test", true],
|
['C:/Temp/../..', 'c:\Temp\..\..\test', "./test", true],
|
||||||
['C:/Temp/../..', 'D:\Temp\..\..\test', "D:/test", true],
|
['C:/Temp/../..', 'D:\Temp\..\..\test', "D:/test", true],
|
||||||
|
['/app/vendor/foo/bar', '/lib', '../../../../lib', true, true],
|
||||||
['/tmp', '/tmp/../../test', '../test', true],
|
['/tmp', '/tmp/../../test', '../test', true],
|
||||||
['/tmp', '/test', '../test', true],
|
['/tmp', '/test', '../test', true],
|
||||||
['/foo/bar', '/foo/bar_vendor', '../bar_vendor', true],
|
['/foo/bar', '/foo/bar_vendor', '../bar_vendor', true],
|
||||||
|
|
Loading…
Reference in New Issue