Merge branch 'master' into 2.0
commit
6c4357a7ed
|
@ -30,9 +30,11 @@ matrix:
|
|||
env:
|
||||
- deps=high
|
||||
- php: nightly
|
||||
- php: 7.4snapshot
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
- php: 7.4snapshot
|
||||
|
||||
before_install:
|
||||
# disable xdebug if available
|
||||
|
|
|
@ -259,6 +259,10 @@ match the platform requirements of the installed packages. This can be used
|
|||
to verify that a production server has all the extensions needed to run a
|
||||
project after installing it for example.
|
||||
|
||||
Unlike update/install, this command will ignore config.platform settings and
|
||||
check the real platform packages so you can be certain you have the required
|
||||
platform dependencies.
|
||||
|
||||
## global
|
||||
|
||||
The global command allows you to run other commands like `install`, `remove`, `require`
|
||||
|
|
|
@ -112,6 +112,19 @@ Note that this will still need to pull and scan all of your VCS repositories
|
|||
because any VCS repository might contain (on any branch) one of the selected
|
||||
packages.
|
||||
|
||||
If you want to scan only the selected package and not all VCS repositories you need
|
||||
to declare a *name* for all your package (this only work on VCS repositories type) :
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [
|
||||
{ "name": "company/privaterepo", "type": "vcs", "url": "https://github.com/mycompany/privaterepo" },
|
||||
{ "name": "private/repo", "type": "vcs", "url": "http://svn.example.org/private/repo" },
|
||||
{ "name": "mycompany/privaterepo2", "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If you want to scan only a single repository and update all packages found in
|
||||
it, pass the VCS repository URL as an optional argument:
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ class CheckPlatformReqsCommand extends BaseCommand
|
|||
<<<EOT
|
||||
Checks that your PHP and extensions versions match the platform requirements of the installed packages.
|
||||
|
||||
Unlike update/install, this command will ignore config.platform settings and check the real platform packages so you can be certain you have the required platform dependencies.
|
||||
|
||||
<info>php composer.phar check-platform-reqs</info>
|
||||
|
||||
EOT
|
||||
|
@ -49,6 +51,10 @@ EOT
|
|||
$dependencies = $composer->getLocker()->getLockedRepository(!$input->getOption('no-dev'))->getPackages();
|
||||
} else {
|
||||
$dependencies = $composer->getRepositoryManager()->getLocalRepository()->getPackages();
|
||||
// fallback to lockfile if installed repo is empty
|
||||
if (!$dependencies) {
|
||||
$dependencies = $composer->getLocker()->getLockedRepository(true)->getPackages();
|
||||
}
|
||||
$requires += $composer->getPackage()->getDevRequires();
|
||||
}
|
||||
foreach ($requires as $require => $link) {
|
||||
|
|
|
@ -168,13 +168,25 @@ EOT
|
|||
if ($repositories) {
|
||||
$config = Factory::createConfig($io);
|
||||
$repos = array(new PlatformRepository);
|
||||
$createDefaultPackagistRepo = true;
|
||||
foreach ($repositories as $repo) {
|
||||
$repos[] = RepositoryFactory::fromString($io, $config, $repo);
|
||||
$repoConfig = RepositoryFactory::configFromString($io, $config, $repo);
|
||||
if (
|
||||
(isset($repoConfig['packagist']) && $repoConfig === array('packagist' => false))
|
||||
|| (isset($repoConfig['packagist.org']) && $repoConfig === array('packagist.org' => false))
|
||||
) {
|
||||
$createDefaultPackagistRepo = false;
|
||||
continue;
|
||||
}
|
||||
$repos[] = RepositoryFactory::createRepo($io, $config, $repoConfig);
|
||||
}
|
||||
|
||||
if ($createDefaultPackagistRepo) {
|
||||
$repos[] = RepositoryFactory::createRepo($io, $config, array(
|
||||
'type' => 'composer',
|
||||
'url' => 'https://repo.packagist.org',
|
||||
));
|
||||
}
|
||||
|
||||
$this->repos = new CompositeRepository($repos);
|
||||
unset($repos, $config, $repositories);
|
||||
|
|
|
@ -26,6 +26,7 @@ use Composer\Plugin\PluginEvents;
|
|||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Util\Silencer;
|
||||
|
||||
/**
|
||||
* @author Jérémy Romey <jeremy@free-agent.fr>
|
||||
|
@ -103,11 +104,6 @@ EOT
|
|||
|
||||
return 1;
|
||||
}
|
||||
if (!is_writable($this->file)) {
|
||||
$io->writeError('<error>'.$this->file.' is not writable.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (filesize($this->file) === 0) {
|
||||
file_put_contents($this->file, "{\n}\n");
|
||||
|
@ -116,6 +112,14 @@ EOT
|
|||
$this->json = new JsonFile($this->file);
|
||||
$this->composerBackup = file_get_contents($this->json->getPath());
|
||||
|
||||
// check for writability by writing to the file as is_writable can not be trusted on network-mounts
|
||||
// see https://github.com/composer/composer/issues/8231 and https://bugs.php.net/bug.php?id=68926
|
||||
if (!is_writable($this->file) && !Silencer::call('file_put_contents', $this->file, $this->composerBackup)) {
|
||||
$io->writeError('<error>'.$this->file.' is not writable.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
$repos = $composer->getRepositoryManager()->getRepositories();
|
||||
|
||||
|
@ -141,7 +145,12 @@ EOT
|
|||
|
||||
// validate requirements format
|
||||
$versionParser = new VersionParser();
|
||||
foreach ($requirements as $constraint) {
|
||||
foreach ($requirements as $package => $constraint) {
|
||||
if (strtolower($package) === $composer->getPackage()->getName()) {
|
||||
$io->writeError(sprintf('<error>Root package \'%s\' cannot require itself in its composer.json</error>', $package));
|
||||
|
||||
return 1;
|
||||
}
|
||||
$versionParser->parseConstraints($constraint);
|
||||
}
|
||||
|
||||
|
|
|
@ -379,6 +379,9 @@ class Application extends BaseApplication
|
|||
public function resetComposer()
|
||||
{
|
||||
$this->composer = null;
|
||||
if ($this->getIO() && method_exists($this->getIO(), 'resetAuthentications')) {
|
||||
$this->getIO()->resetAuthentications();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -197,7 +197,7 @@ class RuleSetGenerator
|
|||
}
|
||||
}
|
||||
|
||||
protected function addConflictRules()
|
||||
protected function addConflictRules($ignorePlatformReqs = false)
|
||||
{
|
||||
/** @var PackageInterface $package */
|
||||
foreach ($this->addedPackages as $package) {
|
||||
|
@ -206,6 +206,10 @@ class RuleSetGenerator
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var PackageInterface $possibleConflict */
|
||||
foreach ($this->addedPackagesByNames[$link->getTarget()] as $possibleConflict) {
|
||||
$conflictMatch = $this->pool->match($possibleConflict, $link->getTarget(), $link->getConstraint(), true);
|
||||
|
@ -304,7 +308,7 @@ class RuleSetGenerator
|
|||
|
||||
$this->addRulesForJobs($ignorePlatformReqs);
|
||||
|
||||
$this->addConflictRules();
|
||||
$this->addConflictRules($ignorePlatformReqs);
|
||||
|
||||
// Remove references to packages
|
||||
$this->addedPackages = $this->addedPackagesByNames = null;
|
||||
|
|
|
@ -87,8 +87,6 @@ class PerforceDownloader extends VcsDownloader
|
|||
public function getLocalChanges(PackageInterface $package, $path)
|
||||
{
|
||||
$this->io->writeError('Perforce driver does not check for local changes before overriding', true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -200,7 +200,9 @@ class EventDispatcher
|
|||
|
||||
try {
|
||||
/** @var InstallerEvent $event */
|
||||
$return = $this->dispatch($scriptName, new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags));
|
||||
$scriptEvent = new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags);
|
||||
$scriptEvent->setOriginatingEvent($event);
|
||||
$return = $this->dispatch($scriptName, $scriptEvent);
|
||||
} catch (ScriptExecutionException $e) {
|
||||
$this->io->writeError(sprintf('<error>Script %s was called via %s</error>', $callable, $event->getName()), true, IOInterface::QUIET);
|
||||
throw $e;
|
||||
|
|
|
@ -28,6 +28,14 @@ abstract class BaseIO implements IOInterface
|
|||
return $this->authentications;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function resetAuthentications()
|
||||
{
|
||||
$this->authentications = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
|
@ -326,9 +326,10 @@ class JsonManipulator
|
|||
}
|
||||
|
||||
// try and find a match for the subkey
|
||||
if ($this->pregMatch('{"'.preg_quote($name).'"\s*:}i', $children)) {
|
||||
$keyRegex = str_replace('/', '\\\\?/', preg_quote($name));
|
||||
if ($this->pregMatch('{"'.$keyRegex.'"\s*:}i', $children)) {
|
||||
// find best match for the value of "name"
|
||||
if (preg_match_all('{'.self::$DEFINES.'"'.preg_quote($name).'"\s*:\s*(?:(?&json))}x', $children, $matches)) {
|
||||
if (preg_match_all('{'.self::$DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) {
|
||||
$bestMatch = '';
|
||||
foreach ($matches[0] as $match) {
|
||||
if (strlen($bestMatch) < strlen($match)) {
|
||||
|
|
|
@ -16,6 +16,7 @@ use Composer\IO\IOInterface;
|
|||
use Composer\Json\JsonFile;
|
||||
use Composer\Package\Loader\ArrayLoader;
|
||||
use Composer\Package\Loader\LoaderInterface;
|
||||
use Composer\Util\Zip;
|
||||
|
||||
/**
|
||||
* @author Serge Smertin <serg.smertin@gmail.com>
|
||||
|
@ -80,76 +81,15 @@ class ArtifactRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a file by name, returning the one that has the shortest path.
|
||||
*
|
||||
* @param \ZipArchive $zip
|
||||
* @param string $filename
|
||||
* @return bool|int
|
||||
*/
|
||||
private function locateFile(\ZipArchive $zip, $filename)
|
||||
{
|
||||
$indexOfShortestMatch = false;
|
||||
$lengthOfShortestMatch = -1;
|
||||
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$stat = $zip->statIndex($i);
|
||||
if (strcmp(basename($stat['name']), $filename) === 0) {
|
||||
$directoryName = dirname($stat['name']);
|
||||
if ($directoryName == '.') {
|
||||
//if composer.json is in root directory
|
||||
//it has to be the one to use.
|
||||
return $i;
|
||||
}
|
||||
|
||||
if (strpos($directoryName, '\\') !== false ||
|
||||
strpos($directoryName, '/') !== false) {
|
||||
//composer.json files below first directory are rejected
|
||||
continue;
|
||||
}
|
||||
|
||||
$length = strlen($stat['name']);
|
||||
if ($indexOfShortestMatch === false || $length < $lengthOfShortestMatch) {
|
||||
//Check it's not a directory.
|
||||
$contents = $zip->getFromIndex($i);
|
||||
if ($contents !== false) {
|
||||
$indexOfShortestMatch = $i;
|
||||
$lengthOfShortestMatch = $length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $indexOfShortestMatch;
|
||||
}
|
||||
|
||||
private function getComposerInformation(\SplFileInfo $file)
|
||||
{
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($file->getPathname()) !== true) {
|
||||
$json = Zip::getComposerJson($file->getPathname());
|
||||
|
||||
if (null === $json) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == $zip->numFiles) {
|
||||
$zip->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$foundFileIndex = $this->locateFile($zip, 'composer.json');
|
||||
if (false === $foundFileIndex) {
|
||||
$zip->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$configurationFileName = $zip->getNameIndex($foundFileIndex);
|
||||
$zip->close();
|
||||
|
||||
$composerFile = "zip://{$file->getPathname()}#$configurationFileName";
|
||||
$json = file_get_contents($composerFile);
|
||||
|
||||
$package = JsonFile::parseJson($json, $composerFile);
|
||||
$package = JsonFile::parseJson($json, $file->getPathname().'#composer.json');
|
||||
$package['dist'] = array(
|
||||
'type' => 'zip',
|
||||
'url' => strtr($file->getPathname(), '\\', '/'),
|
||||
|
|
|
@ -308,6 +308,10 @@ class GitHubDriver extends VcsDriver
|
|||
*/
|
||||
protected function generateSshUrl()
|
||||
{
|
||||
if (false !== strpos($this->originUrl, ':')) {
|
||||
return 'ssh://git@' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
|
||||
}
|
||||
|
||||
return 'git@' . $this->originUrl . ':'.$this->owner.'/'.$this->repository.'.git';
|
||||
}
|
||||
|
||||
|
|
|
@ -68,9 +68,9 @@ class GitLabDriver extends VcsDriver
|
|||
private $isPrivate = true;
|
||||
|
||||
/**
|
||||
* @var int port number
|
||||
* @var bool true if the origin has a port number or a path component in it
|
||||
*/
|
||||
protected $portNumber;
|
||||
private $hasNonstandardOrigin = false;
|
||||
|
||||
const URL_REGEX = '#^(?:(?P<scheme>https?)://(?P<domain>.+?)(?::(?P<port>[0-9]+))?/|git@(?P<domain2>[^:]+):)(?P<parts>.+)/(?P<repo>[^/]+?)(?:\.git|/)?$#';
|
||||
|
||||
|
@ -95,11 +95,10 @@ class GitLabDriver extends VcsDriver
|
|||
? $match['scheme']
|
||||
: (isset($this->repoConfig['secure-http']) && $this->repoConfig['secure-http'] === false ? 'http' : 'https')
|
||||
;
|
||||
$this->originUrl = $this->determineOrigin($configuredDomains, $guessedDomain, $urlParts);
|
||||
$this->originUrl = $this->determineOrigin($configuredDomains, $guessedDomain, $urlParts, $match['port']);
|
||||
|
||||
if (!empty($match['port']) && true === is_numeric($match['port'])) {
|
||||
// If it is an HTTP based URL, and it has a port
|
||||
$this->portNumber = (int) $match['port'];
|
||||
if (false !== strpos($this->originUrl, ':') || false !== strpos($this->originUrl, '/')) {
|
||||
$this->hasNonstandardOrigin = true;
|
||||
}
|
||||
|
||||
$this->namespace = implode('/', $urlParts);
|
||||
|
@ -260,10 +259,7 @@ class GitLabDriver extends VcsDriver
|
|||
*/
|
||||
public function getApiUrl()
|
||||
{
|
||||
$domainName = $this->originUrl;
|
||||
$portNumber = (true === is_numeric($this->portNumber)) ? sprintf(':%s', $this->portNumber) : '';
|
||||
|
||||
return $this->scheme.'://'.$domainName.$portNumber.'/api/v4/projects/'.$this->urlEncodeAll($this->namespace).'%2F'.$this->urlEncodeAll($this->repository);
|
||||
return $this->scheme.'://'.$this->originUrl.'/api/v4/projects/'.$this->urlEncodeAll($this->namespace).'%2F'.$this->urlEncodeAll($this->repository);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -362,6 +358,10 @@ class GitLabDriver extends VcsDriver
|
|||
*/
|
||||
protected function generateSshUrl()
|
||||
{
|
||||
if ($this->hasNonstandardOrigin) {
|
||||
return 'ssh://git@'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository.'.git';
|
||||
}
|
||||
|
||||
return 'git@' . $this->originUrl . ':'.$this->namespace.'/'.$this->repository.'.git';
|
||||
}
|
||||
|
||||
|
@ -464,7 +464,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)) {
|
||||
if (false === self::determineOrigin((array) $config->get('gitlab-domains'), $guessedDomain, $urlParts, $match['port'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -495,16 +495,16 @@ class GitLabDriver extends VcsDriver
|
|||
* @param array $urlParts
|
||||
* @return bool|string
|
||||
*/
|
||||
private static function determineOrigin(array $configuredDomains, $guessedDomain, array &$urlParts)
|
||||
private static function determineOrigin(array $configuredDomains, $guessedDomain, array &$urlParts, $portNumber)
|
||||
{
|
||||
if (in_array($guessedDomain, $configuredDomains)) {
|
||||
if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array($guessedDomain.':'.$portNumber, $configuredDomains))) {
|
||||
return $guessedDomain;
|
||||
}
|
||||
|
||||
while (null !== ($part = array_shift($urlParts))) {
|
||||
$guessedDomain .= '/' . $part;
|
||||
|
||||
if (in_array($guessedDomain, $configuredDomains)) {
|
||||
if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array(preg_replace('{/}', ':'.$portNumber.'/', $guessedDomain, 1), $configuredDomains))) {
|
||||
return $guessedDomain;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,11 @@ class Event extends BaseEvent
|
|||
*/
|
||||
private $devMode;
|
||||
|
||||
/**
|
||||
* @var BaseEvent
|
||||
*/
|
||||
private $originatingEvent;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -55,6 +60,7 @@ class Event extends BaseEvent
|
|||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
$this->devMode = $devMode;
|
||||
$this->originatingEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,4 +92,42 @@ class Event extends BaseEvent
|
|||
{
|
||||
return $this->devMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the originating event.
|
||||
*
|
||||
* @return \Composer\EventDispatcher\Event|null
|
||||
*/
|
||||
public function getOriginatingEvent()
|
||||
{
|
||||
return $this->originatingEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the originating event.
|
||||
*
|
||||
* @param \Composer\EventDispatcher\Event $event
|
||||
* @return $this
|
||||
*/
|
||||
public function setOriginatingEvent(BaseEvent $event)
|
||||
{
|
||||
$this->originatingEvent = $this->calculateOriginatingEvent($event);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the upper-most event in chain.
|
||||
*
|
||||
* @param \Composer\EventDispatcher\Event $event
|
||||
* @return \Composer\EventDispatcher\Event
|
||||
*/
|
||||
private function calculateOriginatingEvent(BaseEvent $event)
|
||||
{
|
||||
if ($event instanceof Event && $event->getOriginatingEvent()) {
|
||||
return $this->calculateOriginatingEvent($event->getOriginatingEvent());
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ class ErrorHandler
|
|||
*
|
||||
* @static
|
||||
* @throws \ErrorException
|
||||
* @return bool
|
||||
*/
|
||||
public static function handle($level, $message, $file, $line)
|
||||
{
|
||||
|
@ -63,6 +64,8 @@ class ErrorHandler
|
|||
}, array_slice(debug_backtrace(), 2))));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,7 +57,10 @@ class GitLab
|
|||
*/
|
||||
public function authorizeOAuth($originUrl)
|
||||
{
|
||||
if (!in_array($originUrl, $this->config->get('gitlab-domains'), true)) {
|
||||
// before composer 1.9, origin URLs had no port number in them
|
||||
$bcOriginUrl = preg_replace('{:\d+}', '', $originUrl);
|
||||
|
||||
if (!in_array($originUrl, $this->config->get('gitlab-domains'), true) && !in_array($bcOriginUrl, $this->config->get('gitlab-domains'), true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -77,6 +80,12 @@ class GitLab
|
|||
return true;
|
||||
}
|
||||
|
||||
if (isset($authTokens[$bcOriginUrl])) {
|
||||
$this->io->setAuthentication($originUrl, $authTokens[$bcOriginUrl], 'private-token');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -363,8 +363,6 @@ class Perforce
|
|||
while ($line !== false) {
|
||||
$line = fgets($pipe);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public function windowsLogin($password)
|
||||
|
|
|
@ -286,6 +286,8 @@ class RemoteFilesystem
|
|||
$errorMessage .= "\n";
|
||||
}
|
||||
$errorMessage .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg);
|
||||
|
||||
return true;
|
||||
});
|
||||
try {
|
||||
$result = $this->getRemoteContents($originUrl, $fileUrl, $ctx, $http_response_header);
|
||||
|
@ -459,6 +461,8 @@ class RemoteFilesystem
|
|||
$errorMessage .= "\n";
|
||||
}
|
||||
$errorMessage .= preg_replace('{^file_put_contents\(.*?\): }', '', $msg);
|
||||
|
||||
return true;
|
||||
});
|
||||
$result = (bool) file_put_contents($fileName, $result);
|
||||
restore_error_handler();
|
||||
|
|
|
@ -19,8 +19,6 @@ use Composer\CaBundle\CaBundle;
|
|||
*/
|
||||
final class TlsHelper
|
||||
{
|
||||
private static $useOpensslParse;
|
||||
|
||||
/**
|
||||
* Match hostname against a certificate.
|
||||
*
|
||||
|
|
|
@ -70,6 +70,9 @@ class Url
|
|||
}
|
||||
|
||||
$origin = (string) parse_url($url, PHP_URL_HOST);
|
||||
if ($port = parse_url($url, PHP_URL_PORT)) {
|
||||
$origin .= ':'.$port;
|
||||
}
|
||||
|
||||
if (strpos($origin, '.github.com') === (strlen($origin) - 11)) {
|
||||
return 'github.com';
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Util;
|
||||
|
||||
/**
|
||||
* @author Andreas Schempp <andreas.schempp@terminal42.ch>
|
||||
*/
|
||||
class Zip
|
||||
{
|
||||
/**
|
||||
* Gets content of the root composer.json inside a ZIP archive.
|
||||
*
|
||||
* @param string $pathToZip
|
||||
* @param string $filename
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getComposerJson($pathToZip)
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
throw new \RuntimeException('The Zip Util requires PHP\'s zip extension');
|
||||
}
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($pathToZip) !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (0 == $zip->numFiles) {
|
||||
$zip->close();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$foundFileIndex = self::locateFile($zip, 'composer.json');
|
||||
if (false === $foundFileIndex) {
|
||||
$zip->close();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$content = null;
|
||||
$configurationFileName = $zip->getNameIndex($foundFileIndex);
|
||||
$stream = $zip->getStream($configurationFileName);
|
||||
|
||||
if (false !== $stream) {
|
||||
$content = stream_get_contents($stream);
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a file by name, returning the one that has the shortest path.
|
||||
*
|
||||
* @param \ZipArchive $zip
|
||||
* @param string $filename
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
private static function locateFile(\ZipArchive $zip, $filename)
|
||||
{
|
||||
$indexOfShortestMatch = false;
|
||||
$lengthOfShortestMatch = -1;
|
||||
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$stat = $zip->statIndex($i);
|
||||
if (strcmp(basename($stat['name']), $filename) === 0) {
|
||||
$directoryName = dirname($stat['name']);
|
||||
if ($directoryName === '.') {
|
||||
//if composer.json is in root directory
|
||||
//it has to be the one to use.
|
||||
return $i;
|
||||
}
|
||||
|
||||
if (strpos($directoryName, '\\') !== false ||
|
||||
strpos($directoryName, '/') !== false) {
|
||||
//composer.json files below first directory are rejected
|
||||
continue;
|
||||
}
|
||||
|
||||
$length = strlen($stat['name']);
|
||||
if ($indexOfShortestMatch === false || $length < $lengthOfShortestMatch) {
|
||||
//Check it's not a directory.
|
||||
$contents = $zip->getFromIndex($i);
|
||||
if ($contents !== false) {
|
||||
$indexOfShortestMatch = $i;
|
||||
$lengthOfShortestMatch = $length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $indexOfShortestMatch;
|
||||
}
|
||||
}
|
|
@ -162,18 +162,18 @@ class AllFunctionalTest extends TestCase
|
|||
}
|
||||
};
|
||||
|
||||
for ($i = 0, $c = count($tokens); $i < $c; $i++) {
|
||||
if ('' === $tokens[$i] && null === $section) {
|
||||
foreach ($tokens as $token) {
|
||||
if ('' === $token && null === $section) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle section headers.
|
||||
if (null === $section) {
|
||||
$section = $tokens[$i];
|
||||
$section = $token;
|
||||
continue;
|
||||
}
|
||||
|
||||
$sectionData = $tokens[$i];
|
||||
$sectionData = $token;
|
||||
|
||||
// Allow sections to validate, or modify their section data.
|
||||
switch ($section) {
|
||||
|
|
|
@ -152,11 +152,4 @@ class RuleSetTest extends TestCase
|
|||
|
||||
$this->assertContains('JOB : Install command rule (install foo 2.1)', $ruleSet->getPrettyString($pool));
|
||||
}
|
||||
|
||||
private function getRuleMock()
|
||||
{
|
||||
return $this->getMockBuilder('Composer\DependencyResolver\Rule')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1448,6 +1448,22 @@ class JsonManipulatorTest extends TestCase
|
|||
"repositories": {
|
||||
}
|
||||
}
|
||||
',
|
||||
),
|
||||
'works on simple ones escaped slash' => array(
|
||||
'{
|
||||
"repositories": {
|
||||
"foo\/bar": {
|
||||
"bar": "baz"
|
||||
}
|
||||
}
|
||||
}',
|
||||
'foo/bar',
|
||||
true,
|
||||
'{
|
||||
"repositories": {
|
||||
}
|
||||
}
|
||||
',
|
||||
),
|
||||
'works on simple ones middle' => array(
|
||||
|
|
|
@ -148,7 +148,6 @@ class ArrayLoaderTest extends TestCase
|
|||
{
|
||||
$package = $this->loader->load($config);
|
||||
$dumper = new ArrayDumper;
|
||||
$expectedConfig = $config;
|
||||
$expectedConfig = $this->fixConfigWhenLoadConfigIsFalse($config);
|
||||
$this->assertEquals($expectedConfig, $dumper->dump($package));
|
||||
}
|
||||
|
|
|
@ -40,15 +40,6 @@ class FossilDriverTest extends TestCase
|
|||
$fs->removeDirectory($this->home);
|
||||
}
|
||||
|
||||
private function getCmd($cmd)
|
||||
{
|
||||
if (Platform::isWindows()) {
|
||||
return strtr($cmd, "'", '"');
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
public static function supportProvider()
|
||||
{
|
||||
return array(
|
||||
|
|
|
@ -71,15 +71,6 @@ class SvnDriverTest extends TestCase
|
|||
$svn->initialize();
|
||||
}
|
||||
|
||||
private function getCmd($cmd)
|
||||
{
|
||||
if (Platform::isWindows()) {
|
||||
return strtr($cmd, "'", '"');
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
public static function supportProvider()
|
||||
{
|
||||
return array(
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Test\Script;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\Config;
|
||||
use Composer\Script\Event;
|
||||
use Composer\Test\TestCase;
|
||||
|
||||
class EventTest extends TestCase
|
||||
{
|
||||
public function testEventSetsOriginatingEvent()
|
||||
{
|
||||
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
|
||||
$composer = $this->createComposerInstance();
|
||||
|
||||
$originatingEvent = new \Composer\EventDispatcher\Event('originatingEvent');
|
||||
|
||||
$scriptEvent = new Event('test', $composer, $io, true);
|
||||
|
||||
$this->assertNull(
|
||||
$scriptEvent->getOriginatingEvent(),
|
||||
'originatingEvent is initialized as null'
|
||||
);
|
||||
|
||||
$scriptEvent->setOriginatingEvent($originatingEvent);
|
||||
|
||||
$this->assertSame(
|
||||
$originatingEvent,
|
||||
$scriptEvent->getOriginatingEvent(),
|
||||
'getOriginatingEvent() SHOULD return test event'
|
||||
);
|
||||
}
|
||||
|
||||
public function testEventCalculatesNestedOriginatingEvent()
|
||||
{
|
||||
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
|
||||
$composer = $this->createComposerInstance();
|
||||
|
||||
$originatingEvent = new \Composer\EventDispatcher\Event('upperOriginatingEvent');
|
||||
$intermediateEvent = new Event('intermediate', $composer, $io, true);
|
||||
$intermediateEvent->setOriginatingEvent($originatingEvent);
|
||||
|
||||
$scriptEvent = new Event('test', $composer, $io, true);
|
||||
$scriptEvent->setOriginatingEvent($intermediateEvent);
|
||||
|
||||
$this->assertNotSame(
|
||||
$intermediateEvent,
|
||||
$scriptEvent->getOriginatingEvent(),
|
||||
'getOriginatingEvent() SHOULD NOT return intermediate events'
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
$originatingEvent,
|
||||
$scriptEvent->getOriginatingEvent(),
|
||||
'getOriginatingEvent() SHOULD return upper-most event'
|
||||
);
|
||||
}
|
||||
|
||||
private function createComposerInstance()
|
||||
{
|
||||
$composer = new Composer;
|
||||
$config = new Config;
|
||||
$composer->setConfig($config);
|
||||
$package = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
|
||||
$composer->setPackage($package);
|
||||
|
||||
return $composer;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -24,12 +24,9 @@ use RecursiveIteratorIterator;
|
|||
*/
|
||||
class GitHubTest extends TestCase
|
||||
{
|
||||
private $username = 'username';
|
||||
private $password = 'password';
|
||||
private $authcode = 'authcode';
|
||||
private $message = 'mymessage';
|
||||
private $origin = 'github.com';
|
||||
private $token = 'githubtoken';
|
||||
|
||||
public function testUsernamePasswordAuthenticationFlow()
|
||||
{
|
||||
|
|
|
@ -24,7 +24,6 @@ class GitLabTest extends TestCase
|
|||
{
|
||||
private $username = 'username';
|
||||
private $password = 'password';
|
||||
private $authcode = 'authcode';
|
||||
private $message = 'mymessage';
|
||||
private $origin = 'gitlab.com';
|
||||
private $token = 'gitlabtoken';
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Test\Util;
|
||||
|
||||
use Composer\Util\Zip;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @author Andreas Schempp <andreas.schempp@terminal42.ch>
|
||||
*/
|
||||
class ZipTest extends TestCase
|
||||
{
|
||||
public function testThrowsExceptionIfZipExcentionIsNotLoaded()
|
||||
{
|
||||
if (extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is loaded.');
|
||||
}
|
||||
|
||||
$this->setExpectedException('\RuntimeException', 'The Zip Util requires PHP\'s zip extension');
|
||||
|
||||
Zip::getComposerJson('');
|
||||
}
|
||||
|
||||
public function testReturnsNullifTheZipIsNotFound()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/invalid.zip');
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testReturnsNullIfTheZipIsEmpty()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/empty.zip');
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testReturnsNullIfTheZipHasNoComposerJson()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/nojson.zip');
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testReturnsNullIfTheComposerJsonIsInASubSubfolder()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/subfolder.zip');
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testReturnsComposerJsonInZipRoot()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/root.zip');
|
||||
|
||||
$this->assertEquals("{\n \"name\": \"foo/bar\"\n}\n", $result);
|
||||
}
|
||||
|
||||
public function testReturnsComposerJsonInFirstFolder()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/folder.zip');
|
||||
|
||||
$this->assertEquals("{\n \"name\": \"foo/bar\"\n}\n", $result);
|
||||
}
|
||||
|
||||
public function testReturnsRootComposerJsonAndSkipsSubfolders()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/multiple.zip');
|
||||
|
||||
$this->assertEquals("{\n \"name\": \"foo/bar\"\n}\n", $result);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue