Merge branch 'master' into 2.0
commit
0ea06de286
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,3 +1,15 @@
|
||||||
|
### [1.9.1] 2019-11-01
|
||||||
|
|
||||||
|
* Fixed various credential handling issues with gitlab and github
|
||||||
|
* Fixed credentials being present in git remotes in Composer cache and vendor directory when not using SSH keys
|
||||||
|
* Fixed `composer why` not listing replacers as a reason something is present
|
||||||
|
* Fixed various PHP 7.4 compatibility issues
|
||||||
|
* Fixed root warnings always present in Docker containers, setting COMPOSER_ALLOW_SUPERUSER is not necessary anymore
|
||||||
|
* Fixed GitHub access tokens leaking into debug-verbosity output
|
||||||
|
* Fixed several edge case issues detecting GitHub, Bitbucket and GitLab repository types
|
||||||
|
* Fixed Composer asking if you want to use a composer.json in a parent directory when ran in non-interactive mode
|
||||||
|
* Fixed classmap autoloading issue finding classes located within a few non-PHP context blocks (?>...<?php)
|
||||||
|
|
||||||
### [1.9.0] 2019-08-02
|
### [1.9.0] 2019-08-02
|
||||||
|
|
||||||
* Breaking: artifact repositories with URLs containing port numbers and requiring authentication now require you to configure http-basic auth for the `host:port` pair explicitly
|
* Breaking: artifact repositories with URLs containing port numbers and requiring authentication now require you to configure http-basic auth for the `host:port` pair explicitly
|
||||||
|
@ -764,6 +776,7 @@
|
||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
|
[1.9.1]: https://github.com/composer/composer/compare/1.9.0...1.9.1
|
||||||
[1.9.0]: https://github.com/composer/composer/compare/1.8.6...1.9.0
|
[1.9.0]: https://github.com/composer/composer/compare/1.8.6...1.9.0
|
||||||
[1.8.6]: https://github.com/composer/composer/compare/1.8.5...1.8.6
|
[1.8.6]: https://github.com/composer/composer/compare/1.8.5...1.8.6
|
||||||
[1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5
|
[1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5
|
||||||
|
|
|
@ -256,15 +256,14 @@ EOF;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$namespaceFilter = $namespace === '' ? null : $namespace;
|
$classMap = $this->addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist, $namespace, $group['type'], $classMap);
|
||||||
$classMap = $this->addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist, $namespaceFilter, $classMap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($autoloads['classmap'] as $dir) {
|
foreach ($autoloads['classmap'] as $dir) {
|
||||||
$classMap = $this->addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist, null, $classMap);
|
$classMap = $this->addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist, null, null, $classMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($classMap);
|
ksort($classMap);
|
||||||
|
@ -317,9 +316,9 @@ EOF;
|
||||||
return count($classMap);
|
return count($classMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist = null, $namespaceFilter = null, array $classMap = array())
|
private function addClassMapCode($filesystem, $basePath, $vendorPath, $dir, $blacklist = null, $namespaceFilter = null, $autoloadType = null, array $classMap = array())
|
||||||
{
|
{
|
||||||
foreach ($this->generateClassMap($dir, $blacklist, $namespaceFilter) as $class => $path) {
|
foreach ($this->generateClassMap($dir, $blacklist, $namespaceFilter, $autoloadType) as $class => $path) {
|
||||||
$pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n";
|
$pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n";
|
||||||
if (!isset($classMap[$class])) {
|
if (!isset($classMap[$class])) {
|
||||||
$classMap[$class] = $pathCode;
|
$classMap[$class] = $pathCode;
|
||||||
|
@ -334,9 +333,9 @@ EOF;
|
||||||
return $classMap;
|
return $classMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateClassMap($dir, $blacklist = null, $namespaceFilter = null, $showAmbiguousWarning = true)
|
private function generateClassMap($dir, $blacklist = null, $namespaceFilter = null, $autoloadType = null, $showAmbiguousWarning = true)
|
||||||
{
|
{
|
||||||
return ClassMapGenerator::createMap($dir, $blacklist, $showAmbiguousWarning ? $this->io : null, $namespaceFilter);
|
return ClassMapGenerator::createMap($dir, $blacklist, $showAmbiguousWarning ? $this->io : null, $namespaceFilter, $autoloadType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildPackageMap(InstallationManager $installationManager, PackageInterface $mainPackage, array $packages)
|
public function buildPackageMap(InstallationManager $installationManager, PackageInterface $mainPackage, array $packages)
|
||||||
|
@ -447,7 +446,7 @@ EOF;
|
||||||
|
|
||||||
foreach ($autoloads['classmap'] as $dir) {
|
foreach ($autoloads['classmap'] as $dir) {
|
||||||
try {
|
try {
|
||||||
$loader->addClassMap($this->generateClassMap($dir, $blacklist, null, false));
|
$loader->addClassMap($this->generateClassMap($dir, $blacklist, null, null, false));
|
||||||
} catch (\RuntimeException $e) {
|
} catch (\RuntimeException $e) {
|
||||||
$this->io->writeError('<warning>'.$e->getMessage().'</warning>');
|
$this->io->writeError('<warning>'.$e->getMessage().'</warning>');
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,17 +50,19 @@ class ClassMapGenerator
|
||||||
/**
|
/**
|
||||||
* Iterate over all files in the given directory searching for classes
|
* Iterate over all files in the given directory searching for classes
|
||||||
*
|
*
|
||||||
* @param \Iterator|string $path The path to search in or an iterator
|
* @param \Iterator|string $path The path to search in or an iterator
|
||||||
* @param string $blacklist Regex that matches against the file path that exclude from the classmap.
|
* @param string $blacklist Regex that matches against the file path that exclude from the classmap.
|
||||||
* @param IOInterface $io IO object
|
* @param IOInterface $io IO object
|
||||||
* @param string $namespace Optional namespace prefix to filter by
|
* @param string $namespace Optional namespace prefix to filter by
|
||||||
|
* @param string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException When the path is neither an existing file nor directory
|
* @throws \RuntimeException When the path is neither an existing file nor directory
|
||||||
* @return array A class map array
|
* @return array A class map array
|
||||||
*/
|
*/
|
||||||
public static function createMap($path, $blacklist = null, IOInterface $io = null, $namespace = null)
|
public static function createMap($path, $blacklist = null, IOInterface $io = null, $namespace = null, $autoloadType = null)
|
||||||
{
|
{
|
||||||
if (is_string($path)) {
|
if (is_string($path)) {
|
||||||
|
$basePath = $path;
|
||||||
if (is_file($path)) {
|
if (is_file($path)) {
|
||||||
$path = array(new \SplFileInfo($path));
|
$path = array(new \SplFileInfo($path));
|
||||||
} elseif (is_dir($path)) {
|
} elseif (is_dir($path)) {
|
||||||
|
@ -71,6 +73,8 @@ class ClassMapGenerator
|
||||||
'" which does not appear to be a file nor a folder'
|
'" which does not appear to be a file nor a folder'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} elseif (null !== $autoloadType) {
|
||||||
|
throw new \RuntimeException('Path must be a string when specifying an autoload type');
|
||||||
}
|
}
|
||||||
|
|
||||||
$map = array();
|
$map = array();
|
||||||
|
@ -100,10 +104,14 @@ class ClassMapGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
$classes = self::findClasses($filePath);
|
$classes = self::findClasses($filePath);
|
||||||
|
if (null !== $autoloadType) {
|
||||||
|
$classes = self::filterByNamespace($classes, $filePath, $namespace, $autoloadType, $basePath, $io);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
// skip classes not within the given namespace prefix
|
// skip classes not within the given namespace prefix
|
||||||
if (null !== $namespace && 0 !== strpos($class, $namespace)) {
|
// TODO enable in Composer v1.11 or 2.0 whichever comes first
|
||||||
|
if (/* null === $autoloadType && */ null !== $namespace && 0 !== strpos($class, $namespace)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +129,72 @@ class ClassMapGenerator
|
||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove classes which could not have been loaded by namespace autoloaders
|
||||||
|
*
|
||||||
|
* @param array $classes found classes in given file
|
||||||
|
* @param string $filePath current file
|
||||||
|
* @param string $baseNamespace prefix of given autoload mapping
|
||||||
|
* @param string $namespaceType psr-0|psr-4
|
||||||
|
* @param string $basePath root directory of given autoload mapping
|
||||||
|
* @param IOInterface $io IO object
|
||||||
|
* @return array valid classes
|
||||||
|
*/
|
||||||
|
private static function filterByNamespace($classes, $filePath, $baseNamespace, $namespaceType, $basePath, $io)
|
||||||
|
{
|
||||||
|
$validClasses = array();
|
||||||
|
$rejectedClasses = array();
|
||||||
|
|
||||||
|
$realSubPath = substr($filePath, strlen($basePath) + 1);
|
||||||
|
$realSubPath = substr($realSubPath, 0, strrpos($realSubPath, '.'));
|
||||||
|
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
// silently skip if ns doesn't have common root
|
||||||
|
if ('' !== $baseNamespace && 0 !== strpos($class, $baseNamespace)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// transform class name to file path and validate
|
||||||
|
if ('psr-0' === $namespaceType) {
|
||||||
|
$namespaceLength = strrpos($class, '\\');
|
||||||
|
if (false !== $namespaceLength) {
|
||||||
|
$namespace = substr($class, 0, $namespaceLength + 1);
|
||||||
|
$className = substr($class, $namespaceLength + 1);
|
||||||
|
$subPath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace)
|
||||||
|
. str_replace('_', DIRECTORY_SEPARATOR, $className);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$subPath = str_replace('_', DIRECTORY_SEPARATOR, $class);
|
||||||
|
}
|
||||||
|
} elseif ('psr-4' === $namespaceType) {
|
||||||
|
$subNamespace = ('' !== $baseNamespace) ? substr($class, strlen($baseNamespace)) : $class;
|
||||||
|
$subPath = str_replace('\\', DIRECTORY_SEPARATOR, $subNamespace);
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException("namespaceType must be psr-0 or psr-4, $namespaceType given");
|
||||||
|
}
|
||||||
|
if ($subPath === $realSubPath) {
|
||||||
|
$validClasses[] = $class;
|
||||||
|
} else {
|
||||||
|
$rejectedClasses[] = $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// warn only if no valid classes, else silently skip invalid
|
||||||
|
if (empty($validClasses)) {
|
||||||
|
foreach ($rejectedClasses as $class) {
|
||||||
|
trigger_error(
|
||||||
|
"Class $class located in ".preg_replace('{^'.preg_quote(getcwd()).'}', '.', $filePath, 1)." does not comply with $namespaceType autoloading standard. It will not autoload anymore in Composer v1.11+.",
|
||||||
|
E_USER_DEPRECATED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO enable in Composer v1.11 or 2.0 whichever comes first
|
||||||
|
//return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO enable in Composer v1.11 or 2.0 whichever comes first & unskip test in AutoloadGeneratorTest::testPSRToClassMapIgnoresNonPSRClasses
|
||||||
|
//return $validClasses;
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the classes in the given file
|
* Extract the classes in the given file
|
||||||
*
|
*
|
||||||
|
|
|
@ -63,11 +63,11 @@ EOT
|
||||||
$apcu = $input->getOption('apcu') || $config->get('apcu-autoloader');
|
$apcu = $input->getOption('apcu') || $config->get('apcu-autoloader');
|
||||||
|
|
||||||
if ($authoritative) {
|
if ($authoritative) {
|
||||||
$this->getIO()->writeError('<info>Generating optimized autoload files (authoritative)</info>', false);
|
$this->getIO()->write('<info>Generating optimized autoload files (authoritative)</info>');
|
||||||
} elseif ($optimize) {
|
} elseif ($optimize) {
|
||||||
$this->getIO()->writeError('<info>Generating optimized autoload files</info>', false);
|
$this->getIO()->write('<info>Generating optimized autoload files</info>');
|
||||||
} else {
|
} else {
|
||||||
$this->getIO()->writeError('<info>Generating autoload files</info>', false);
|
$this->getIO()->write('<info>Generating autoload files</info>');
|
||||||
}
|
}
|
||||||
|
|
||||||
$generator = $composer->getAutoloadGenerator();
|
$generator = $composer->getAutoloadGenerator();
|
||||||
|
@ -78,11 +78,11 @@ EOT
|
||||||
$numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
|
$numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
|
||||||
|
|
||||||
if ($authoritative) {
|
if ($authoritative) {
|
||||||
$this->getIO()->overwriteError('<info>Generated optimized autoload files (authoritative) containing '. $numberOfClasses .' classes</info>');
|
$this->getIO()->write('<info>Generated optimized autoload files (authoritative) containing '. $numberOfClasses .' classes</info>');
|
||||||
} elseif ($optimize) {
|
} elseif ($optimize) {
|
||||||
$this->getIO()->overwriteError('<info>Generated optimized autoload files containing '. $numberOfClasses .' classes</info>');
|
$this->getIO()->write('<info>Generated optimized autoload files containing '. $numberOfClasses .' classes</info>');
|
||||||
} else {
|
} else {
|
||||||
$this->getIO()->overwriteError('<info>Generated autoload files containing '. $numberOfClasses .' classes</info>');
|
$this->getIO()->write('<info>Generated autoload files containing '. $numberOfClasses .' classes</info>');
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -159,7 +159,15 @@ EOT
|
||||||
}
|
}
|
||||||
|
|
||||||
$phpVersion = $this->repos->findPackage('php', '*')->getPrettyVersion();
|
$phpVersion = $this->repos->findPackage('php', '*')->getPrettyVersion();
|
||||||
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability, !$input->getOption('no-update'), $input->getOption('fixed'));
|
try {
|
||||||
|
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability, !$input->getOption('no-update'), $input->getOption('fixed'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($this->newlyCreated) {
|
||||||
|
throw new \RuntimeException('No composer.json present in the current directory, this may be the cause of the following exception.', 0, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
$requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
|
$requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
|
||||||
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev';
|
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev';
|
||||||
|
|
|
@ -548,6 +548,48 @@ class AutoloadGeneratorTest extends TestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPSRToClassMapIgnoresNonPSRClasses()
|
||||||
|
{
|
||||||
|
$package = new Package('a', '1.0', '1.0');
|
||||||
|
|
||||||
|
$this->markTestSkipped('Skipped until ClassMapGenerator ignoring of invalid PSR-x classes is enabled');
|
||||||
|
|
||||||
|
$package->setAutoload(array(
|
||||||
|
'psr-0' => array('psr0_' => 'psr0/'),
|
||||||
|
'psr-4' => array('psr4\\' => 'psr4/'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->repository->expects($this->once())
|
||||||
|
->method('getCanonicalPackages')
|
||||||
|
->will($this->returnValue(array()));
|
||||||
|
|
||||||
|
$this->fs->ensureDirectoryExists($this->workingDir.'/psr0/psr0');
|
||||||
|
$this->fs->ensureDirectoryExists($this->workingDir.'/psr4');
|
||||||
|
file_put_contents($this->workingDir.'/psr0/psr0/match.php', '<?php class psr0_match {}');
|
||||||
|
file_put_contents($this->workingDir.'/psr0/psr0/badfile.php', '<?php class psr0_badclass {}');
|
||||||
|
file_put_contents($this->workingDir.'/psr4/match.php', '<?php namespace psr4; class match {}');
|
||||||
|
file_put_contents($this->workingDir.'/psr4/badfile.php', '<?php namespace psr4; class badclass {}');
|
||||||
|
|
||||||
|
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_1');
|
||||||
|
$this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated.");
|
||||||
|
|
||||||
|
$expectedClassmap = <<<EOF
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
\$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
\$baseDir = dirname(\$vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'psr0_match' => \$baseDir . '/psr0/psr0/match.php',
|
||||||
|
'psr4\\\\match' => \$baseDir . '/psr4/match.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
EOF;
|
||||||
|
$this->assertStringEqualsFile($this->vendorDir.'/composer/autoload_classmap.php', $expectedClassmap);
|
||||||
|
}
|
||||||
|
|
||||||
public function testVendorsClassMapAutoloading()
|
public function testVendorsClassMapAutoloading()
|
||||||
{
|
{
|
||||||
$package = new Package('a', '1.0', '1.0');
|
$package = new Package('a', '1.0', '1.0');
|
||||||
|
|
Loading…
Reference in New Issue