1
0
Fork 0

Merge pull request #3610 from bd808/feature/classmap-authoritative

Add classmap-authoritative config setting
pull/3688/head
Nils Adermann 2015-01-28 11:26:28 +01:00
commit 0543a32d39
10 changed files with 116 additions and 18 deletions

View File

@ -790,6 +790,9 @@ The following options are supported:
the generated Composer autoloader. When null a random one will be generated.
* **optimize-autoloader** Defaults to `false`. Always optimize when dumping
the autoloader.
* **classmap-authoritative:** Defaults to `false`. If true, the composer
autoloader will not scan the filesystem for classes that are not found in
the class map. Implies 'optimize-autoloader'.
* **github-domains:** Defaults to `["github.com"]`. A list of domains to use in
github mode. This is used for GitHub Enterprise setups.
* **github-expose-hostname:** Defaults to `true`. If set to false, the OAuth

View File

@ -197,6 +197,10 @@
"type": "boolean",
"description": "If false, the composer autoloader will not be prepended to existing autoloaders, defaults to true."
},
"classmap-authoritative": {
"type": "boolean",
"description": "If true, the composer autoloader will not scan the filesystem for classes that are not found in the class map, defaults to false."
},
"github-domains": {
"type": "array",
"description": "A list of domains to use in github mode. This is used for GitHub Enterprise setups, defaults to [\"github.com\"].",

View File

@ -63,6 +63,7 @@ class AutoloadGenerator
$vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
$useGlobalIncludePath = (bool) $config->get('use-include-path');
$prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true';
$classMapAuthoritative = $config->get('classmap-authoritative');
$targetDir = $vendorPath.'/'.$targetDir;
$filesystem->ensureDirectoryExists($targetDir);
@ -226,7 +227,7 @@ EOF;
file_put_contents($targetDir.'/autoload_files.php', $includeFilesFile);
}
file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFile, $targetDirLoader, (bool) $includeFilesFile, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader));
file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFile, $targetDirLoader, (bool) $includeFilesFile, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $classMapAuthoritative));
// use stream_copy_to_stream instead of copy
// to work around https://bugs.php.net/bug.php?id=64634
@ -443,7 +444,7 @@ return ComposerAutoloaderInit$suffix::getLoader();
AUTOLOAD;
}
protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader)
protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $classMapAuthoritative)
{
// TODO the class ComposerAutoloaderInit should be revert to a closure
// when APC has been fixed:
@ -520,6 +521,13 @@ PSR4;
CLASSMAP;
}
if ($classMapAuthoritative) {
$file .= <<<'CLASSMAPAUTHORITATIVE'
$loader->setClassMapAuthoritative(true);
CLASSMAPAUTHORITATIVE;
}
if ($useGlobalIncludePath) {
$file .= <<<'INCLUDEPATH'
$loader->setUseIncludePath(true);

View File

@ -54,6 +54,8 @@ class ClassLoader
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
@ -248,6 +250,27 @@ class ClassLoader
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* Registers this instance as an autoloader.
*
@ -299,6 +322,9 @@ class ClassLoader
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');

View File

@ -325,6 +325,7 @@ EOT
),
'autoloader-suffix' => array('is_string', function ($val) { return $val === 'null' ? null : $val; }),
'optimize-autoloader' => array($booleanValidator, $booleanNormalizer),
'classmap-authoritative' => array($booleanValidator, $booleanNormalizer),
'prepend-autoloader' => array($booleanValidator, $booleanNormalizer),
'github-expose-hostname' => array($booleanValidator, $booleanNormalizer),
);

View File

@ -52,7 +52,7 @@ EOT
$package = $composer->getPackage();
$config = $composer->getConfig();
$optimize = $input->getOption('optimize') || $config->get('optimize-autoloader');
$optimize = $input->getOption('optimize') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
if ($optimize) {
$output->writeln('<info>Generating optimized autoload files</info>');

View File

@ -106,7 +106,7 @@ EOT
$preferDist = $input->getOption('prefer-dist');
}
$optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
$optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
$install
->setDryRun($input->getOption('dry-run'))

View File

@ -110,7 +110,7 @@ EOT
$preferDist = $input->getOption('prefer-dist');
}
$optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
$optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
$install
->setDryRun($input->getOption('dry-run'))

View File

@ -39,6 +39,7 @@ class Config
'discard-changes' => false,
'autoloader-suffix' => null,
'optimize-autoloader' => false,
'classmap-authoritative' => false,
'prepend-autoloader' => true,
'github-domains' => array('github.com'),
'github-expose-hostname' => true,

View File

@ -67,6 +67,17 @@ class AutoloadGeneratorTest extends TestCase
*/
private $eventDispatcher;
/**
* Map of setting name => return value configuration for the stub Config
* object.
*
* Note: must be public for compatibility with PHP 5.3 runtimes where
* closures cannot access private members of the classes they are created
* in.
* @var array
*/
public $configValueMap;
protected function setUp()
{
$this->fs = new Filesystem;
@ -79,18 +90,23 @@ class AutoloadGeneratorTest extends TestCase
$this->config = $this->getMock('Composer\Config');
$this->config->expects($this->at(0))
->method('get')
->with($this->equalTo('vendor-dir'))
->will($this->returnCallback(function () use ($that) {
$this->configValueMap = array(
'vendor-dir' => function () use ($that) {
return $that->vendorDir;
}));
},
);
$this->config->expects($this->at(1))
$this->config->expects($this->atLeastOnce())
->method('get')
->with($this->equalTo('vendor-dir'))
->will($this->returnCallback(function () use ($that) {
return $that->vendorDir;
->will($this->returnCallback(function ($arg) use ($that) {
$ret = null;
if (isset($that->configValueMap[$arg])) {
$ret = $that->configValueMap[$arg];
if (is_callable($ret)) {
$ret = $ret();
}
}
return $ret;
}));
$this->origDir = getcwd();
@ -483,6 +499,48 @@ class AutoloadGeneratorTest extends TestCase
include $this->vendorDir.'/composer/autoload_classmap.php'
);
$this->assertAutoloadFiles('classmap5', $this->vendorDir.'/composer', 'classmap');
$this->assertNotContains('$loader->setClassMapAuthoritative(true);', file_get_contents($this->vendorDir.'/composer/autoload_real.php'));
}
public function testClassMapAutoloadingAuthoritative()
{
$package = new Package('a', '1.0', '1.0');
$packages = array();
$packages[] = $a = new Package('a/a', '1.0', '1.0');
$packages[] = $b = new Package('b/b', '1.0', '1.0');
$packages[] = $c = new Package('c/c', '1.0', '1.0');
$a->setAutoload(array('classmap' => array('')));
$b->setAutoload(array('classmap' => array('test.php')));
$c->setAutoload(array('classmap' => array('./')));
$this->repository->expects($this->once())
->method('getCanonicalPackages')
->will($this->returnValue($packages));
$this->configValueMap['classmap-authoritative'] = true;
$this->fs->ensureDirectoryExists($this->vendorDir.'/composer');
$this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/src');
$this->fs->ensureDirectoryExists($this->vendorDir.'/b/b');
$this->fs->ensureDirectoryExists($this->vendorDir.'/c/c/foo');
file_put_contents($this->vendorDir.'/a/a/src/a.php', '<?php class ClassMapFoo {}');
file_put_contents($this->vendorDir.'/b/b/test.php', '<?php class ClassMapBar {}');
file_put_contents($this->vendorDir.'/c/c/foo/test.php', '<?php class ClassMapBaz {}');
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_7');
$this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->assertEquals(
array(
'ClassMapBar' => $this->vendorDir.'/b/b/test.php',
'ClassMapBaz' => $this->vendorDir.'/c/c/foo/test.php',
'ClassMapFoo' => $this->vendorDir.'/a/a/src/a.php',
),
include $this->vendorDir.'/composer/autoload_classmap.php'
);
$this->assertAutoloadFiles('classmap5', $this->vendorDir.'/composer', 'classmap');
$this->assertContains('$loader->setClassMapAuthoritative(true);', file_get_contents($this->vendorDir.'/composer/autoload_real.php'));
}
public function testFilesAutoloadGeneration()
@ -829,10 +887,7 @@ EOF;
->method('getCanonicalPackages')
->will($this->returnValue(array()));
$this->config->expects($this->at(2))
->method('get')
->with($this->equalTo('use-include-path'))
->will($this->returnValue(true));
$this->configValueMap['use-include-path'] = true;
$this->fs->ensureDirectoryExists($this->vendorDir.'/a');