1
0
Fork 0

Add types to `Util` namespace, refs #10159 (#10190)

pull/10198/head
Martin Herndl 2021-10-19 14:35:37 +02:00 committed by GitHub
parent 261d93aacf
commit 995bf5a932
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 402 additions and 32 deletions

View File

@ -469,7 +469,7 @@ class GitHubDriver extends VcsDriver
}
}
$rateLimited = $gitHubUtil->isRateLimited($e->getHeaders());
$rateLimited = $gitHubUtil->isRateLimited((array) $e->getHeaders());
if (!$this->io->hasAuthentication($this->originUrl)) {
if (!$this->io->isInteractive()) {
@ -575,7 +575,7 @@ class GitHubDriver extends VcsDriver
protected function getNextPage(Response $response)
{
$header = $response->getHeader('link');
if (!$header) {
return;
}

View File

@ -37,6 +37,8 @@ class AuthHelper
/**
* @param string $origin
* @param string|bool $storeAuth
*
* @return void
*/
public function storeAuth($origin, $storeAuth)
{
@ -192,10 +194,11 @@ class AuthHelper
}
/**
* @param array $headers
* @param string $origin
* @param string $url
* @return array updated headers array
* @param string[] $headers
* @param string $origin
* @param string $url
*
* @return string[] updated headers array
*/
public function addAuthenticationHeader(array $headers, $origin, $url)
{

View File

@ -211,16 +211,17 @@ class Bitbucket
throw new \LogicException('Failed to initialize token above');
}
// side effect above caused this, https://github.com/phpstan/phpstan/issues/5129
// @phpstan-ignore-next-line
return $this->token['access_token'];
}
/**
* Store the new/updated credentials to the configuration
*
* @param string $originUrl
* @param string $consumerKey
* @param string $consumerSecret
*
* @return void
*/
private function storeInAuthConfig($originUrl, $consumerKey, $consumerSecret)
{

View File

@ -19,6 +19,16 @@ namespace Composer\Util;
*/
class ComposerMirror
{
/**
* @param string $mirrorUrl
* @param string $packageName
* @param string $version
* @param string|null $reference
* @param string|null $type
* @param string|null $prettyVersion
*
* @return string
*/
public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type, $prettyVersion = null)
{
if ($reference) {
@ -36,6 +46,14 @@ class ComposerMirror
return str_replace($from, $to, $mirrorUrl);
}
/**
* @param string $mirrorUrl
* @param string $packageName
* @param string $url
* @param string|null $type
*
* @return string
*/
public static function processGitUrl($mirrorUrl, $packageName, $url, $type)
{
if (preg_match('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) {
@ -53,6 +71,14 @@ class ComposerMirror
);
}
/**
* @param string $mirrorUrl
* @param string $packageName
* @param string $url
* @param string $type
*
* @return string
*/
public static function processHgUrl($mirrorUrl, $packageName, $url, $type)
{
return self::processGitUrl($mirrorUrl, $packageName, $url, $type);

View File

@ -45,7 +45,7 @@ class ConfigValidator
* @param int $arrayLoaderValidationFlags Flags for ArrayLoader validation
* @param int $flags Flags for validation
*
* @return array a triple containing the errors, publishable errors, and warnings
* @return array{list<string>, list<string>, list<string>} a triple containing the errors, publishable errors, and warnings
*/
public function validate($file, $arrayLoaderValidationFlags = ValidatingArrayLoader::CHECK_ALL, $flags = self::CHECK_VERSION)
{

View File

@ -82,6 +82,8 @@ class ErrorHandler
* Register error handler.
*
* @param IOInterface|null $io
*
* @return void
*/
public static function register(IOInterface $io = null)
{

View File

@ -32,6 +32,11 @@ class Filesystem
$this->processExecutor = $executor;
}
/**
* @param string $file
*
* @return bool
*/
public function remove($file)
{
if (is_dir($file)) {
@ -62,6 +67,12 @@ class Filesystem
return \count($finder) === 0;
}
/**
* @param string $dir
* @param bool $ensureDirectoryExists
*
* @return void
*/
public function emptyDirectory($dir, $ensureDirectoryExists = true)
{
if (is_link($dir) && file_exists($dir)) {
@ -163,6 +174,7 @@ class Filesystem
/**
* @param string $directory
* @param bool $fallbackToPhp
*
* @return bool|null Returns null, when no edge case was hit. Otherwise a bool whether removal was successfull
*/
@ -240,6 +252,11 @@ class Filesystem
return $this->rmdir($directory);
}
/**
* @param string $directory
*
* @return void
*/
public function ensureDirectoryExists($directory)
{
if (!is_dir($directory)) {
@ -326,6 +343,8 @@ class Filesystem
*
* @param string $source
* @param string $target
*
* @return void
*/
public function copyThenRemove($source, $target)
{
@ -370,6 +389,12 @@ class Filesystem
return $result;
}
/**
* @param string $source
* @param string $target
*
* @return void
*/
public function rename($source, $target)
{
if (true === @rename($source, $target)) {
@ -605,13 +630,18 @@ class Filesystem
return (bool) preg_match('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path);
}
/**
* @param string $path
*
* @return string
*/
public static function getPlatformPath($path)
{
if (Platform::isWindows()) {
$path = preg_replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path);
}
return preg_replace('{^file://}i', '', $path);
return (string) preg_replace('{^file://}i', '', $path);
}
/**
@ -641,6 +671,11 @@ class Filesystem
return false;
}
/**
* @param string $directory
*
* @return int
*/
protected function directorySize($directory)
{
$it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
@ -767,6 +802,8 @@ class Filesystem
*
* @param string $target
* @param string $junction
*
* @return void
*/
public function junction($target, $junction)
{
@ -845,6 +882,12 @@ class Filesystem
return $this->rmdir($junction);
}
/**
* @param string $path
* @param string $content
*
* @return int|false
*/
public function filePutContentsIfModified($path, $content)
{
$currentContent = @file_get_contents($path);
@ -860,6 +903,8 @@ class Filesystem
*
* @param string $source
* @param string $target
*
* @return void
*/
public function safeCopy($source, $target)
{
@ -876,6 +921,11 @@ class Filesystem
/**
* compare 2 files
* https://stackoverflow.com/questions/3060125/can-i-use-file-get-contents-to-compare-two-files
*
* @param string $a
* @param string $b
*
* @return bool
*/
private function filesAreEqual($a, $b)
{

View File

@ -40,6 +40,14 @@ class Git
$this->filesystem = $fs;
}
/**
* @param callable $commandCallable
* @param string $url
* @param string|null $cwd
* @param bool $initialClone
*
* @return void
*/
public function runCommand($commandCallable, $url, $cwd, $initialClone = false)
{
// Ensure we are allowed to use this URL by config
@ -257,6 +265,12 @@ class Git
}
}
/**
* @param string $url
* @param string $dir
*
* @return bool
*/
public function syncMirror($url, $dir)
{
if (getenv('COMPOSER_DISABLE_NETWORK') && getenv('COMPOSER_DISABLE_NETWORK') !== 'prime') {
@ -295,6 +309,13 @@ class Git
return true;
}
/**
* @param string $url
* @param string $dir
* @param string $ref
*
* @return bool
*/
public function fetchRefOrSyncMirror($url, $dir, $ref)
{
if ($this->checkRefIsInMirror($dir, $ref)) {
@ -308,6 +329,9 @@ class Git
return false;
}
/**
* @return string
*/
public static function getNoShowSignatureFlag(ProcessExecutor $process)
{
$gitVersion = self::getVersion($process);
@ -318,6 +342,12 @@ class Git
return '';
}
/**
* @param string $dir
* @param string $ref
*
* @return bool
*/
private function checkRefIsInMirror($dir, $ref)
{
if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
@ -331,6 +361,12 @@ class Git
return false;
}
/**
* @param string $url
* @param string[] $match
*
* @return bool
*/
private function isAuthenticationFailure($url, &$match)
{
if (!preg_match('{^(https?://)([^/]+)(.*)$}i', $url, $match)) {
@ -355,6 +391,9 @@ class Git
return false;
}
/**
* @return void
*/
public static function cleanEnv()
{
if (PHP_VERSION_ID < 50400 && ini_get('safe_mode') && false === strpos(ini_get('safe_mode_allowed_env_vars'), 'GIT_ASKPASS')) {
@ -383,16 +422,28 @@ class Git
Platform::clearEnv('DYLD_LIBRARY_PATH');
}
/**
* @return non-empty-string
*/
public static function getGitHubDomainsRegex(Config $config)
{
return '(' . implode('|', array_map('preg_quote', $config->get('github-domains'))) . ')';
}
/**
* @return non-empty-string
*/
public static function getGitLabDomainsRegex(Config $config)
{
return '(' . implode('|', array_map('preg_quote', $config->get('gitlab-domains'))) . ')';
}
/**
* @param non-empty-string $message
* @param string $url
*
* @return never
*/
private function throwException($message, $url)
{
// git might delete a directory when it fails and php will not know

View File

@ -132,11 +132,11 @@ class GitHub
}
/**
* Extract ratelimit from response.
* Extract rate limit from response.
*
* @param array $headers Headers from Composer\Downloader\TransportException.
* @param string[] $headers Headers from Composer\Downloader\TransportException.
*
* @return array Associative array with the keys limit and reset.
* @return array{limit: int|'?', reset: string}
*/
public function getRateLimit(array $headers)
{
@ -167,7 +167,7 @@ class GitHub
/**
* Finds whether a request failed due to rate limiting
*
* @param array $headers Headers from Composer\Downloader\TransportException.
* @param string[] $headers Headers from Composer\Downloader\TransportException.
*
* @return bool
*/

View File

@ -160,6 +160,14 @@ class GitLab
throw new \RuntimeException('Invalid GitLab credentials 5 times in a row, aborting.');
}
/**
* @param string $scheme
* @param string $originUrl
*
* @return array{access_token: non-empty-string, token_type: non-empty-string, expires_in: positive-int}
*
* @see https://docs.gitlab.com/ee/api/oauth2.html#resource-owner-password-credentials-flow
*/
private function createToken($scheme, $originUrl)
{
$username = $this->io->ask('Username: ');

View File

@ -45,6 +45,13 @@ class Hg
$this->process = $process;
}
/**
* @param callable $commandCallable
* @param string $url
* @param string|null $cwd
*
* @return void
*/
public function runCommand($commandCallable, $url, $cwd)
{
$this->config->prohibitUrlByConfig($url, $this->io);
@ -75,6 +82,12 @@ class Hg
$this->throwException('Failed to clone ' . $url . ', ' . "\n\n" . $error, $url);
}
/**
* @param non-empty-string $message
* @param string $url
*
* @return never
*/
private function throwException($message, $url)
{
if (null === self::getVersion($this->process)) {

View File

@ -23,8 +23,9 @@ class ProxyHelper
/**
* Returns proxy environment values
*
* @return array{string|null, string|null, string|null} httpProxy, httpsProxy, noProxy values
*
* @throws \RuntimeException on malformed url
* @return array httpProxy, httpsProxy, noProxy values
*/
public static function getProxyData()
{
@ -59,8 +60,9 @@ class ProxyHelper
/**
* Returns http context options for the proxy url
*
* @param string $proxyUrl
* @return array
* @param string $proxyUrl
*
* @return array{http: array{proxy: string, header?: string}}
*/
public static function getContextOptions($proxyUrl)
{
@ -90,8 +92,10 @@ class ProxyHelper
/**
* Sets/unsets request_fulluri value in http context options array
*
* @param string $requestUrl
* @param array $options Set by method
* @param string $requestUrl
* @param mixed[] $options Set by method
*
* @return void
*/
public static function setRequestFullUri($requestUrl, array &$options)
{
@ -105,8 +109,9 @@ class ProxyHelper
/**
* Searches $_SERVER for case-sensitive values
*
* @param array $names Names to search for
* @param mixed $name Name of any found value
* @param string[] $names Names to search for
* @param string|null $name Name of any found value
*
* @return string|null The found value
*/
private static function getProxyEnv(array $names, &$name)
@ -151,8 +156,9 @@ class ProxyHelper
/**
* Formats a url from its component parts
*
* @param array $proxy Values from parse_url
* @param bool $includeAuth Whether to include authorization values
* @param array{scheme: string, host: string, port?: int, user?: string, pass?: string} $proxy
* @param bool $includeAuth
*
* @return string The formatted value
*/
private static function formatParsedUrl(array $proxy, $includeAuth)

View File

@ -71,6 +71,8 @@ class ProxyManager
/**
* Clears the persistent instance
*
* @return void
*/
public static function reset()
{
@ -130,6 +132,8 @@ class ProxyManager
/**
* Initializes proxy values from the environment
*
* @return void
*/
private function initProxyData()
{
@ -160,8 +164,10 @@ class ProxyManager
/**
* Sets initial data
*
* @param string $url Proxy url
* @param 'http'|'https' $scheme Environment variable scheme
* @param non-empty-string $url Proxy url
* @param 'http'|'https' $scheme Environment variable scheme
*
* @return non-empty-string
*/
private function setData($url, $scheme)
{

View File

@ -17,6 +17,8 @@ use Symfony\Component\Process\Process;
/**
* @author Matt Whittom <Matt.Whittom@veteransunited.com>
*
* @phpstan-type RepoConfig array{unique_perforce_client_name?: string, depot?: string, branch?: string, p4user?: string, p4password?: string}
*/
class Perforce
{
@ -30,7 +32,7 @@ class Perforce
protected $p4User;
/** @var ?string */
protected $p4Password;
/** @var int */
/** @var string */
protected $p4Port;
/** @var string */
protected $p4Stream;
@ -55,6 +57,14 @@ class Perforce
/** @var Filesystem */
protected $filesystem;
/**
* @phpstan-param RepoConfig $repoConfig
* @param string $port
* @param string $path
* @param ProcessExecutor $process
* @param bool $isWindows
* @param IOInterface $io
*/
public function __construct($repoConfig, $port, $path, ProcessExecutor $process, $isWindows, IOInterface $io)
{
$this->windowsFlag = $isWindows;
@ -65,11 +75,26 @@ class Perforce
$this->io = $io;
}
/**
* @phpstan-param RepoConfig $repoConfig
* @param string $port
* @param string $path
* @param ProcessExecutor $process
* @param IOInterface $io
*
* @return self
*/
public static function create($repoConfig, $port, $path, ProcessExecutor $process, IOInterface $io)
{
return new Perforce($repoConfig, $port, $path, $process, Platform::isWindows(), $io);
}
/**
* @param string $url
* @param ProcessExecutor $processExecutor
*
* @return bool
*/
public static function checkServerExists($url, ProcessExecutor $processExecutor)
{
$output = null;
@ -77,6 +102,11 @@ class Perforce
return 0 === $processExecutor->execute('p4 -p ' . ProcessExecutor::escape($url) . ' info -s', $output);
}
/**
* @phpstan-param RepoConfig $repoConfig
*
* @return void
*/
public function initialize($repoConfig)
{
$this->uniquePerforceClientName = $this->generateUniquePerforceClientName();
@ -103,6 +133,12 @@ class Perforce
}
}
/**
* @param string|null $depot
* @param string|null $branch
*
* @return void
*/
public function initializeDepotAndBranch($depot, $branch)
{
if (isset($depot)) {
@ -113,11 +149,17 @@ class Perforce
}
}
/**
* @return non-empty-string
*/
public function generateUniquePerforceClientName()
{
return gethostname() . "_" . time();
}
/**
* @return void
*/
public function cleanupClientSpec()
{
$client = $this->getClient();
@ -130,6 +172,11 @@ class Perforce
$fileSystem->remove($clientSpec);
}
/**
* @param non-empty-string $command
*
* @return int
*/
protected function executeCommand($command)
{
$this->commandResult = '';
@ -137,6 +184,9 @@ class Perforce
return $this->process->execute($command, $this->commandResult);
}
/**
* @return string
*/
public function getClient()
{
if (!isset($this->p4Client)) {
@ -147,11 +197,19 @@ class Perforce
return $this->p4Client;
}
/**
* @return string
*/
protected function getPath()
{
return $this->path;
}
/**
* @param string $path
*
* @return void
*/
public function initializePath($path)
{
$this->path = $path;
@ -159,11 +217,19 @@ class Perforce
$fs->ensureDirectoryExists($path);
}
/**
* @return string
*/
protected function getPort()
{
return $this->p4Port;
}
/**
* @param string $stream
*
* @return void
*/
public function setStream($stream)
{
$this->p4Stream = $stream;
@ -174,11 +240,17 @@ class Perforce
}
}
/**
* @return bool
*/
public function isStream()
{
return is_string($this->p4DepotType) && (strcmp($this->p4DepotType, 'stream') === 0);
}
/**
* @return string
*/
public function getStream()
{
if (!isset($this->p4Stream)) {
@ -192,6 +264,11 @@ class Perforce
return $this->p4Stream;
}
/**
* @param string $stream
*
* @return string
*/
public function getStreamWithoutLabel($stream)
{
$index = strpos($stream, '@');
@ -202,21 +279,35 @@ class Perforce
return substr($stream, 0, $index);
}
/**
* @return non-empty-string
*/
public function getP4ClientSpec()
{
return $this->path . '/' . $this->getClient() . '.p4.spec';
}
/**
* @return string|null
*/
public function getUser()
{
return $this->p4User;
}
/**
* @param string $user
*
* @return void
*/
public function setUser($user)
{
$this->p4User = $user;
}
/**
* @return void
*/
public function queryP4User()
{
$this->getUser();
@ -272,6 +363,9 @@ class Perforce
return $result;
}
/**
* @return string|null
*/
public function queryP4Password()
{
if (isset($this->p4Password)) {
@ -286,6 +380,12 @@ class Perforce
return $password;
}
/**
* @param string $command
* @param bool $useClient
*
* @return non-empty-string
*/
public function generateP4Command($command, $useClient = true)
{
$p4Command = 'p4 ';
@ -298,6 +398,9 @@ class Perforce
return $p4Command;
}
/**
* @return bool
*/
public function isLoggedIn()
{
$command = $this->generateP4Command('login -s', false);
@ -318,6 +421,9 @@ class Perforce
return true;
}
/**
* @return void
*/
public function connectClient()
{
$p4CreateClientCommand = $this->generateP4Command(
@ -326,6 +432,11 @@ class Perforce
$this->executeCommand($p4CreateClientCommand);
}
/**
* @param string|null $sourceReference
*
* @return void
*/
public function syncCodeBase($sourceReference)
{
$prevDir = getcwd();
@ -338,6 +449,11 @@ class Perforce
chdir($prevDir);
}
/**
* @param resource|false $spec
*
* @return void
*/
public function writeClientSpecToFile($spec)
{
fwrite($spec, 'Client: ' . $this->getClient() . PHP_EOL . PHP_EOL);
@ -361,6 +477,9 @@ class Perforce
}
}
/**
* @return void
*/
public function writeP4ClientSpec()
{
$clientSpec = $this->getP4ClientSpec();
@ -374,6 +493,12 @@ class Perforce
fclose($spec);
}
/**
* @param resource $pipe
* @param mixed $name
*
* @return void
*/
protected function read($pipe, $name)
{
if (feof($pipe)) {
@ -385,6 +510,11 @@ class Perforce
}
}
/**
* @param string|null $password
*
* @return int
*/
public function windowsLogin($password)
{
$command = $this->generateP4Command(' login -a');
@ -393,12 +523,16 @@ class Perforce
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$process = Process::fromShellCommandline($command, null, null, $password);
} else {
// @phpstan-ignore-next-line
$process = new Process($command, null, null, $password);
}
return $process->run();
}
/**
* @return void
*/
public function p4Login()
{
$this->queryP4User();
@ -416,6 +550,11 @@ class Perforce
}
}
/**
* @param string $identifier
*
* @return mixed|void
*/
public function getComposerInformation($identifier)
{
$composerFileContent = $this->getFileContent('composer.json', $identifier);
@ -427,6 +566,12 @@ class Perforce
return json_decode($composerFileContent, true);
}
/**
* @param string $file
* @param string $identifier
*
* @return string|null
*/
public function getFileContent($file, $identifier)
{
$path = $this->getFilePath($file, $identifier);
@ -442,6 +587,12 @@ class Perforce
return $result;
}
/**
* @param string $file
* @param string $identifier
*
* @return string|null
*/
public function getFilePath($file, $identifier)
{
$index = strpos($identifier, '@');
@ -467,6 +618,9 @@ class Perforce
return null;
}
/**
* @return array{master: string}
*/
public function getBranches()
{
$possibleBranches = array();
@ -496,6 +650,9 @@ class Perforce
return array('master' => $possibleBranches[$this->p4Branch] . '@'. $lastCommitNum);
}
/**
* @return array<string, string>
*/
public function getTags()
{
$command = $this->generateP4Command('labels');
@ -513,6 +670,9 @@ class Perforce
return $tags;
}
/**
* @return bool
*/
public function checkStream()
{
$command = $this->generateP4Command('depots', false);
@ -578,6 +738,9 @@ class Perforce
return $this->commandResult;
}
/**
* @return Filesystem
*/
public function getFilesystem()
{
if (empty($this->filesystem)) {
@ -587,6 +750,9 @@ class Perforce
return $this->filesystem;
}
/**
* @return void
*/
public function setFilesystem(Filesystem $fs)
{
$this->filesystem = $fs;

View File

@ -555,6 +555,7 @@ class RemoteFilesystem
* @param string $originUrl The origin URL
* @param string $fileUrl The file URL
* @param resource $context The stream context
* @param string[] $responseHeaders
* @param int $maxFileSize The maximum allowed file size
*
* @return string|false The response contents or false on failure
@ -592,12 +593,15 @@ class RemoteFilesystem
/**
* Get notification action.
*
* @param int $notificationCode The notification code
* @param int $severity The severity level
* @param string $message The message
* @param int $messageCode The message code
* @param int $bytesTransferred The loaded size
* @param int $bytesMax The total size
* @param int $notificationCode The notification code
* @param int $severity The severity level
* @param string $message The message
* @param int $messageCode The message code
* @param int $bytesTransferred The loaded size
* @param int $bytesMax The total size
*
* @return void
*
* @throws TransportException
*/
protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
@ -631,6 +635,13 @@ class RemoteFilesystem
}
}
/**
* @param positive-int $httpStatus
* @param string|null $reason
* @param string[] $headers
*
* @return void
*/
protected function promptAuthAndRetry($httpStatus, $reason = null, $headers = array())
{
$result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers);
@ -643,6 +654,12 @@ class RemoteFilesystem
}
}
/**
* @param string $originUrl
* @param mixed[] $additionalOptions
*
* @return mixed[]
*/
protected function getOptionsForUrl($originUrl, $additionalOptions)
{
$tlsOptions = array();
@ -714,6 +731,13 @@ class RemoteFilesystem
return $options;
}
/**
* @param string[] $http_response_header
* @param mixed[] $additionalOptions
* @param string|false $result
*
* @return bool|string
*/
private function handleRedirect(array $http_response_header, array $additionalOptions, $result)
{
if ($locationHeader = Response::findHeaderValue($http_response_header, 'location')) {
@ -763,6 +787,9 @@ class RemoteFilesystem
*
* @todo Remove when PHP 5.6 is minimum supported version.
*
* @param string $url
* @param mixed[] $options
*
* @return ?array{cn: string, fp: string}
*/
private function getCertificateCnAndFp($url, $options)
@ -807,6 +834,11 @@ class RemoteFilesystem
return null;
}
/**
* @param string $url
*
* @return string
*/
private function getUrlAuthority($url)
{
$defaultPorts = array(
@ -832,6 +864,12 @@ class RemoteFilesystem
return parse_url($url, PHP_URL_HOST).':'.$port;
}
/**
* @param string|false $result
* @param string[] $http_response_header
*
* @return string|false
*/
private function decodeResult($result, $http_response_header)
{
// decode gzip