1
0
Fork 0

Fix newly surfaced errors

pull/10635/head
Jordi Boggiano 2022-04-28 21:20:40 +02:00
parent 6fdd9494ef
commit bd6403a6be
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
20 changed files with 115 additions and 109 deletions

View File

@ -289,7 +289,7 @@
"properties": {
"platform": {
"type": "object",
"description": "This is an object of package name (keys) and version (values) that will be used to mock the platform packages on this machine.",
"description": "This is an object of package name (keys) and version (values) that will be used to mock the platform packages on this machine, the version can be set to false to make it appear like the package is not present.",
"additionalProperties": {
"type": ["string", "boolean"]
}
@ -347,9 +347,20 @@
},
"gitlab-token": {
"type": "object",
"description": "An object of domain name => gitlab private tokens, typically {\"gitlab.com\":\"<token>\"}.",
"description": "An object of domain name => gitlab private tokens, typically {\"gitlab.com\":\"<token>\"}, or an object with username and token keys.",
"additionalProperties": {
"type": "string"
"type": ["string", "object"],
"required": ["username", "token"],
"properties": {
"username": {
"type": "string",
"description": "The username used for GitLab authentication"
},
"token": {
"type": "string",
"description": "The token used for GitLab authentication"
}
}
}
},
"gitlab-protocol": {
@ -512,6 +523,14 @@
"consumer-secret": {
"type": "string",
"description": "The consumer-secret used for OAuth authentication"
},
"access-token": {
"type": "string",
"description": "The OAuth token retrieved from Bitbucket's API, this is written by Composer and you should not set it nor modify it."
},
"access-token-expiration": {
"type": "integer",
"description": "The generated token's expiration timestamp, this is written by Composer and you should not set it nor modify it."
}
}
}

View File

@ -202,7 +202,7 @@ class AutoloadGenerator
// See https://bugs.php.net/bug.php?id=72738
$basePath = $filesystem->normalizePath(realpath(realpath(Platform::getCwd())));
$vendorPath = $filesystem->normalizePath(realpath(realpath($config->get('vendor-dir'))));
$useGlobalIncludePath = (bool) $config->get('use-include-path');
$useGlobalIncludePath = $config->get('use-include-path');
$prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true';
$targetDir = $vendorPath.'/'.$targetDir;
$filesystem->ensureDirectoryExists($targetDir);
@ -408,7 +408,7 @@ EOF;
unlink($includeFilesFilePath);
}
$filesystem->filePutContentsIfModified($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath));
$checkPlatform = $config->get('platform-check') && !($this->platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter);
$checkPlatform = $config->get('platform-check') !== false && !($this->platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter);
$platformCheckContent = null;
if ($checkPlatform) {
$platformCheckContent = $this->getPlatformCheck($packageMap, $config->get('platform-check'), $devPackageNames);
@ -429,7 +429,7 @@ EOF;
if ($this->runScripts) {
$this->eventDispatcher->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP, $this->devMode, array(), array(
'optimize' => (bool) $scanPsrPackages,
'optimize' => $scanPsrPackages,
));
}

View File

@ -114,7 +114,7 @@ EOT
$this->outputResult($this->checkHttpProxy());
}
if ($oauth = $config->get('github-oauth')) {
if (count($oauth = $config->get('github-oauth')) > 0) {
foreach ($oauth as $domain => $token) {
$io->write('Checking '.$domain.' oauth access: ', false);
$this->outputResult($this->checkGithubOauth($domain, $token));

View File

@ -237,7 +237,7 @@ EOT
$allowPlugins = $composer->getConfig()->get('allow-plugins');
$removedPlugins = is_array($allowPlugins) ? array_intersect(array_keys($allowPlugins), $packages) : [];
if (!$dryRun && count($removedPlugins) > 0) {
if (!$dryRun && is_array($allowPlugins) && count($removedPlugins) > 0) {
if (count($allowPlugins) === count($removedPlugins)) {
$json->removeConfigSetting('allow-plugins');
} else {

View File

@ -301,6 +301,10 @@ class Config
$this->setSourceOfConfigValue($val, $key, $env);
}
if ($key === 'process-timeout') {
return max(0, false !== $val ? (int) $val : $this->config[$key]);
}
$val = rtrim((string) $this->process(false !== $val ? $val : $this->config[$key], $flags), '/\\');
$val = Platform::expandPath($val);
@ -339,7 +343,7 @@ class Config
// ints without env var support
case 'cache-ttl':
return (int) $this->config[$key];
return max(0, (int) $this->config[$key]);
// numbers with kb/mb/gb support, without env var support
case 'cache-files-maxsize':
@ -348,7 +352,7 @@ class Config
"Could not parse the value of '$key': {$this->config[$key]}"
);
}
$size = $matches[1];
$size = (float) $matches[1];
if (isset($matches[2])) {
switch (strtolower($matches[2])) {
case 'g':
@ -365,15 +369,15 @@ class Config
}
}
return $size;
return max(0, (int) $size);
// special cases below
case 'cache-files-ttl':
if (isset($this->config[$key])) {
return (int) $this->config[$key];
return max(0, (int) $this->config[$key]);
}
return (int) $this->config['cache-ttl'];
return $this->get('cache-ttl');
case 'home':
return rtrim($this->process(Platform::expandPath($this->config[$key]), $flags), '/\\');

View File

@ -94,7 +94,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
if ($this->cache && $this->cache->gcIsNecessary()) {
$this->io->writeError('Running cache garbage collection', true, IOInterface::VERY_VERBOSE);
$this->cache->gc((int) $config->get('cache-files-ttl'), (int) $config->get('cache-files-maxsize'));
$this->cache->gc($config->get('cache-files-ttl'), $config->get('cache-files-maxsize'));
}
}

View File

@ -190,7 +190,7 @@ class Factory
}
$config->setConfigSource(new JsonConfigSource($file));
$htaccessProtect = (bool) $config->get('htaccess-protect');
$htaccessProtect = $config->get('htaccess-protect');
if ($htaccessProtect) {
// Protect directory against web access. Since HOME could be
// the www-data's user home and be web-accessible it is a
@ -645,10 +645,10 @@ class Factory
}
$httpDownloaderOptions = array();
if ($disableTls === false) {
if ($config->get('cafile')) {
if ('' !== $config->get('cafile')) {
$httpDownloaderOptions['ssl']['cafile'] = $config->get('cafile');
}
if ($config->get('capath')) {
if ('' !== $config->get('capath')) {
$httpDownloaderOptions['ssl']['capath'] = $config->get('capath');
}
$httpDownloaderOptions = array_replace_recursive($httpDownloaderOptions, $options);

View File

@ -141,8 +141,8 @@ abstract class BaseIO implements IOInterface
}
foreach ($gitlabToken as $domain => $token) {
$username = is_array($token) && array_key_exists("username", $token) ? $token["username"] : $token;
$password = is_array($token) && array_key_exists("token", $token) ? $token["token"] : 'private-token';
$username = is_array($token) ? $token["username"] : $token;
$password = is_array($token) ? $token["token"] : 'private-token';
$this->checkAndSetAuthentication($domain, $username, $password);
}
@ -156,7 +156,7 @@ abstract class BaseIO implements IOInterface
}
// setup process timeout
ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
ProcessExecutor::setTimeout($config->get('process-timeout'));
}
public function emergency($message, array $context = array()): void

View File

@ -11,6 +11,7 @@ use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\IntegerRangeType;
@ -29,7 +30,10 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio
public function __construct()
{
$schema = JsonFile::parseJson(file_get_contents(__DIR__.'/../../../res/composer-schema.json'));
$schema = JsonFile::parseJson((string) file_get_contents(__DIR__.'/../../../res/composer-schema.json'));
/**
* @var string $prop
*/
foreach ($schema['properties']['config']['properties'] as $prop => $conf) {
$type = $this->parseType($conf, $prop);
@ -66,7 +70,7 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio
}
/**
* @param array<mixed> $types
* @param array<mixed> $def
*/
private function parseType(array $def, string $path): Type
{
@ -75,15 +79,17 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio
foreach ((array) $def['type'] as $type) {
switch ($type) {
case 'integer':
if (in_array($path, ['process-timeout', 'cache-ttl', 'cache-files-ttl'], true)) {
$types[] = IntegerRangeType::createAllGreaterThan(0);
if (in_array($path, ['process-timeout', 'cache-ttl', 'cache-files-ttl', 'cache-files-maxsize'], true)) {
$types[] = IntegerRangeType::createAllGreaterThanOrEqualTo(0);
} else {
$types[] = new IntegerType();
}
break;
case 'string':
if ($path === 'discard-changes') {
if ($path === 'cache-files-maxsize') {
// passthru, skip as it is always converted to int
} elseif ($path === 'discard-changes') {
$types[] = new ConstantStringType('stash');
} elseif ($path === 'use-parent-dir') {
$types[] = new ConstantStringType('prompt');
@ -101,7 +107,11 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio
break;
case 'boolean':
$types[] = new BooleanType();
if ($path === 'platform.additionalProperties') {
$types[] = new ConstantBooleanType(false);
} else {
$types[] = new BooleanType();
}
break;
case 'object':
@ -116,7 +126,7 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio
foreach ($def['properties'] as $propName => $propdef) {
$keyNames[] = new ConstantStringType($propName);
$valType = $this->parseType($propdef, $path.'.'.$propName);
if (!isset($def['required']) || !in_array($propName, $def['required'])) {
if (!isset($def['required']) || !in_array($propName, $def['required'], true)) {
$valType = TypeCombinator::addNull($valType);
}
$valTypes[] = $valType;
@ -146,16 +156,16 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio
$types[] = new MixedType();
}
}
$type = TypeCombinator::union(...$types);
} elseif (isset($def['enum'])) {
$types[] = TypeCombinator::union(...array_map(function (string $value): ConstantStringType {
$type = TypeCombinator::union(...array_map(function (string $value): ConstantStringType {
return new ConstantStringType($value);
}, $def['enum']));
} else {
$types = [new MixedType()];
$type = new MixedType();
}
$type = \count($types) === 1 ? $types[0] : TypeCombinator::union(...$types);
// allow-plugins defaults to null until July 1st 2022 for some BC hackery, but after that it is not nullable anymore
if ($path === 'allow-plugins' && time() < strtotime('2022-07-01')) {
$type = TypeCombinator::addNull($type);

View File

@ -337,17 +337,17 @@ class Locker
/**
* Locks provided data into lockfile.
*
* @param PackageInterface[] $packages array of packages
* @param PackageInterface[]|null $devPackages array of dev packages or null if installed without --dev
* @param array<string, string> $platformReqs array of package name => constraint for required platform packages
* @param array<string, string> $platformDevReqs array of package name => constraint for dev-required platform packages
* @param string[][] $aliases array of aliases
* @param string $minimumStability
* @param array<string, int> $stabilityFlags
* @param bool $preferStable
* @param bool $preferLowest
* @param array<string, string> $platformOverrides
* @param bool $write Whether to actually write data to disk, useful in tests and for --dry-run
* @param PackageInterface[] $packages array of packages
* @param PackageInterface[]|null $devPackages array of dev packages or null if installed without --dev
* @param array<string, string> $platformReqs array of package name => constraint for required platform packages
* @param array<string, string> $platformDevReqs array of package name => constraint for dev-required platform packages
* @param string[][] $aliases array of aliases
* @param string $minimumStability
* @param array<string, int> $stabilityFlags
* @param bool $preferStable
* @param bool $preferLowest
* @param array<string, string|false> $platformOverrides
* @param bool $write Whether to actually write data to disk, useful in tests and for --dry-run
*
* @return bool
*
@ -386,7 +386,7 @@ class Locker
$lock['platform'] = $platformReqs;
$lock['platform-dev'] = $platformDevReqs;
if ($platformOverrides) {
if (\count($platformOverrides) > 0) {
$lock['platform-overrides'] = $platformOverrides;
}
$lock['plugin-api-version'] = PluginInterface::PLUGIN_API_VERSION;

View File

@ -51,7 +51,7 @@ class FossilDriver extends VcsDriver
if (Filesystem::isLocalPath($this->url) && is_dir($this->url)) {
$this->checkoutDir = $this->url;
} else {
if (!Cache::isUsable((string) $this->config->get('cache-repo-dir')) || !Cache::isUsable((string) $this->config->get('cache-vcs-dir'))) {
if (!Cache::isUsable($this->config->get('cache-repo-dir')) || !Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled');
}

View File

@ -49,7 +49,7 @@ class GitDriver extends VcsDriver
$this->repoDir = $this->url;
$cacheUrl = realpath($this->url);
} else {
if (!Cache::isUsable((string) $this->config->get('cache-vcs-dir'))) {
if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled');
}

View File

@ -111,7 +111,7 @@ class GitLabDriver extends VcsDriver
}
$this->originUrl = $origin;
if ($protocol = $this->config->get('gitlab-protocol')) {
if (is_string($protocol = $this->config->get('gitlab-protocol'))) {
// https treated as a synonym for http.
if (!in_array($protocol, array('git', 'http', 'https'))) {
throw new \RuntimeException('gitlab-protocol must be one of git, http.');
@ -582,7 +582,7 @@ class GitLabDriver extends VcsDriver
$guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2'];
$urlParts = explode('/', $match['parts']);
if (false === self::determineOrigin((array) $config->get('gitlab-domains'), $guessedDomain, $urlParts, $match['port'])) {
if (false === self::determineOrigin($config->get('gitlab-domains'), $guessedDomain, $urlParts, $match['port'])) {
return false;
}

View File

@ -42,7 +42,7 @@ class HgDriver extends VcsDriver
if (Filesystem::isLocalPath($this->url)) {
$this->repoDir = $this->url;
} else {
if (!Cache::isUsable((string) $this->config->get('cache-vcs-dir'))) {
if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('HgDriver requires a usable cache directory, and it looks like you set it to be disabled');
}

View File

@ -62,7 +62,7 @@ class PerforceDriver extends VcsDriver
return;
}
if (!Cache::isUsable((string) $this->config->get('cache-vcs-dir'))) {
if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('PerforceDriver requires a usable cache directory, and it looks like you set it to be disabled');
}

View File

@ -74,9 +74,6 @@ class Git
}
$protocols = $this->config->get('github-protocols');
if (!is_array($protocols)) {
throw new \RuntimeException('Config value "github-protocols" must be an array, got ' . gettype($protocols));
}
// public github, autoswitch protocols
if (Preg::isMatch('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) {
$messages = array();

View File

@ -90,8 +90,8 @@ class GitLab
}
if (isset($token)) {
$username = is_array($token) && array_key_exists("username", $token) ? $token["username"] : $token;
$password = is_array($token) && array_key_exists("token", $token) ? $token["token"] : 'private-token';
$username = is_array($token) ? $token["username"] : $token;
$password = is_array($token) ? $token["token"] : 'private-token';
$this->io->setAuthentication($originUrl, $username, $password);
return true;

View File

@ -90,9 +90,8 @@ class Url
// Gitlab can be installed in a non-root context (i.e. gitlab.com/foo). When downloading archives the originUrl
// is the host without the path, so we look for the registered gitlab-domains matching the host here
if (
is_array($config->get('gitlab-domains'))
&& false === strpos($origin, '/')
&& !in_array($origin, $config->get('gitlab-domains'))
false === strpos($origin, '/')
&& !in_array($origin, $config->get('gitlab-domains'), true)
) {
foreach ($config->get('gitlab-domains') as $gitlabDomain) {
if (0 === strpos($gitlabDomain, $origin)) {

View File

@ -104,6 +104,9 @@ class AutoloadGeneratorTest extends TestCase
'platform-check' => function (): bool {
return true;
},
'use-include-path' => function (): bool {
return false;
},
);
$this->config->expects($this->atLeastOnce())

View File

@ -14,33 +14,26 @@ namespace Composer\Test\Repository;
use Composer\Repository\PathRepository;
use Composer\Test\TestCase;
use Composer\Util\HttpDownloader;
use Composer\Util\Loop;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
class PathRepositoryTest extends TestCase
{
public function testLoadPackageFromFileSystemWithIncorrectPath(): void
{
self::expectException('RuntimeException');
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'missing'));
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl));
$repository->getPackages();
}
public function testLoadPackageFromFileSystemWithVersion(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$versionGuesser = null;
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'with-version'));
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl));
$repository->getPackages();
$this->assertSame(1, $repository->count());
@ -49,14 +42,8 @@ class PathRepositoryTest extends TestCase
public function testLoadPackageFromFileSystemWithoutVersion(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$versionGuesser = null;
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'without-version'));
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl));
$packages = $repository->getPackages();
$this->assertGreaterThanOrEqual(1, $repository->count());
@ -70,14 +57,8 @@ class PathRepositoryTest extends TestCase
public function testLoadPackageFromFileSystemWithWildcard(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$versionGuesser = null;
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl));
$packages = $repository->getPackages();
$names = array();
@ -95,12 +76,6 @@ class PathRepositoryTest extends TestCase
public function testLoadPackageWithExplicitVersions(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$versionGuesser = null;
$options = array(
'versions' => array(
'test/path-unversioned' => '4.3.2.1',
@ -108,7 +83,7 @@ class PathRepositoryTest extends TestCase
),
);
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
$repository = new PathRepository(array('url' => $repositoryUrl, 'options' => $options), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl, 'options' => $options));
$packages = $repository->getPackages();
$versions = array();
@ -130,12 +105,6 @@ class PathRepositoryTest extends TestCase
*/
public function testUrlRemainsRelative(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$versionGuesser = null;
// realpath() does not fully expand the paths
// PHP Bug https://bugs.php.net/bug.php?id=72642
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(realpath(realpath(__DIR__)), 'Fixtures', 'path', 'with-version'));
@ -143,7 +112,7 @@ class PathRepositoryTest extends TestCase
// PHP Bug https://bugs.php.net/bug.php?id=73797
$relativeUrl = ltrim(substr($repositoryUrl, strlen(realpath(realpath(Platform::getCwd())))), DIRECTORY_SEPARATOR);
$repository = new PathRepository(array('url' => $relativeUrl), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $relativeUrl));
$packages = $repository->getPackages();
$this->assertSame(1, $repository->count());
@ -158,16 +127,11 @@ class PathRepositoryTest extends TestCase
public function testReferenceNone(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$options = array(
'reference' => 'none',
);
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
$repository = new PathRepository(array('url' => $repositoryUrl, 'options' => $options), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl, 'options' => $options));
$packages = $repository->getPackages();
$this->assertGreaterThanOrEqual(2, $repository->count());
@ -179,17 +143,12 @@ class PathRepositoryTest extends TestCase
public function testReferenceConfig(): void
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$options = array(
'reference' => 'config',
'relative' => true,
);
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
$repository = new PathRepository(array('url' => $repositoryUrl, 'options' => $options), $ioInterface, $config);
$repository = $this->createPathRepo(array('url' => $repositoryUrl, 'options' => $options));
$packages = $repository->getPackages();
$this->assertGreaterThanOrEqual(2, $repository->count());
@ -201,4 +160,19 @@ class PathRepositoryTest extends TestCase
);
}
}
/**
* @param array<mixed> $options
*/
private function createPathRepo(array $options): PathRepository
{
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$config = new \Composer\Config();
$proc = new ProcessExecutor();
$loop = new Loop(new HttpDownloader($io, $config), $proc);
return new PathRepository($options, $io, $config, null, null, $proc);
}
}