diff --git a/compiler/compiler-core.cpp b/compiler/compiler-core.cpp index 420bfe28c8..1f9fccaf64 100644 --- a/compiler/compiler-core.cpp +++ b/compiler/compiler-core.cpp @@ -4,11 +4,8 @@ #include "compiler/compiler-core.h" -#include - #include "common/algorithms/contains.h" #include "common/wrappers/mkdir_recursive.h" -#include "common/smart_ptrs/unique_ptr_with_delete_function.h" #include "compiler/const-manipulations.h" #include "compiler/data/ffi-data.h" @@ -18,80 +15,6 @@ #include "compiler/data/src-file.h" #include "compiler/name-gen.h" -namespace { - -void close_dir(DIR *d) { - closedir(d); -} - -void collect_composer_folders(const std::string &path, std::vector &result) { - // can't use nftw here as it doesn't provide a portable way to stop directory traversal; - // we don't want to visit *all* files in the vendor tree - // - // suppose we have this composer-generated layout: - // vendor/pkg1/ - // * composer.json - // * src/ - // vendor/ns/pkg2/ - // * composer.json - // * src/ - // all pkg directories can have a lot of files inside src/, - // if we can stop as soon as we find composer.json, a lot of - // redundant work is avoided - - vk::unique_ptr_with_delete_function dp{opendir(path.c_str())}; - if (dp == nullptr) { - kphp_warning(fmt_format("find composer files: opendir({}) failed: {}", path.c_str(), strerror(errno))); - return; - } - - // since composer package can't have nested composer.json file, we stop - // directory traversal if we found it; otherwise we descend further; - // dirs contains all directories that we need to visit when descending - bool recurse = true; - std::vector dirs; - - while (const auto *entry = readdir(dp.get())) { - if (entry->d_name[0] == '.') { - continue; - } - - if (std::strcmp(entry->d_name, "composer.json") == 0) { - result.push_back(path); - recurse = false; - break; - } - - // by default, composer does no copy for packages; it creates a symlink instead - if (entry->d_type == DT_LNK) { - // collect only those links that point to a directory - auto link_path = path + "/" + entry->d_name; - struct stat link_info; - stat(link_path.c_str(), &link_info); - if (S_ISDIR(link_info.st_mode)) { - dirs.push_back(std::move(link_path)); - } - } else if (entry->d_type == DT_DIR) { - dirs.emplace_back(path + "/" + entry->d_name); - } - } - - if (recurse) { - for (const auto &dir : dirs) { - collect_composer_folders(dir, result); - } - } -} - -// Collect all composer.json file roots that can be found in the given directory. -std::vector find_composer_folders(const std::string &dir) { - std::vector result; - collect_composer_folders(dir, result); - return result; -} - -} - static FunctionPtr UNPARSED_BUT_REQUIRED_FUNC_PTR = FunctionPtr(reinterpret_cast(0x0001)); CompilerCore::CompilerCore() : @@ -532,24 +455,7 @@ void CompilerCore::init_composer_class_loader() { } composer_class_loader.set_use_dev(settings().composer_autoload_dev.get()); - - composer_class_loader.load_root_file(settings().composer_root.get()); - - // We could traverse the composer file and collect all "repositories" - // and map them with "requirements" to get the dependency list, - // but some projects may use composer plugins that change composer - // files before "composer install" is invoked, so the final vendor - // folder may be generated from files that differ from the composer - // files that we can reach. To avoid that problem, we scan the vendor - // folder in order to collect all dependencies (both direct and indirect). - - std::string vendor = settings().composer_root.get() + "vendor"; - bool vendor_folder_exists = access(vendor.c_str(), F_OK) == 0; - if (vendor_folder_exists) { - for (const auto &composer_root : find_composer_folders(vendor)) { - composer_class_loader.load_file(composer_root); - } - } + composer_class_loader.load(settings().composer_root.get()); } diff --git a/compiler/composer.cpp b/compiler/composer.cpp index 637c90e610..97fa7d5d49 100644 --- a/compiler/composer.cpp +++ b/compiler/composer.cpp @@ -6,11 +6,128 @@ #include // using YAML parser to handle JSON files +#include +#include // TODO: remove when std::filesystem is used everywhere instead of stat +#include + +#include "common/smart_ptrs/unique_ptr_with_delete_function.h" #include "common/algorithms/contains.h" #include "common/wrappers/fmt_format.h" #include "compiler/kphp_assert.h" #include "compiler/stage.h" +namespace { + +void close_dir(DIR *d) { + closedir(d); +} + +void collect_composer_folders(const std::string &path, std::vector &result) { + // can't use nftw here as it doesn't provide a portable way to stop directory traversal; + // we don't want to visit *all* files in the vendor tree + // + // suppose we have this composer-generated layout: + // vendor/pkg1/ + // * composer.json + // * src/ + // vendor/ns/pkg2/ + // * composer.json + // * src/ + // all pkg directories can have a lot of files inside src/, + // if we can stop as soon as we find composer.json, a lot of + // redundant work is avoided + // + // TODO: rewrite using C++17 filesystem? + + vk::unique_ptr_with_delete_function dp{opendir(path.c_str())}; + if (dp == nullptr) { + kphp_warning(fmt_format("find composer files: opendir({}) failed: {}", path.c_str(), strerror(errno))); + return; + } + + // since composer package can't have nested composer.json file, we stop + // directory traversal if we found it; otherwise we descend further; + // dirs contains all directories that we need to visit when descending + bool recurse = true; + std::vector dirs; + + while (const auto *entry = readdir(dp.get())) { + if (entry->d_name[0] == '.') { + continue; + } + + if (std::strcmp(entry->d_name, "composer.json") == 0) { + result.push_back(path); + recurse = false; + break; + } + + // by default, composer does no copy for packages; it creates a symlink instead + if (entry->d_type == DT_LNK) { + // collect only those links that point to a directory + auto link_path = path + "/" + entry->d_name + "/"; + struct stat link_info; + stat(link_path.c_str(), &link_info); + if (S_ISDIR(link_info.st_mode)) { + dirs.push_back(std::move(link_path)); + } + } else if (entry->d_type == DT_DIR) { + dirs.emplace_back(path + "/" + entry->d_name + "/"); + } + } + + if (recurse) { + for (const auto &dir : dirs) { + collect_composer_folders(dir, result); + } + } +} + +// Collect all composer.json file roots that can be found in the given directory. +std::vector find_composer_folders(const std::string &dir) { + std::vector result; + collect_composer_folders(dir, result); + return result; +} + +} // namespace + +bool ComposerAutoloader::is_classmap_file(const std::string &filename) const noexcept { + return vk::contains(classmap_files_, filename); +} + +void ComposerAutoloader::scan_classmap(const std::string &filename) { + // supporting the real composer classmap is cumbersome: it requires full PHP parsing to + // fetch all classes from files (the filename doesn't have to follow any conventions); + // we could also invoke php interpreter over vendor/composer/autoload_classmap.php to + // print a JSON dump of the generated classmap and then decode that, but then + // it will be impossible to compile a kphp program that uses a classmap without php interpreter; + // as an alternative, we add all classmap files to auto-required lists that will be + // included along "autoload.files" files, if some classes are not needed, they will be + // discarded after we compute actually used symbols + // + // this approach works well as long as there is no significant side effects related to + // the files being autoloaded (otherwise those side effects will trigger at different point in time) + + const auto add_classmap_file = [&](const std::string &filename) { + classmap_files_.insert(filename); + files_to_require_.emplace_back(filename); + }; + + auto file_info = std::filesystem::status(filename); + kphp_error(file_info.type() != std::filesystem::file_type::not_found, + fmt_format("can't find {} classmap file", filename)); + if (file_info.type() == std::filesystem::file_type::directory) { + for (const auto &entry : std::filesystem::directory_iterator(filename)) { + scan_classmap(entry.path().string()); + } + } else if (file_info.type() == std::filesystem::file_type::regular) { + if (vk::string_view(filename).ends_with(".php") || vk::string_view(filename).ends_with(".inc")) { + add_classmap_file(filename); + } + } +} + std::string ComposerAutoloader::psr4_lookup_nocache(const std::string &class_name) const { std::string prefix = class_name; @@ -84,6 +201,26 @@ void ComposerAutoloader::set_use_dev(bool v) { use_dev_ = v; } +void ComposerAutoloader::load(const std::string &pkg_root) { + load_root_file(pkg_root); + + // We could traverse the composer file and collect all "repositories" + // and map them with "requirements" to get the dependency list, + // but some projects may use composer plugins that change composer + // files before "composer install" is invoked, so the final vendor + // folder may be generated from files that differ from the composer + // files that we can reach. To avoid that problem, we scan the vendor + // folder in order to collect all dependencies (both direct and indirect). + + std::string vendor = pkg_root + "vendor"; + bool vendor_folder_exists = access(vendor.c_str(), F_OK) == 0; + if (vendor_folder_exists) { + for (const auto &composer_root : find_composer_folders(vendor)) { + load_file(composer_root); + } + } +} + void ComposerAutoloader::load_root_file(const std::string &pkg_root) { kphp_assert(!pkg_root.empty() && pkg_root.back() == '/'); kphp_assert(autoload_filename_.empty()); @@ -119,6 +256,11 @@ void ComposerAutoloader::load_file(const std::string &pkg_root, bool is_root_fil // "": "fallback-dir/", // <...> // }, + // "classmap": [ + // "src/", + // "lib/file.php", + // <...> + // ], // "files": [ // "file.php", // <...> @@ -136,9 +278,9 @@ void ComposerAutoloader::load_file(const std::string &pkg_root, bool is_root_fil // } // } - auto filename = pkg_root + "/composer.json"; + auto filename = pkg_root + "composer.json"; - auto add_autoload_dir = [&](const std::string &prefix, std::string dir) { + auto add_autoload_psr4_dir = [&](const std::string &prefix, std::string dir) { if (dir.empty()) { dir = "./"; // composer interprets "" as "./" or "." } @@ -148,7 +290,7 @@ void ComposerAutoloader::load_file(const std::string &pkg_root, bool is_root_fil dir.push_back('/'); } - autoload_psr4_[prefix].emplace_back(pkg_root + "/" + dir); + autoload_psr4_[prefix].emplace_back(pkg_root + dir); }; auto add_autoload_section = [&](YAML::Node autoload, bool require_files) { @@ -160,20 +302,26 @@ void ComposerAutoloader::load_file(const std::string &pkg_root, bool is_root_fil if (kv.second.IsSequence()) { for (const auto &dir : kv.second) { - add_autoload_dir(prefix, dir.as()); + add_autoload_psr4_dir(prefix, dir.as()); } } else if (kv.second.IsScalar()) { - add_autoload_dir(prefix, kv.second.as()); + add_autoload_psr4_dir(prefix, kv.second.as()); } else { kphp_error(false, fmt_format("load composer file {}: invalid autoload psr-4 item", filename.c_str())); } } + // https://getcomposer.org/doc/04-schema.md#classmap + const auto classmap_src = autoload["classmap"]; + for (const auto &elem : classmap_src) { + scan_classmap(pkg_root + elem.as()); + } + if (require_files) { // files that are required by the composer-generated autoload.php // https://getcomposer.org/doc/04-schema.md#files for (const auto &autoload_filename : autoload["files"]) { - files_to_require_.emplace_back(pkg_root + "/" + autoload_filename.as()); + files_to_require_.emplace_back(pkg_root + autoload_filename.as()); } } }; diff --git a/compiler/composer.h b/compiler/composer.h index c6bea46c08..b3d20d112e 100644 --- a/compiler/composer.h +++ b/compiler/composer.h @@ -22,15 +22,7 @@ class ComposerAutoloader : private vk::not_copyable { // inverse of the `composer --no-dev` option void set_use_dev(bool v); - // load_file parses the "$pkg_root/composer.json" file and saves - // all relevant definitions inside loader; - // this method is not thread-safe and should be called only during the compiler init - void load_file(const std::string &pkg_root); - - // load_root_file is like load_file, but should be only used - // for the main composer file; - // this method is not thread-safe and should be called only during the compiler init - void load_root_file(const std::string &pkg_root); + void load(const std::string&); // psr4_lookup tries to find a filename that should contain // a class class_name; the lookup is based on the loaded @@ -43,17 +35,31 @@ class ComposerAutoloader : private vk::not_copyable { return filename == autoload_filename_; } + bool is_classmap_file(const std::string &filename) const noexcept; + const std::vector &get_files_to_require() const noexcept { return files_to_require_; } private: + // load_file parses the "$pkg_root/composer.json" file and saves + // all relevant definitions inside loader; + // this method is not thread-safe and should be called only during the compiler init + void load_file(const std::string &pkg_root); + + // load_root_file is like load_file, but should be only used + // for the main composer file; + // this method is not thread-safe and should be called only during the compiler init + void load_root_file(const std::string &pkg_root); + void load_file(const std::string &filename, bool root); std::string psr4_lookup_nocache(const std::string &class_name) const; + void scan_classmap(const std::string &filename); bool use_dev_; std::map, std::less<>> autoload_psr4_; std::unordered_set deps_; + std::unordered_set classmap_files_; std::string autoload_filename_; std::vector files_to_require_; diff --git a/compiler/data/class-data.cpp b/compiler/data/class-data.cpp index ef7a52244e..ff4c3cc068 100644 --- a/compiler/data/class-data.cpp +++ b/compiler/data/class-data.cpp @@ -41,7 +41,8 @@ void ClassData::set_name_and_src_name(const std::string &full_name) { std::string namespace_name = pos == std::string::npos ? "" : full_name.substr(0, pos); std::string class_name = pos == std::string::npos ? full_name : full_name.substr(pos + 1); - this->can_be_php_autoloaded = file_id && namespace_name == file_id->namespace_name && class_name == file_id->short_file_name; + this->can_be_php_autoloaded = file_id && ((namespace_name == file_id->namespace_name && class_name == file_id->short_file_name) || + (G->get_composer_autoloader().is_classmap_file(file_id->file_name))); this->can_be_php_autoloaded |= this->is_builtin(); this->is_lambda = vk::string_view{full_name}.starts_with("Lambda$") || vk::string_view{full_name}.starts_with("ITyped$"); diff --git a/tests/python/tests/composer/php/classmap/classmap_lib.php b/tests/python/tests/composer/php/classmap/classmap_lib.php new file mode 100644 index 0000000000..553bbaaf28 --- /dev/null +++ b/tests/python/tests/composer/php/classmap/classmap_lib.php @@ -0,0 +1,11 @@ +value); +$classmap_c2 = new \ClassmapLib\Classes\ClassmapClass2(); +var_dump($classmap_c2->value); +$classmap_c3 = new ClassmapNoNamespace(); +$classmap_c3->f(); +$classmap_c4 = new \OtherClassmap\OtherClassmapClass(); +$classmap_c4->g(); + $controller = new Controller(); $t = new FeedTester(); diff --git a/tests/python/tests/composer/php/vendor/composer/ClassLoader.php b/tests/python/tests/composer/php/vendor/composer/ClassLoader.php index dc02dfb114..afef3fa2ad 100644 --- a/tests/python/tests/composer/php/vendor/composer/ClassLoader.php +++ b/tests/python/tests/composer/php/vendor/composer/ClassLoader.php @@ -37,57 +37,130 @@ * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { + /** @var ?string */ + private $vendorDir; + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr4 = array(); // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr0 = array(); + /** @var bool */ private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ private $classMap = array(); + + /** @var bool */ private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ private $missingClasses = array(); + + /** @var ?string */ private $apcuPrefix; + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + /** + * @return string[] + */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } + /** + * @return array[] + * @psalm-return array> + */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } + /** + * @return string[] Array of classname => path + * @psalm-return array + */ public function getClassMap() { return $this->classMap; } /** - * @param array $classMap Class to filename map + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void */ public function addClassMap(array $classMap) { @@ -102,9 +175,11 @@ public function addClassMap(array $classMap) * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void */ public function add($prefix, $paths, $prepend = false) { @@ -147,11 +222,13 @@ public function add($prefix, $paths, $prepend = false) * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException + * + * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -195,8 +272,10 @@ public function addPsr4($prefix, $paths, $prepend = false) * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void */ public function set($prefix, $paths) { @@ -211,10 +290,12 @@ public function set($prefix, $paths) * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException + * + * @return void */ public function setPsr4($prefix, $paths) { @@ -234,6 +315,8 @@ public function setPsr4($prefix, $paths) * Turns on searching the include path for class files. * * @param bool $useIncludePath + * + * @return void */ public function setUseIncludePath($useIncludePath) { @@ -256,6 +339,8 @@ public function getUseIncludePath() * that have not been registered with the class map. * * @param bool $classMapAuthoritative + * + * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -276,10 +361,12 @@ public function isClassMapAuthoritative() * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix + * + * @return void */ public function setApcuPrefix($apcuPrefix) { - $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** @@ -296,25 +383,44 @@ public function getApcuPrefix() * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } } /** * Unregisters this instance as an autoloader. + * + * @return void */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } } /** * Loads the given class or interface. * * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { @@ -323,6 +429,8 @@ public function loadClass($class) return true; } + + return null; } /** @@ -367,6 +475,21 @@ public function findFile($class) return $file; } + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -377,7 +500,7 @@ private function findFileWithExtension($class, $ext) $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); - $search = $subPath.'\\'; + $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { @@ -438,6 +561,10 @@ private function findFileWithExtension($class, $ext) * Scope isolated include. * * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private */ function includeFile($file) { diff --git a/tests/python/tests/composer/php/vendor/composer/LICENSE b/tests/python/tests/composer/php/vendor/composer/LICENSE index f0157a6ed0..f27399a042 100644 --- a/tests/python/tests/composer/php/vendor/composer/LICENSE +++ b/tests/python/tests/composer/php/vendor/composer/LICENSE @@ -1,56 +1,21 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Composer -Upstream-Contact: Jordi Boggiano -Source: https://github.com/composer/composer -Files: * -Copyright: 2016, Nils Adermann - 2016, Jordi Boggiano -License: Expat +Copyright (c) Nils Adermann, Jordi Boggiano -Files: src/Composer/Util/TlsHelper.php -Copyright: 2016, Nils Adermann - 2016, Jordi Boggiano - 2013, Evan Coury -License: Expat and BSD-2-Clause +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: -License: BSD-2-Clause - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - . - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - . - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. -License: Expat - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is furnished - to do so, subject to the following conditions: - . - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - . - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. diff --git a/tests/python/tests/composer/php/vendor/composer/autoload_classmap.php b/tests/python/tests/composer/php/vendor/composer/autoload_classmap.php index 7a91153b0d..4a112bfc89 100644 --- a/tests/python/tests/composer/php/vendor/composer/autoload_classmap.php +++ b/tests/python/tests/composer/php/vendor/composer/autoload_classmap.php @@ -6,4 +6,9 @@ $baseDir = dirname($vendorDir); return array( + 'ClassmapLib\\Classes\\ClassmapClass1' => $baseDir . '/classmap/classmap_lib.php', + 'ClassmapLib\\Classes\\ClassmapClass2' => $baseDir . '/classmap/classmap_lib.php', + 'ClassmapNoNamespace' => $baseDir . '/classmap/classmap_no_namespace.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'OtherClassmap\\OtherClassmapClass' => $baseDir . '/classmap/dir/classmap.php', ); diff --git a/tests/python/tests/composer/php/vendor/composer/autoload_real.php b/tests/python/tests/composer/php/vendor/composer/autoload_real.php index cfaa1bbbc1..087f3993cc 100644 --- a/tests/python/tests/composer/php/vendor/composer/autoload_real.php +++ b/tests/python/tests/composer/php/vendor/composer/autoload_real.php @@ -13,6 +13,9 @@ public static function loadClassLoader($class) } } + /** + * @return \Composer\Autoload\ClassLoader + */ public static function getLoader() { if (null !== self::$loader) { @@ -20,12 +23,12 @@ public static function getLoader() } spl_autoload_register(array('ComposerAutoloaderInit9539f736c30192217f7a8384c08769a6', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInit9539f736c30192217f7a8384c08769a6', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; + require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInit9539f736c30192217f7a8384c08769a6::getInitializer($loader)); } else { diff --git a/tests/python/tests/composer/php/vendor/composer/autoload_static.php b/tests/python/tests/composer/php/vendor/composer/autoload_static.php index cd31e9808b..fbf8708fe1 100644 --- a/tests/python/tests/composer/php/vendor/composer/autoload_static.php +++ b/tests/python/tests/composer/php/vendor/composer/autoload_static.php @@ -50,12 +50,21 @@ class ComposerStaticInit9539f736c30192217f7a8384c08769a6 1 => __DIR__ . '/..' . '/vk/utils/utils-fallback/src', ); + public static $classMap = array ( + 'ClassmapLib\\Classes\\ClassmapClass1' => __DIR__ . '/../..' . '/classmap/classmap_lib.php', + 'ClassmapLib\\Classes\\ClassmapClass2' => __DIR__ . '/../..' . '/classmap/classmap_lib.php', + 'ClassmapNoNamespace' => __DIR__ . '/../..' . '/classmap/classmap_no_namespace.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'OtherClassmap\\OtherClassmapClass' => __DIR__ . '/../..' . '/classmap/dir/classmap.php', + ); + public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInit9539f736c30192217f7a8384c08769a6::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit9539f736c30192217f7a8384c08769a6::$prefixDirsPsr4; $loader->fallbackDirsPsr4 = ComposerStaticInit9539f736c30192217f7a8384c08769a6::$fallbackDirsPsr4; + $loader->classMap = ComposerStaticInit9539f736c30192217f7a8384c08769a6::$classMap; }, null, ClassLoader::class); } diff --git a/tests/python/tests/composer/php/vendor/composer/installed.json b/tests/python/tests/composer/php/vendor/composer/installed.json index 4421498f4d..83c366be7a 100644 --- a/tests/python/tests/composer/php/vendor/composer/installed.json +++ b/tests/python/tests/composer/php/vendor/composer/installed.json @@ -1,60 +1,73 @@ -[ - { - "name": "vk/pkg1", - "version": "1.0.0", - "version_normalized": "1.0.0.0", - "dist": { - "type": "path", - "url": "./packages/pkg1", - "reference": "cad9181dd719b2300857994e3f139a3537295184", - "shasum": null +{ + "packages": [ + { + "name": "vk/pkg1", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "dist": { + "type": "path", + "url": "./packages/pkg1", + "reference": "c815828c6fde4469dddb6f0df1057dc308af767d" + }, + "require": { + "vk/pkg2": "1.0.0" + }, + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "VK\\Common\\Pkg1\\": "src/" + } + }, + "transport-options": { + "relative": true + }, + "install-path": "../vk/pkg1" }, - "require": { - "vk/pkg2": "1.0.0" + { + "name": "vk/pkg2", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "dist": { + "type": "path", + "url": "./packages/pkg2", + "reference": "e32549ec11d35c5d7deea3ffe72a35ca33456f23" + }, + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "VK\\Common\\Pkg2\\": "src" + } + }, + "transport-options": { + "relative": true + }, + "install-path": "../vk/pkg2" }, - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "VK\\Common\\Pkg1\\": "src/" - } + { + "name": "vk/utils", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "dist": { + "type": "path", + "url": "./packages/utils", + "reference": "0a222823e935ae31baddb76e6ab1801884ebc6c9" + }, + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "VK\\Utils\\": "src/", + "": "utils-fallback/src/" + } + }, + "transport-options": { + "relative": true + }, + "install-path": "../vk/utils" } - }, - { - "name": "vk/pkg2", - "version": "1.0.0", - "version_normalized": "1.0.0.0", - "dist": { - "type": "path", - "url": "./packages/pkg2", - "reference": "a4d1b73b856b267d687b5b6f9d4ab6ec1b884afe", - "shasum": null - }, - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "VK\\Common\\Pkg2\\": "src" - } - } - }, - { - "name": "vk/utils", - "version": "1.0.0", - "version_normalized": "1.0.0.0", - "dist": { - "type": "path", - "url": "./packages/utils", - "reference": "f08b32d3a2176e0de96c4e79383d1c950f39fc63", - "shasum": null - }, - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "VK\\Utils\\": "src/", - "": "utils-fallback/src/" - } - } - } -] + ], + "dev": true, + "dev-package-names": [] +}