]> _ Git - couzy.git/blob
16592fc3e7a90b6ee49ba51802d3e5dfeda47309
[couzy.git] /
1 <?php
2 /*
3  * Copyright (c) 2013, Christoph Mewes, http://www.xrstf.de
4  *
5  * This file is released under the terms of the MIT license. You can find the
6  * complete text in the attached LICENSE file or online at:
7  *
8  * http://www.opensource.org/licenses/mit-license.php
9  *
10  * --------------------------------------------------------------------------
11  *
12  * 99% of this is copied as-is from the original Composer source code and is
13  * released under MIT license as well. Copyright goes to:
14  *
15  * - Igor Wiedler <igor@wiedler.ch>
16  * - Jordi Boggiano <j.boggiano@seld.be>
17  */
18
19 namespace xrstf\Composer52;
20
21 use Composer\Autoload\AutoloadGenerator as BaseGenerator;
22 use Composer\Autoload\ClassMapGenerator;
23 use Composer\Config;
24 use Composer\Installer\InstallationManager;
25 use Composer\Package\AliasPackage;
26 use Composer\Package\PackageInterface;
27 use Composer\Repository\InstalledRepositoryInterface;
28 use Composer\Util\Filesystem;
29
30 class AutoloadGenerator extends BaseGenerator {
31         public function __construct() {
32                 // do nothing (but keep this constructor so we can build an instance without the need for an event dispatcher)
33         }
34
35         public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsr0Packages = false, $suffix = '') {
36                 $filesystem = new Filesystem();
37                 $filesystem->ensureDirectoryExists($config->get('vendor-dir'));
38
39                 $cwd        = getcwd();
40                 $basePath   = $filesystem->normalizePath($cwd);
41                 $vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
42                 $targetDir  = $vendorPath.'/'.$targetDir;
43                 $filesystem->ensureDirectoryExists($targetDir);
44
45                 $useGlobalIncludePath  = (bool) $config->get('use-include-path');
46                 $prependAutoloader     = $config->get('prepend-autoloader') === false ? 'false' : 'true';
47                 $classMapAuthoritative = $config->get('classmap-authoritative');
48
49                 $vendorPathCode            = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
50                 $vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true);
51
52                 $appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true);
53                 $appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode);
54
55                 // add 5.2 compat
56                 $vendorPathCode            = str_replace('__DIR__', 'dirname(__FILE__)', $vendorPathCode);
57                 $vendorPathToTargetDirCode = str_replace('__DIR__', 'dirname(__FILE__)', $vendorPathToTargetDirCode);
58
59                 $packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages());
60                 $autoloads = $this->parseAutoloads($packageMap, $mainPackage);
61
62                 // add custom psr-0 autoloading if the root package has a target dir
63                 $targetDirLoader = null;
64                 $mainAutoload = $mainPackage->getAutoload();
65                 if ($mainPackage->getTargetDir() && !empty($mainAutoload['psr-0'])) {
66                         $levels   = count(explode('/', $filesystem->normalizePath($mainPackage->getTargetDir())));
67                         $prefixes = implode(', ', array_map(function ($prefix) {
68                                 return var_export($prefix, true);
69                         }, array_keys($mainAutoload['psr-0'])));
70
71                         $baseDirFromTargetDirCode = $filesystem->findShortestPathCode($targetDir, $basePath, true);
72
73                         $targetDirLoader = <<<EOF
74
75         public static function autoload(\$class) {
76                 \$dir      = $baseDirFromTargetDirCode.'/';
77                 \$prefixes = array($prefixes);
78
79                 foreach (\$prefixes as \$prefix) {
80                         if (0 !== strpos(\$class, \$prefix)) {
81                                 continue;
82                         }
83
84                         \$path = explode(DIRECTORY_SEPARATOR, self::getClassPath(\$class));
85                         \$path = \$dir.implode('/', array_slice(\$path, $levels));
86
87                         if (!\$path = self::resolveIncludePath(\$path)) {
88                                 return false;
89                         }
90
91                         require \$path;
92                         return true;
93                 }
94         }
95
96 EOF;
97                 }
98
99                 $filesCode = "";
100                 $autoloads['files'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['files']));
101                 foreach ($autoloads['files'] as $functionFile) {
102                         // don't include file if it is using PHP 5.3+ syntax
103                         // https://bitbucket.org/xrstf/composer-php52/issue/4
104                         if ($this->isPHP53($functionFile)) {
105                                 $filesCode .= '//               require '.$this->getPathCode($filesystem, $basePath, $vendorPath, $functionFile)."; // disabled because of PHP 5.3 syntax\n";
106                         }
107                         else {
108                                 $filesCode .= '         require '.$this->getPathCode($filesystem, $basePath, $vendorPath, $functionFile).";\n";
109                         }
110                 }
111
112                 if (!$suffix) {
113                         $suffix = md5(uniqid('', true));
114                 }
115
116                 $includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode);
117
118                 file_put_contents($vendorPath.'/autoload_52.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
119                 file_put_contents($targetDir.'/autoload_real_52.php', $this->getAutoloadRealFile(true, (bool) $includePathFile, $targetDirLoader, $filesCode, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $classMapAuthoritative));
120
121                 // use stream_copy_to_stream instead of copy
122                 // to work around https://bugs.php.net/bug.php?id=64634
123                 $sourceLoader = fopen(__DIR__.'/ClassLoader.php', 'r');
124                 $targetLoader = fopen($targetDir.'/ClassLoader52.php', 'w+');
125                 stream_copy_to_stream($sourceLoader, $targetLoader);
126                 fclose($sourceLoader);
127                 fclose($targetLoader);
128                 unset($sourceLoader, $targetLoader);
129         }
130
131         protected function isPHP53($file) {
132                 $tokens = token_get_all(file_get_contents($file));
133                 $php53  = array(T_DIR, T_GOTO, T_NAMESPACE, T_NS_C, T_NS_SEPARATOR, T_USE);
134
135                 // PHP 5.4+
136                 if (defined('T_TRAIT')) {
137                         $php53[] = T_TRAIT;
138                         $php53[] = T_TRAIT_C;
139                         $php53[] = T_TRAIT_C;
140                 }
141
142                 // PHP 5.5+
143                 if (defined('T_FINALLY')) {
144                         $php53[] = T_FINALLY;
145                         $php53[] = T_YIELD;
146                 }
147
148                 foreach ($tokens as $token) {
149                         if (is_array($token) && in_array($token[0], $php53)) {
150                                 return true;
151                         }
152                 }
153
154                 return false;
155         }
156
157         protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode) {
158                 $includePaths = array();
159
160                 foreach ($packageMap as $item) {
161                         list($package, $installPath) = $item;
162
163                         if (null !== $package->getTargetDir() && strlen($package->getTargetDir()) > 0) {
164                                 $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
165                         }
166
167                         foreach ($package->getIncludePaths() as $includePath) {
168                                 $includePath = trim($includePath, '/');
169                                 $includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath;
170                         }
171                 }
172
173                 if (!$includePaths) {
174                         return;
175                 }
176
177                 $includePathsFile = <<<EOF
178 <?php
179
180 // include_paths_52.php generated by xrstf/composer-php52
181
182 \$vendorDir = $vendorPathCode;
183 \$baseDir = $appBaseDirCode;
184
185 return array(
186
187 EOF;
188
189                 foreach ($includePaths as $path) {
190                         $includePathsFile .= "\t" . $this->getPathCode($filesystem, $basePath, $vendorPath, $path) . ",\n";
191                 }
192
193                 return $includePathsFile . ");\n";
194         }
195
196         protected function getAutoloadFile($vendorPathToTargetDirCode, $suffix) {
197                 return <<<AUTOLOAD
198 <?php
199
200 // autoload_52.php generated by xrstf/composer-php52
201
202 require_once $vendorPathToTargetDirCode.'/autoload_real_52.php';
203
204 return ComposerAutoloaderInit$suffix::getLoader();
205
206 AUTOLOAD;
207         }
208
209         protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $filesCode, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $classMapAuthoritative) {
210                 // TODO the class ComposerAutoloaderInit should be revert to a closure
211                 // when APC has been fixed:
212                 // - https://github.com/composer/composer/issues/959
213                 // - https://bugs.php.net/bug.php?id=52144
214                 // - https://bugs.php.net/bug.php?id=61576
215                 // - https://bugs.php.net/bug.php?id=59298
216
217                 if ($filesCode) {
218                                 $filesCode = "\n\n".rtrim($filesCode);
219                 }
220
221                 $file = <<<HEADER
222 <?php
223
224 // autoload_real_52.php generated by xrstf/composer-php52
225
226 class ComposerAutoloaderInit$suffix {
227         private static \$loader;
228
229         public static function loadClassLoader(\$class) {
230                 if ('xrstf_Composer52_ClassLoader' === \$class) {
231                         require dirname(__FILE__).'/ClassLoader52.php';
232                 }
233         }
234
235         /**
236          * @return xrstf_Composer52_ClassLoader
237          */
238         public static function getLoader() {
239                 if (null !== self::\$loader) {
240                         return self::\$loader;
241                 }
242
243                 spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'), true /*, true */);
244                 self::\$loader = \$loader = new xrstf_Composer52_ClassLoader();
245                 spl_autoload_unregister(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'));
246
247                 \$vendorDir = $vendorPathCode;
248                 \$baseDir   = $appBaseDirCode;
249                 \$dir       = dirname(__FILE__);
250
251
252 HEADER;
253
254                 if ($useIncludePath) {
255                         $file .= <<<'INCLUDE_PATH'
256                 $includePaths = require $dir.'/include_paths.php';
257                 array_push($includePaths, get_include_path());
258                 set_include_path(implode(PATH_SEPARATOR, $includePaths));
259
260
261 INCLUDE_PATH;
262                 }
263
264                 $file .= <<<'PSR0'
265                 $map = require $dir.'/autoload_namespaces.php';
266                 foreach ($map as $namespace => $path) {
267                         $loader->add($namespace, $path);
268                 }
269
270
271 PSR0;
272
273                 if ($useClassMap) {
274                         $file .= <<<'CLASSMAP'
275                 $classMap = require $dir.'/autoload_classmap.php';
276                 if ($classMap) {
277                         $loader->addClassMap($classMap);
278                 }
279
280
281 CLASSMAP;
282                 }
283
284                 if ($classMapAuthoritative) {
285                         $file .= <<<'CLASSMAPAUTHORITATIVE'
286                 $loader->setClassMapAuthoritative(true);
287
288 CLASSMAPAUTHORITATIVE;
289                 }
290
291                 if ($useGlobalIncludePath) {
292                         $file .= <<<'INCLUDEPATH'
293                 $loader->setUseIncludePath(true);
294
295
296 INCLUDEPATH;
297                 }
298
299                 if ($targetDirLoader) {
300                         $file .= <<<REGISTER_AUTOLOAD
301                 spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'autoload'), true);
302
303
304 REGISTER_AUTOLOAD;
305
306                 }
307
308                 $file .= <<<METHOD_FOOTER
309                 \$loader->register($prependAutoloader);{$filesCode}
310
311                 return \$loader;
312         }
313
314 METHOD_FOOTER;
315
316                 $file .= $targetDirLoader;
317
318                 return $file . <<<FOOTER
319 }
320
321 FOOTER;
322
323         }
324 }