diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 538868318..60b9afaf2 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -52,5 +52,5 @@ jobs: - name: Run PHPStan # Locked to phpunit 7.5 here as newer ones have void return types which break inheritance run: | - bin/composer require --dev phpstan/phpstan:^0.12.42 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }} + bin/composer require --dev phpstan/phpstan:^0.12.69 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }} vendor/bin/phpstan analyse --configuration=phpstan/config.neon diff --git a/CHANGELOG.md b/CHANGELOG.md index df976943e..6db4259db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +### [2.0.9] 2021-01-27 + + * Added warning if the curl extension is not enabled as it significantly degrades performance + * Fixed InstalledVersions to report all packages when several vendor dirs are present in the same runtime + * Fixed download speed when downloading large files + * Fixed `archive` and path repo copies mishandling some .gitignore paths + * Fixed root package classes not being available to the plugins/scripts during the initial install + * Fixed cache writes to be atomic and better support multiple Composer processes running in parallel + * Fixed preg jit issues when `config` or `require` modifies large composer.json files + * Fixed compatibility with envs having open_basedir restrictions + * Fixed exclude-from-classmap causing regex issues when having too many paths + * Fixed compatibility issue with Symfony 4/5 + * Several small performance and debug output improvements + ### [2.0.8] 2020-12-03 * Fixed packages with aliases not matching conflicts which match the alias @@ -150,6 +164,11 @@ * Fixed suggest output being very spammy, it now is only one line long and shows more rarely * Fixed conflict rules like e.g. >=5 from matching dev-master, as it is not normalized to 9999999-dev internally anymore +### [1.10.20] 2021-01-27 + + * Fixed exclude-from-classmap causing regex issues when having too many paths + * Fixed compatibility issue with Symfony 4/5 + ### [1.10.19] 2020-12-04 * Fixed regression on PHP 8.0 @@ -1076,6 +1095,7 @@ * Initial release +[2.0.9]: https://github.com/composer/composer/compare/2.0.8...2.0.9 [2.0.8]: https://github.com/composer/composer/compare/2.0.7...2.0.8 [2.0.7]: https://github.com/composer/composer/compare/2.0.6...2.0.7 [2.0.6]: https://github.com/composer/composer/compare/2.0.5...2.0.6 @@ -1090,6 +1110,7 @@ [2.0.0-alpha3]: https://github.com/composer/composer/compare/2.0.0-alpha2...2.0.0-alpha3 [2.0.0-alpha2]: https://github.com/composer/composer/compare/2.0.0-alpha1...2.0.0-alpha2 [2.0.0-alpha1]: https://github.com/composer/composer/compare/1.10.7...2.0.0-alpha1 +[1.10.20]: https://github.com/composer/composer/compare/1.10.19...1.10.20 [1.10.19]: https://github.com/composer/composer/compare/1.10.18...1.10.19 [1.10.18]: https://github.com/composer/composer/compare/1.10.17...1.10.18 [1.10.17]: https://github.com/composer/composer/compare/1.10.16...1.10.17 diff --git a/composer.lock b/composer.lock index a5e510d4d..371202b49 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.2.8", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "8a7ecad675253e4654ea05505233285377405215" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", - "reference": "8a7ecad675253e4654ea05505233285377405215", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -26,14 +26,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -63,7 +64,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.8" + "source": "https://github.com/composer/ca-bundle/tree/1.2.9" }, "funding": [ { @@ -79,7 +80,7 @@ "type": "tidelift" } ], - "time": "2020-08-23T12:54:47+00:00" + "time": "2021-01-12T12:10:35+00:00" }, { "name": "composer/semver", diff --git a/doc/03-cli.md b/doc/03-cli.md index 0561bebef..99d4272b8 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -943,6 +943,8 @@ The `COMPOSER_HOME` var allows you to change the Composer home directory. This is a hidden, global (per-user on the machine) directory that is shared between all projects. +Use `composer config --global home` to see the location of the home directory. + By default, it points to `C:\Users\\AppData\Roaming\Composer` on Windows and `/Users//.composer` on macOS. On \*nix systems that follow the [XDG Base Directory Specifications](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html), @@ -1012,6 +1014,13 @@ similar use case), and need to support proxies, please provide the `CGI_HTTP_PRO environment variable instead. See [httpoxy.org](https://httpoxy.org/) for further details. +### COMPOSER_MAX_PARALLEL_HTTP + +Set to an integer to configure how many files can be downloaded in parallel. This +defaults to 12 and must be between 1 and 50. If your proxy has issues with +concurrency maybe you want to lower this. Increasing it should generally not result +in performance gains. + ### HTTP_PROXY_REQUEST_FULLURI If you use a proxy, but it does not support the request_fulluri flag, then you diff --git a/doc/04-schema.md b/doc/04-schema.md index f1859ea95..05149d331 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -401,19 +401,19 @@ Example: #### require -Lists packages required by this package. The package will not be installed +Map of packages required by this package. The package will not be installed unless those requirements can be met. #### require-dev ([root-only](04-schema.md#root-package)) -Lists packages required for developing this package, or running +Map of packages required for developing this package, or running tests, etc. The dev requirements of the root package are installed by default. Both `install` or `update` support the `--no-dev` option that prevents dev dependencies from being installed. #### conflict -Lists packages that conflict with this version of this package. They +Map of packages that conflict with this version of this package. They will not be allowed to be installed together with your package. Note that when specifying ranges like `<1.0 >=1.1` in a `conflict` link, @@ -423,7 +423,7 @@ probably want to go for `<1.0 || >=1.1` in this case. #### replace -Lists packages that are replaced by this package. This allows you to fork a +Map of packages that are replaced by this package. This allows you to fork a package, publish it under a different name with its own version numbers, while packages requiring the original package continue to work with your fork because it replaces the original package. @@ -441,10 +441,12 @@ that exact version, and not any other version, which would be incorrect. #### provide -List of other packages that are provided by this package. This is mostly +Map of packages that are provided by this package. This is mostly useful for implementations of common interfaces. A package could depend on -some virtual `logger-implementation` package, any library that implements -this logger interface would list it in `provide`. +some virtual package e.g. `psr/logger-implementation`, any library that implements +this logger interface would list it in `provide`. Implementors can then +be [found on Packagist.org](https://packagist.org/providers/psr/log-implementation). + Using `provide` with the name of an actual package rather than a virtual one implies that the code of that package is also shipped, in which case `replace` is generally a better choice. A common convention for packages providing an diff --git a/doc/05-repositories.md b/doc/05-repositories.md index af0267368..7624c054e 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -576,14 +576,23 @@ the branch or tag that is currently checked out. Otherwise, the version should be explicitly defined in the package's `composer.json` file. If the version cannot be resolved by these means, it is assumed to be `dev-master`. -When the version cannot be inferred from the local VCS repository, you should use -the special `branch-version` entry under `extra` instead of `version`: +When the version cannot be inferred from the local VCS repository, or when you +want to override the version, you can use the `versions` option when declaring +the repository: ```json { - "extra": { - "branch-version": "4.2-dev" - } + "repositories": [ + { + "type": "path", + "url": "../../packages/my-package", + "options": { + "versions": { + "my/package": "4.2-dev" + } + } + } + ] } ``` diff --git a/doc/07-runtime.md b/doc/07-runtime.md index 7cbbd63a2..ab90a57b3 100644 --- a/doc/07-runtime.md +++ b/doc/07-runtime.md @@ -87,7 +87,7 @@ possible for safety. ---- A few other methods are available for more complex usages, please refer to the -source/docblocks of the class itself. +source/docblocks of [the class itself](https://github.com/composer/composer/blob/master/src/Composer/InstalledVersions.php). ## Platform check diff --git a/doc/articles/authentication-for-private-packages.md b/doc/articles/authentication-for-private-packages.md index 1c065cb6d..b722df236 100644 --- a/doc/articles/authentication-for-private-packages.md +++ b/doc/articles/authentication-for-private-packages.md @@ -80,10 +80,9 @@ To fix this you need to open the file in an editor and fix the error. To find th your global `auth.json`, execute: ```sh -composer config --global --list +composer config --global home ``` -And look for the `[home]` section. (It is by default `~/.composer` or `%APPDATA%/Composer` on Windows) The folder will contain your global `auth.json` if it exists. You can open this file in your favorite editor and fix the error. @@ -107,7 +106,7 @@ section or directly in the repository definition. The final option to supply Composer with credentials is to use the `COMPOSER_AUTH` environment variable. These variables can be either passed as command line variables or set in actual environment variables. -Read more about the usage of this environment variable [here](../03-cli.md#COMPOSER_AUTH). +Read more about the usage of this environment variable [here](../03-cli.md#composer-auth). # Authentication methods diff --git a/doc/articles/versions.md b/doc/articles/versions.md index fc2f36c55..67f2c2958 100644 --- a/doc/articles/versions.md +++ b/doc/articles/versions.md @@ -80,6 +80,19 @@ In the above example, if you wanted to check out the `my-feature` branch, you wo When branch names look like versions, we have to clarify for composer that we're trying to check out a branch and not a tag. In the above example, we have two version branches: `v1` and `v2`. To get Composer to check out one of these branches, you must specify a version constraint that looks like this: `v1.x-dev`. The `.x` is an arbitrary string that Composer requires to tell it that we're talking about the `v1` branch and not a `v1` tag (alternatively, you can name the branch `v1.x` instead of `v1`). In the case of a branch with a version-like name (`v1`, in this case), you append `-dev` as a suffix, rather than using `dev-` as a prefix. +### Stabilities + +Composer recognizes the following stabilities (in order of stability): dev, +alpha, beta, RC, and stable where RC stands for release candidate. The stability +of a version is defined by its suffix e.g version `v1.1-BETA` has a stability of +`beta` and `v1.1-RC1` has a stability of `RC`. If such a suffix is missing +e.g. version `v1.1` then Composer considers that version `stable`. In addition +to that Composer automatically adds a `-dev` suffix to all numeric branches and +prefixes all other branches imported from a VCS repository with `dev-`. In both +cases the stability `dev` gets assigned. + +Keeping this in mind will help you in the next section. + ### Minimum Stability There's one more thing that will affect which files are checked out of a library's VCS and added to your project: Composer allows you to specify stability constraints to limit which tags are considered valid. In the above example, note that the library released a beta and two release candidates for version `1.1` before the final official release. To receive these versions when running `composer install` or `composer update`, we have to explicitly tell Composer that we are ok with release candidates and beta releases (and alpha releases, if we want those). This can be done using either a project-wide `minimum-stability` value in `composer.json` or using "stability flags" in version constraints. Read more on the [schema page](../04-schema.md#minimum-stability). diff --git a/doc/faqs/how-to-install-composer-programmatically.md b/doc/faqs/how-to-install-composer-programmatically.md index 3b378a5ab..6299b6d40 100644 --- a/doc/faqs/how-to-install-composer-programmatically.md +++ b/doc/faqs/how-to-install-composer-programmatically.md @@ -9,7 +9,7 @@ An alternative is to use this script which only works with UNIX utilities: ```bash #!/bin/sh -EXPECTED_CHECKSUM="$(wget -q -O - https://composer.github.io/installer.sig)" +EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 6ad5d94b0..fa5dd9cf2 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -275,7 +275,7 @@ EOF; $excluded = null; if (!empty($autoloads['exclude-from-classmap'])) { - $excluded = '{(' . implode('|', $autoloads['exclude-from-classmap']) . ')}'; + $excluded = $autoloads['exclude-from-classmap']; } $classMap = array(); @@ -398,8 +398,31 @@ EOF; return $classMap; } + /** + * @param ?array $excluded + */ private function generateClassMap($dir, $excluded, $namespaceFilter, $autoloadType, $showAmbiguousWarning, array &$scannedFiles) { + if ($excluded) { + // filter excluded patterns here to only use those matching $dir + // exclude-from-classmap patterns are all realpath'd so we can only filter them if $dir exists so that realpath($dir) will work + // if $dir does not exist, it should anyway not find anything there so no trouble + if (file_exists($dir)) { + // transform $dir in the same way that exclude-from-classmap patterns are transformed so we can match them against each other + $dirMatch = preg_quote(strtr(realpath($dir), '\\', '/')); + foreach ($excluded as $index => $pattern) { + // extract the constant string prefix of the pattern here, until we reach a non-escaped regex special character + $pattern = preg_replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern); + // if the pattern is not a subset or superset of $dir, it is unrelated and we skip it + if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) { + unset($excluded[$index]); + } + } + } + + $excluded = $excluded ? '{(' . implode('|', $excluded) . ')}' : null; + } + return ClassMapGenerator::createMap($dir, $excluded, $showAmbiguousWarning ? $this->io : null, $namespaceFilter, $autoloadType, $scannedFiles); } @@ -513,7 +536,7 @@ EOF; if (isset($autoloads['classmap'])) { $excluded = null; if (!empty($autoloads['exclude-from-classmap'])) { - $excluded = '{(' . implode('|', $autoloads['exclude-from-classmap']) . ')}'; + $excluded = $autoloads['exclude-from-classmap']; } $scannedFiles = array(); @@ -838,7 +861,7 @@ PLATFORM_CHECK; $file .= <<vendorDir = $vendorDir; + } + public function getPrefixes() { if (!empty($this->prefixesPsr0)) { @@ -300,6 +309,17 @@ class ClassLoader 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; + } } /** @@ -308,6 +328,10 @@ class ClassLoader public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } } /** @@ -367,6 +391,16 @@ class ClassLoader return $file; } + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + private function findFileWithExtension($class, $ext) { // PSR-4 lookup diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 60044e19c..92295f021 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -51,7 +51,7 @@ class ClassMapGenerator * Iterate over all files in the given directory searching for classes * * @param \Iterator|string $path The path to search in or an iterator - * @param string $excluded Regex that matches against the file path that exclude from the classmap. + * @param string $excluded Regex that matches file paths to be excluded from the classmap * @param IOInterface $io IO object * @param string $namespace Optional namespace prefix to filter by * @param string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules diff --git a/src/Composer/Cache.php b/src/Composer/Cache.php index c4bb4b2eb..9590693ff 100644 --- a/src/Composer/Cache.php +++ b/src/Composer/Cache.php @@ -114,20 +114,21 @@ class Cache $this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG); + $tempFileName = $this->root . $file . uniqid('.', true) . '.tmp'; try { - return file_put_contents($this->root . $file.'.tmp', $contents) !== false && rename($this->root . $file . '.tmp', $this->root . $file); + return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file); } catch (\ErrorException $e) { $this->io->writeError('Failed to write into cache: '.$e->getMessage().'', true, IOInterface::DEBUG); if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) { // Remove partial file. - unlink($this->root . $file); + unlink($tempFileName); $message = sprintf( 'Writing %1$s into cache failed after %2$u of %3$u bytes written, only %4$u bytes of free space available', - $this->root . $file, + $tempFileName, $m[1], $m[2], - @disk_free_space($this->root . dirname($file)) + @disk_free_space(dirname($tempFileName)) ); $this->io->writeError($message); diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index d3f450c50..038406a34 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -15,6 +15,7 @@ namespace Composer\Command; use Composer\Installer; use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; +use Composer\Util\HttpDownloader; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; @@ -93,6 +94,10 @@ EOT $composer = $this->getComposer(true, $input->getOption('no-plugins')); + if ((!$composer->getLocker() || !$composer->getLocker()->isLocked()) && !HttpDownloader::isCurlEnabled()) { + $io->writeError('Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.'); + } + $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 2bc36e37a..ea0831818 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -126,7 +126,7 @@ EOT $composeUser = posix_getpwuid(posix_geteuid()); $homeOwner = posix_getpwuid(fileowner($home)); if (isset($composeUser['name'], $homeOwner['name']) && $composeUser['name'] !== $homeOwner['name']) { - $io->writeError('You are running composer as "'.$composeUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"'); + $io->writeError('You are running Composer as "'.$composeUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"'); } } @@ -185,7 +185,7 @@ EOT if (Composer::VERSION === $updateVersion) { $io->writeError( sprintf( - 'You are already using composer version %s (%s channel).', + 'You are already using the latest available Composer version %s (%s channel).', $updateVersion, $channelString ) diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 60a4758f1..84d329ba5 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -19,6 +19,7 @@ use Composer\IO\IOInterface; use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; use Composer\Package\Version\VersionParser; +use Composer\Util\HttpDownloader; use Composer\Semver\Constraint\MultiConstraint; use Composer\Package\Link; use Symfony\Component\Console\Helper\Table; @@ -114,6 +115,10 @@ EOT $composer = $this->getComposer(true, $input->getOption('no-plugins')); + if (!HttpDownloader::isCurlEnabled()) { + $io->writeError('Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.'); + } + $packages = $input->getArgument('packages'); $reqs = $this->formatRequirements($input->getOption('with')); diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 436de79f2..e62886122 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -78,8 +78,7 @@ class Config public static $defaultRepositories = array( 'packagist.org' => array( 'type' => 'composer', - 'url' => 'https?://repo.packagist.org', - 'allow_ssl_downgrade' => true, + 'url' => 'https://repo.packagist.org', ), ); @@ -180,6 +179,11 @@ class Config continue; } + // auto-deactivate the default packagist.org repo if it gets redefined + if (isset($repository['type'], $repository['url']) && $repository['type'] === 'composer' && preg_match('{^https?://(?:[a-z0-9-.]+\.)?packagist.org(/|$)}', $repository['url'])) { + $this->disableRepoByName('packagist.org'); + } + // store repo if (is_int($name)) { $this->repositories[] = $repository; diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index cd78684c1..9d3557e27 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -237,11 +237,11 @@ class Application extends BaseApplication } if (extension_loaded('xdebug') && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) { - $io->writeError('You are running composer with Xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug'); + $io->writeError('Composer is operating slower than normal because you have Xdebug enabled. See https://getcomposer.org/xdebug'); } if (defined('COMPOSER_DEV_WARNING_TIME') && $commandName !== 'self-update' && $commandName !== 'selfupdate' && time() > COMPOSER_DEV_WARNING_TIME) { - $io->writeError(sprintf('Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF'])); + $io->writeError(sprintf('Warning: This development build of Composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF'])); } if ( @@ -309,8 +309,9 @@ class Application extends BaseApplication $result = parent::doRun($input, $output); + // chdir back to $oldWorkingDir if set if (isset($oldWorkingDir)) { - chdir($oldWorkingDir); + Silencer::call('chdir', $oldWorkingDir); } if (isset($startTime)) { diff --git a/src/Composer/DependencyResolver/SolverProblemsException.php b/src/Composer/DependencyResolver/SolverProblemsException.php index 85998e5a0..c6844e25c 100644 --- a/src/Composer/DependencyResolver/SolverProblemsException.php +++ b/src/Composer/DependencyResolver/SolverProblemsException.php @@ -63,7 +63,7 @@ class SolverProblemsException extends \RuntimeException $hints[] = $this->createExtensionHint(); } - if ($isCausedByLock && !$isDevExtraction) { + if ($isCausedByLock && !$isDevExtraction && !$request->getUpdateAllowTransitiveRootDependencies()) { $hints[] = "Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions."; } diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 3ca7eb9e4..a99ea79a0 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -16,6 +16,7 @@ use Composer\Config; use Composer\Cache; use Composer\IO\IOInterface; use Composer\IO\NullIO; +use Composer\Exception\IrrecoverableDownloadException; use Composer\Package\Comparer\Comparer; use Composer\DependencyResolver\Operation\UpdateOperation; use Composer\DependencyResolver\Operation\InstallOperation; @@ -219,6 +220,10 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface } $self->clearLastCacheWrite($package); + if ($e instanceof IrrecoverableDownloadException) { + throw $e; + } + if ($e instanceof TransportException) { // if we got an http response with a proper code, then requesting again will probably not help, abort if ((0 !== $e->getCode() && !in_array($e->getCode(), array(500, 502, 503, 504))) || !$retries) { diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index e43163dd0..b5bd73db6 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -71,6 +71,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface if ($this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref) && is_dir($cachePath)) { $this->cachedPackages[$package->getId()][$ref] = true; } + } elseif (null === $gitVersion) { + throw new \RuntimeException('git was not found in your PATH, skipping source download'); } } @@ -454,13 +456,10 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface $command = sprintf('git checkout %s --', ProcessExecutor::escape($branch)); $fallbackCommand = sprintf('git checkout '.$force.'-B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch)); - if (0 === $this->process->execute($command, $output, $path) - || 0 === $this->process->execute($fallbackCommand, $output, $path) - ) { - $command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference)); - if (0 === $this->process->execute($command, $output, $path)) { - return null; - } + $resetCommand = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference)); + + if (0 === $this->process->execute("($command || $fallbackCommand) && $resetCommand", $output, $path)) { + return null; } } diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index 59ced0193..737dd8758 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -26,6 +26,9 @@ class HgDownloader extends VcsDownloader */ protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null) { + if (null === HgUtils::getVersion($this->process)) { + throw new \RuntimeException('hg was not found in your PATH, skipping source download'); + } } /** diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index 2f253b4bd..80454f855 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -30,6 +30,11 @@ class SvnDownloader extends VcsDownloader */ protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null) { + SvnUtil::cleanEnv(); + $util = new SvnUtil($url, $this->io, $this->config, $this->process); + if (null === $util->binaryVersion()) { + throw new \RuntimeException('svn was not found in your PATH, skipping source download'); + } } /** diff --git a/src/Composer/Downloader/TransportException.php b/src/Composer/Downloader/TransportException.php index c682df080..68c73542f 100644 --- a/src/Composer/Downloader/TransportException.php +++ b/src/Composer/Downloader/TransportException.php @@ -20,6 +20,7 @@ class TransportException extends \RuntimeException protected $headers; protected $response; protected $statusCode; + protected $responseInfo = array(); public function setHeaders($headers) { @@ -50,4 +51,20 @@ class TransportException extends \RuntimeException { return $this->statusCode; } + + /** + * @return array + */ + public function getResponseInfo() + { + return $this->responseInfo; + } + + /** + * @param array $responseInfo + */ + public function setResponseInfo(array $responseInfo) + { + $this->responseInfo = $responseInfo; + } } diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index be53cab9d..faedb969a 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -243,6 +243,8 @@ class EventDispatcher if (strpos($exec, '@putenv ') === 0) { putenv(substr($exec, 8)); + list($var, $value) = explode('=', substr($exec, 8), 2); + $_SERVER[$var] = $value; continue; } diff --git a/src/Composer/InstalledVersions.php b/src/Composer/InstalledVersions.php index e492f988a..bd5647882 100644 --- a/src/Composer/InstalledVersions.php +++ b/src/Composer/InstalledVersions.php @@ -12,6 +12,7 @@ namespace Composer; +use Composer\Autoload\ClassLoader; use Composer\Semver\VersionParser; /** @@ -22,6 +23,8 @@ use Composer\Semver\VersionParser; class InstalledVersions { private static $installed; + private static $canGetVendors; + private static $installedByVendor = array(); /** * Returns a list of all package names which are present, either by being installed, replaced or provided @@ -31,7 +34,17 @@ class InstalledVersions */ public static function getInstalledPackages() { - return array_keys(self::$installed['versions']); + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); } /** @@ -44,7 +57,13 @@ class InstalledVersions */ public static function isInstalled($packageName) { - return isset(self::$installed['versions'][$packageName]); + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return true; + } + } + + return false; } /** @@ -79,25 +98,29 @@ class InstalledVersions */ public static function getVersionRanges($packageName) { - if (!isset(self::$installed['versions'][$packageName])) { - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); } - $ranges = array(); - if (isset(self::$installed['versions'][$packageName]['pretty_version'])) { - $ranges[] = self::$installed['versions'][$packageName]['pretty_version']; - } - if (array_key_exists('aliases', self::$installed['versions'][$packageName])) { - $ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']); - } - if (array_key_exists('replaced', self::$installed['versions'][$packageName])) { - $ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']); - } - if (array_key_exists('provided', self::$installed['versions'][$packageName])) { - $ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']); - } - - return implode(' || ', $ranges); + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** @@ -106,15 +129,19 @@ class InstalledVersions */ public static function getVersion($packageName) { - if (!isset(self::$installed['versions'][$packageName])) { - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; } - if (!isset(self::$installed['versions'][$packageName]['version'])) { - return null; - } - - return self::$installed['versions'][$packageName]['version']; + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** @@ -123,15 +150,19 @@ class InstalledVersions */ public static function getPrettyVersion($packageName) { - if (!isset(self::$installed['versions'][$packageName])) { - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; } - if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) { - return null; - } - - return self::$installed['versions'][$packageName]['pretty_version']; + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** @@ -140,15 +171,19 @@ class InstalledVersions */ public static function getReference($packageName) { - if (!isset(self::$installed['versions'][$packageName])) { - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; } - if (!isset(self::$installed['versions'][$packageName]['reference'])) { - return null; - } - - return self::$installed['versions'][$packageName]['reference']; + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** @@ -157,7 +192,9 @@ class InstalledVersions */ public static function getRootPackage() { - return self::$installed['root']; + $installed = self::getInstalled(); + + return $installed[0]['root']; } /** @@ -192,5 +229,32 @@ class InstalledVersions public static function reload($data) { self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + } + } + } + + $installed[] = self::$installed; + + return $installed; } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 51b7c40b6..1a7c5e694 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -43,12 +43,14 @@ use Composer\Package\Version\VersionParser; use Composer\Package\Package; use Composer\Repository\ArrayRepository; use Composer\Repository\RepositorySet; +use Composer\Repository\CompositeRepository; use Composer\Semver\Constraint\Constraint; use Composer\Package\Locker; use Composer\Package\RootPackageInterface; use Composer\Repository\InstalledArrayRepository; use Composer\Repository\InstalledRepositoryInterface; use Composer\Repository\InstalledRepository; +use Composer\Repository\FilterRepository; use Composer\Repository\RootPackageRepository; use Composer\Repository\PlatformRepository; use Composer\Repository\RepositoryInterface; @@ -706,7 +708,7 @@ class Installer return 0; } - private function createPlatformRepo($forUpdate) + protected function createPlatformRepo($forUpdate) { if ($forUpdate) { $platformOverrides = $this->config->get('platform') ?: array(); @@ -766,6 +768,21 @@ class Installer $repositorySet->addRepository(new RootPackageRepository($this->fixedRootPackage)); $repositorySet->addRepository($platformRepo); if ($this->additionalFixedRepository) { + // allow using installed repos if needed to avoid warnings about installed repositories being used in the RepositorySet + // see https://github.com/composer/composer/pull/9574 + $additionalFixedRepositories = $this->additionalFixedRepository; + if ($additionalFixedRepositories instanceof CompositeRepository) { + $additionalFixedRepositories = $additionalFixedRepositories->getRepositories(); + } else { + $additionalFixedRepositories = array($additionalFixedRepositories); + } + foreach ($additionalFixedRepositories as $additionalFixedRepository) { + if ($additionalFixedRepository instanceof InstalledRepository || $additionalFixedRepository instanceof InstalledRepositoryInterface) { + $repositorySet->allowInstalledRepositories(); + break; + } + } + $repositorySet->addRepository($this->additionalFixedRepository); } diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index f8a0e5708..01148583a 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -492,9 +492,15 @@ class InstallationManager $promise = $installer->update($repo, $initial, $target); $this->markForNotification($target); } else { - $this->getInstaller($initialType)->uninstall($repo, $initial); + $promise = $this->getInstaller($initialType)->uninstall($repo, $initial); + if (!$promise instanceof PromiseInterface) { + $promise = \React\Promise\resolve(); + } + $installer = $this->getInstaller($targetType); - $promise = $installer->install($repo, $target); + $promise->then(function () use ($installer, $repo, $target) { + return $installer->install($repo, $target); + }); } return $promise; diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index e794fe63a..f4c595b39 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -80,6 +80,7 @@ class JsonFile /** * Reads json file. * + * @throws ParsingException * @throws \RuntimeException * @return mixed */ @@ -172,6 +173,7 @@ class JsonFile * @param int $schema a JsonFile::*_SCHEMA constant * @param string|null $schemaFile a path to the schema file * @throws JsonValidationException + * @throws ParsingException * @return bool true on success */ public function validateSchema($schema = self::STRICT_SCHEMA, $schemaFile = null) @@ -289,6 +291,7 @@ class JsonFile * @param string $json json string * @param string $file the json file * + * @throws ParsingException * @return mixed */ public static function parseJson($json, $file = null) diff --git a/src/Composer/Json/JsonManipulator.php b/src/Composer/Json/JsonManipulator.php index d6b196e7d..ecb15878b 100644 --- a/src/Composer/Json/JsonManipulator.php +++ b/src/Composer/Json/JsonManipulator.php @@ -20,13 +20,13 @@ use Composer\Repository\PlatformRepository; class JsonManipulator { private static $DEFINES = '(?(DEFINE) - (? -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? ) + (? -? (?= [1-9]|0(?!\d) ) \d++ (\.\d++)? ([eE] [+-]?+ \d++)? ) (? true | false | null ) - (? " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " ) - (? \[ (?: (?&json) \s* (?: , (?&json) \s* )* )? \s* \] ) - (? \s* (?&string) \s* : (?&json) \s* ) - (? \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} ) - (? \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) ) + (? " ([^"\\\\]*+ | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " ) + (? \[ (?: (?&json) \s*+ (?: , (?&json) \s*+ )*+ )?+ \s*+ \] ) + (? \s*+ (?&string) \s*+ : (?&json) \s*+ ) + (? \{ (?: (?&pair) (?: , (?&pair) )*+ )?+ \s*+ \} ) + (? \s*+ (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) ) )'; private $contents; diff --git a/src/Composer/Package/Archiver/BaseExcludeFilter.php b/src/Composer/Package/Archiver/BaseExcludeFilter.php index 8e69ed069..29ed0ff1b 100644 --- a/src/Composer/Package/Archiver/BaseExcludeFilter.php +++ b/src/Composer/Package/Archiver/BaseExcludeFilter.php @@ -123,26 +123,25 @@ abstract class BaseExcludeFilter protected function generatePattern($rule) { $negate = false; - $pattern = '{'; + $pattern = ''; - if (strlen($rule) && $rule[0] === '!') { + if ($rule !== '' && $rule[0] === '!') { $negate = true; - $rule = substr($rule, 1); + $rule = ltrim($rule, '!'); } - if (strlen($rule) && $rule[0] === '/') { - $pattern .= '^/'; - $rule = substr($rule, 1); - } elseif (strlen($rule) - 1 === strpos($rule, '/')) { - $pattern .= '/'; - $rule = substr($rule, 0, -1); - } elseif (false === strpos($rule, '/')) { - $pattern .= '/'; + $firstSlashPosition = strpos($rule, '/'); + if (0 === $firstSlashPosition) { + $pattern = '^/'; + } elseif (false === $firstSlashPosition || strlen($rule) - 1 === $firstSlashPosition) { + $pattern = '/'; } + $rule = trim($rule, '/'); + // remove delimiters as well as caret (^) and dollar sign ($) from the regex - $pattern .= substr(Finder\Glob::toRegex($rule), 2, -2) . '(?=$|/)'; + $rule = substr(Finder\Glob::toRegex($rule), 2, -2); - return array($pattern . '}', $negate, false); + return array('{'.$pattern.$rule.'(?=$|/)}', $negate, false); } } diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index e807cfd45..843a94e69 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -74,10 +74,8 @@ class RootPackageLoader extends ArrayLoader if (!isset($config['version'])) { $commit = null; - if (isset($config['extra']['branch-version'])) { - $config['version'] = preg_replace('{(\.x)?(-dev)?$}', '', $config['extra']['branch-version']).'.x-dev'; - } elseif (getenv('COMPOSER_ROOT_VERSION')) { - // override with env var if available + // override with env var if available + if (getenv('COMPOSER_ROOT_VERSION')) { $config['version'] = getenv('COMPOSER_ROOT_VERSION'); } else { $versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd()); diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index 8aad71b8e..4c5d4d9bf 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -21,7 +21,9 @@ use Composer\Package\RootPackage; use Composer\Package\Version\VersionParser; use Composer\Repository\RepositoryInterface; use Composer\Repository\InstalledRepository; +use Composer\Repository\RootPackageRepository; use Composer\Package\PackageInterface; +use Composer\Package\RootPackageInterface; use Composer\Package\Link; use Composer\Semver\Constraint\Constraint; use Composer\Plugin\Capability\Capability; @@ -174,7 +176,9 @@ class PluginManager $localRepo = $this->composer->getRepositoryManager()->getLocalRepository(); $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null; - $installedRepo = new InstalledRepository(array($localRepo)); + $rootPackage = clone $this->composer->getPackage(); + $rootPackageRepo = new RootPackageRepository($rootPackage); + $installedRepo = new InstalledRepository(array($localRepo, $rootPackageRepo)); if ($globalRepo) { $installedRepo->addRepository($globalRepo); } @@ -183,13 +187,17 @@ class PluginManager $autoloadPackages = $this->collectDependencies($installedRepo, $autoloadPackages, $package); $generator = $this->composer->getAutoloadGenerator(); - $autoloads = array(); + $autoloads = array(array($rootPackage, '')); foreach ($autoloadPackages as $autoloadPackage) { + if ($autoloadPackage === $rootPackage) { + continue; + } + $downloadPath = $this->getInstallPath($autoloadPackage, $globalRepo && $globalRepo->hasPackage($autoloadPackage)); $autoloads[] = array($autoloadPackage, $downloadPath); } - $map = $generator->parseAutoloads($autoloads, new RootPackage('dummy/root-package', '1.0.0.0', '1.0.0')); + $map = $generator->parseAutoloads($autoloads, $rootPackage); $classLoader = $generator->createLoader($map); $classLoader->register(); @@ -403,12 +411,7 @@ class PluginManager */ private function collectDependencies(InstalledRepository $installedRepo, array $collected, PackageInterface $package) { - $requires = array_merge( - $package->getRequires(), - $package->getDevRequires() - ); - - foreach ($requires as $requireLink) { + foreach ($package->getRequires() as $requireLink) { foreach ($installedRepo->findPackagesWithReplacersAndProviders($requireLink->getTarget()) as $requiredPackage) { if (!isset($collected[$requiredPackage->getName()])) { $collected[$requiredPackage->getName()] = $requiredPackage; diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index cf0d501c3..441e90c20 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -532,6 +532,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito */ private function whatProvides($name, array $acceptableStabilities = null, array $stabilityFlags = null, array $alreadyLoaded = array()) { + $packagesSource = null; if (!$this->hasPartialPackages() || !isset($this->partialPackagesByName[$name])) { // skip platform packages, root package and composer-plugin-api if (PlatformRepository::isPlatformPackage($name) || '__root__' === $name) { @@ -565,15 +566,18 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito if ($cacheKey) { if (!$useLastModifiedCheck && $hash && $this->cache->sha256($cacheKey) === $hash) { $packages = json_decode($this->cache->read($cacheKey), true); + $packagesSource = 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')'; } elseif ($useLastModifiedCheck) { if ($contents = $this->cache->read($cacheKey)) { $contents = json_decode($contents, true); // we already loaded some packages from this file, so assume it is fresh and avoid fetching it again if (isset($alreadyLoaded[$name])) { $packages = $contents; + $packagesSource = 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')'; } elseif (isset($contents['last-modified'])) { $response = $this->fetchFileIfLastModified($url, $cacheKey, $contents['last-modified']); $packages = true === $response ? $contents : $response; + $packagesSource = true === $response ? 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')' : 'downloaded file ('.Url::sanitize($url).')'; } } } @@ -582,10 +586,12 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito if (!$packages) { try { $packages = $this->fetchFile($url, $cacheKey, $hash, $useLastModifiedCheck); + $packagesSource = 'downloaded file ('.Url::sanitize($url).')'; } catch (TransportException $e) { // 404s are acceptable for lazy provider repos if ($this->lazyProvidersUrl && in_array($e->getStatusCode(), array(404, 499), true)) { $packages = array('packages' => array()); + $packagesSource = 'not-found file ('.Url::sanitize($url).')'; if ($e->getStatusCode() === 499) { $this->io->error('' . $e->getMessage() . ''); } @@ -598,6 +604,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $loadingPartialPackage = false; } else { $packages = array('packages' => array('versions' => $this->partialPackagesByName[$name])); + $packagesSource = 'root file ('.Url::sanitize($this->getPackagesJsonUrl()).')'; $loadingPartialPackage = true; } @@ -637,7 +644,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } // load acceptable packages in the providers - $loadedPackages = $this->createPackages($versionsToLoad); + $loadedPackages = $this->createPackages($versionsToLoad, $packagesSource); $uids = array_keys($versionsToLoad); foreach ($loadedPackages as $index => $package) { @@ -667,7 +674,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $repoData = $this->loadDataFromServer(); - foreach ($this->createPackages($repoData) as $package) { + foreach ($this->createPackages($repoData, 'root file ('.Url::sanitize($this->getPackagesJsonUrl()).')') as $package) { $this->addPackage($package); } } @@ -729,8 +736,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified) - ->then(function ($response) use (&$packages, &$namesFound, $contents, $realName, $constraint, $repo, $acceptableStabilities, $stabilityFlags, $alreadyLoaded) { + ->then(function ($response) use (&$packages, &$namesFound, $url, $cacheKey, $contents, $realName, $constraint, $repo, $acceptableStabilities, $stabilityFlags, $alreadyLoaded) { + $packagesSource = 'downloaded file ('.Url::sanitize($url).')'; + if (true === $response) { + $packagesSource = 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')'; $response = $contents; } @@ -764,7 +774,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } } - $loadedPackages = $repo->createPackages($versionsToLoad); + $loadedPackages = $repo->createPackages($versionsToLoad, $packagesSource); foreach ($loadedPackages as $package) { $package->setRepository($repo); $packages[spl_object_hash($package)] = $package; @@ -812,6 +822,17 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return false; } + private function getPackagesJsonUrl() + { + $jsonUrlParts = parse_url($this->url); + + if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) { + return $this->url; + } + + return $this->url . '/packages.json'; + } + protected function loadRootServerFile() { if (null !== $this->rootData) { @@ -822,15 +843,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url); } - $jsonUrlParts = parse_url($this->url); - - if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) { - $jsonUrl = $this->url; - } else { - $jsonUrl = $this->url . '/packages.json'; - } - - $data = $this->fetchFile($jsonUrl, 'packages.json'); + $data = $this->fetchFile($this->getPackagesJsonUrl(), 'packages.json'); if (!empty($data['notify-batch'])) { $this->notifyUrl = $this->canonicalizeUrl($data['notify-batch']); @@ -1027,7 +1040,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito * * @private */ - public function createPackages(array $packages, $class = 'Composer\Package\CompletePackage') + public function createPackages(array $packages, $source = null) { if (!$packages) { return array(); @@ -1040,7 +1053,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } } - $packages = $this->loader->loadPackages($packages, $class); + $packages = $this->loader->loadPackages($packages, 'Composer\Package\CompletePackage'); foreach ($packages as $package) { if (isset($this->sourceMirrors[$package->getSourceType()])) { @@ -1052,7 +1065,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return $packages; } catch (\Exception $e) { - throw new \RuntimeException('Could not load packages '.(isset($packages[0]['name']) ? $packages[0]['name'] : json_encode($packages)).' in '.$this->url.': ['.get_class($e).'] '.$e->getMessage(), 0, $e); + throw new \RuntimeException('Could not load packages '.(isset($packages[0]['name']) ? $packages[0]['name'] : json_encode($packages)).' in '.$this->getRepoName().($source ? ' from '.$source : '').': ['.get_class($e).'] '.$e->getMessage(), 0, $e); } } diff --git a/src/Composer/Repository/FilesystemRepository.php b/src/Composer/Repository/FilesystemRepository.php index 88b292ffb..2823e6ec9 100644 --- a/src/Composer/Repository/FilesystemRepository.php +++ b/src/Composer/Repository/FilesystemRepository.php @@ -204,6 +204,9 @@ class FilesystemRepository extends WritableArrayRepository $fs->filePutContentsIfModified($repoDir.'/installed.php', 'filePutContentsIfModified($repoDir.'/InstalledVersions.php', $installedVersionsClass); diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index c60f9ca9d..c1fc632da 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -170,10 +170,11 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn 'reference' => sha1($json . serialize($this->options)), ); $package['transport-options'] = $this->options; + unset($package['transport-options']['versions']); - // use the branch-version as the package version if available - if (!isset($package['version']) && isset($package['extra']['branch-version'])) { - $package['version'] = preg_replace('{(\.x)?(-dev)?$}', '', $package['extra']['branch-version']).'.x-dev'; + // use the version provided as option if available + if (isset($package['name'], $this->options['versions'][$package['name']])) { + $package['version'] = $this->options['versions'][$package['name']]; } // carry over the root package version if this path repo is in the same git repository as root package diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index 3c3817c7a..0faead2a7 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -37,6 +37,9 @@ class GitDriver extends VcsDriver { if (Filesystem::isLocalPath($this->url)) { $this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url); + if (!is_dir($this->url)) { + throw new \RuntimeException('Failed to read package information from '.$this->url.' as the path does not exist'); + } $this->repoDir = $this->url; $cacheUrl = realpath($this->url); } else { diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index d1200dde9..39092f2e8 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -63,7 +63,7 @@ class Filesystem public function emptyDirectory($dir, $ensureDirectoryExists = true) { - if (file_exists($dir) && is_link($dir)) { + if (is_link($dir) && file_exists($dir)) { $this->unlink($dir); } @@ -108,7 +108,7 @@ class Filesystem return unlink($directory); } - if (!file_exists($directory) || !is_dir($directory)) { + if (!is_dir($directory) || !file_exists($directory)) { return true; } @@ -131,7 +131,7 @@ class Filesystem // clear stat cache because external processes aren't tracked by the php stat cache clearstatcache(); - if ($result && !file_exists($directory)) { + if ($result && !is_dir($directory)) { return true; } @@ -600,7 +600,7 @@ class Filesystem if (!function_exists('symlink')) { return false; } - + $cwd = getcwd(); $relativePath = $this->findShortestPath($link, $target); diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 4eafc24e0..dd95f2062 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -101,7 +101,7 @@ class Git $errorMsg = $this->process->getErrorOutput(); // private github repository without ssh key access, try https with auth if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match) - || preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match) + || preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match) ) { if (!$this->io->hasAuthentication($match[1])) { $gitHubUtil = new GitHub($this->io, $this->config, $this->process); @@ -122,7 +122,7 @@ class Git $errorMsg = $this->process->getErrorOutput(); } - } elseif (preg_match('{^https://(bitbucket\.org)/(.*)(\.git)?$}U', $url, $match)) { //bitbucket oauth + } elseif (preg_match('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process); if (!$this->io->hasAuthentication($match[1])) { @@ -167,7 +167,7 @@ class Git } } elseif ( preg_match('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match) - || preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}', $url, $match) + || preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match) ) { if ($match[1] === 'git') { $match[1] = 'https'; @@ -354,7 +354,7 @@ class Git // added in git 1.7.1, prevents prompting the user for username/password if (getenv('GIT_ASKPASS') !== 'echo') { putenv('GIT_ASKPASS=echo'); - unset($_SERVER['GIT_ASKPASS']); + $_SERVER['GIT_ASKPASS'] = 'echo'; } // clean up rogue git env vars in case this is running in a git hook @@ -370,6 +370,7 @@ class Git // Run processes with predictable LANGUAGE if (getenv('LANGUAGE') !== 'C') { putenv('LANGUAGE=C'); + $_SERVER['LANGUAGE'] = 'C'; } // clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940 @@ -402,15 +403,12 @@ class Git /** * Retrieves the current git version. * - * @return string|null The git version number. + * @return string|null The git version number, if present. */ public static function getVersion(ProcessExecutor $process) { if (false === self::$version) { self::$version = null; - if (!$process) { - $process = new ProcessExecutor; - } if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { self::$version = $matches[1]; } diff --git a/src/Composer/Util/Hg.php b/src/Composer/Util/Hg.php index d0b7fe79f..a0ebac01d 100644 --- a/src/Composer/Util/Hg.php +++ b/src/Composer/Util/Hg.php @@ -20,6 +20,8 @@ use Composer\IO\IOInterface; */ class Hg { + private static $version = false; + /** * @var \Composer\IO\IOInterface */ @@ -74,10 +76,27 @@ class Hg private function throwException($message, $url) { - if (0 !== $this->process->execute('hg --version', $ignoredOutput)) { + if (null === self::getVersion($this->process)) { throw new \RuntimeException(Url::sanitize('Failed to clone ' . $url . ', hg was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput())); } throw new \RuntimeException(Url::sanitize($message)); } + + /** + * Retrieves the current hg version. + * + * @return string|null The hg version number, if present. + */ + public static function getVersion(ProcessExecutor $process) + { + if (false === self::$version) { + self::$version = null; + if (0 === $process->execute('hg --version', $output) && preg_match('/version (\d+(?:\.\d+)+)/m', $output, $matches)) { + self::$version = $matches[1]; + } + } + + return self::$version; + } } diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 5345f5ce3..5e9494aed 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -321,12 +321,12 @@ class CurlDownloader rewind($job['bodyHandle']); $contents = stream_get_contents($job['bodyHandle']); } - $response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents); + $response = new CurlResponse(array('url' => $progress['url']), $statusCode, $headers, $contents, $progress); $this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG); } else { rewind($job['bodyHandle']); $contents = stream_get_contents($job['bodyHandle']); - $response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents); + $response = new CurlResponse(array('url' => $progress['url']), $statusCode, $headers, $contents, $progress); $this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG); } fclose($job['bodyHandle']); @@ -374,6 +374,9 @@ class CurlDownloader if ($e instanceof TransportException && $response) { $e->setResponse($response->getBody()); } + if ($e instanceof TransportException && $progress) { + $e->setResponseInfo($progress); + } if (is_resource($job['headerHandle'])) { fclose($job['headerHandle']); @@ -511,7 +514,12 @@ class CurlDownloader @unlink($job['filename'].'~'); } - return new TransportException('The "'.$job['url'].'" file could not be downloaded ('.$errorMessage.')', $response->getStatusCode()); + $details = ''; + if ($response->getHeader('content-type') === 'application/json') { + $details = ':'.PHP_EOL.substr($response->getBody(), 0, 200).(strlen($response->getBody()) > 200 ? '...' : ''); + } + + return new TransportException('The "'.$job['url'].'" file could not be downloaded ('.$errorMessage.')' . $details, $response->getStatusCode()); } private function checkCurlResult($code) diff --git a/src/Composer/Util/Http/CurlResponse.php b/src/Composer/Util/Http/CurlResponse.php new file mode 100644 index 000000000..82f725266 --- /dev/null +++ b/src/Composer/Util/Http/CurlResponse.php @@ -0,0 +1,32 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Util\Http; + +class CurlResponse extends Response +{ + private $curlInfo; + + public function __construct(array $request, $code, array $headers, $body, array $curlInfo) + { + parent::__construct($request, $code, $headers, $body); + $this->curlInfo = $curlInfo; + } + + /** + * @return array + */ + public function getCurlInfo() + { + return $this->curlInfo; + } +} diff --git a/src/Composer/Util/Http/ProxyManager.php b/src/Composer/Util/Http/ProxyManager.php index 693ef92ad..edd486ef3 100644 --- a/src/Composer/Util/Http/ProxyManager.php +++ b/src/Composer/Util/Http/ProxyManager.php @@ -87,7 +87,7 @@ class ProxyManager $options = array(); $formattedProxyUrl = ''; - if ($this->hasProxy && $this->fullProxy[$scheme]) { + if ($this->hasProxy && in_array($scheme, array('http', 'https'), true) && $this->fullProxy[$scheme]) { if ($this->noProxy($requestUrl)) { $formattedProxyUrl = 'excluded by no_proxy'; } else { diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 8f3d606d8..ba7a49798 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -19,6 +19,7 @@ use Composer\Util\Http\Response; use Composer\Composer; use Composer\Package\Version\VersionParser; use Composer\Semver\Constraint\Constraint; +use Composer\Exception\IrrecoverableDownloadException; use React\Promise\Promise; /** @@ -37,7 +38,7 @@ class HttpDownloader private $jobs = array(); private $options = array(); private $runningJobs = 0; - private $maxJobs = 10; + private $maxJobs = 12; private $curl; private $rfs; private $idGen = 0; @@ -71,6 +72,10 @@ class HttpDownloader } $this->rfs = new RemoteFilesystem($io, $config, $options, $disableTls); + + if (is_numeric($maxJobs = getenv('COMPOSER_MAX_PARALLEL_HTTP'))) { + $this->maxJobs = max(1, min(50, (int) $maxJobs)); + } } /** @@ -253,10 +258,11 @@ class HttpDownloader if (isset($job['curl_id'])) { $curl->abortRequest($job['curl_id']); } + throw new IrrecoverableDownloadException('Download of ' . Url::sanitize($job['request']['url']) . ' canceled'); }; $promise = new Promise($resolver, $canceler); - $promise->then(function ($response) use (&$job, $downloader) { + $promise = $promise->then(function ($response) use (&$job, $downloader) { $job['status'] = HttpDownloader::STATUS_COMPLETED; $job['response'] = $response; @@ -302,7 +308,7 @@ class HttpDownloader if (isset($job['request']['options']['http']['header']) && false !== stripos(implode('', $job['request']['options']['http']['header']), 'if-modified-since')) { $resolve(new Response(array('url' => $url), 304, array(), '')); } else { - $e = new TransportException('Network disabled, request canceled: '.$url, 499); + $e = new TransportException('Network disabled, request canceled: '.Url::sanitize($url), 499); $e->setStatusCode(499); $reject($e); } @@ -336,13 +342,9 @@ class HttpDownloader */ public function wait($index = null) { - while (true) { - if (!$this->countActiveJobs($index)) { - return; - } - - usleep(1000); - } + do { + $jobCount = $this->countActiveJobs($index); + } while ($jobCount); } /** @@ -429,7 +431,7 @@ class HttpDownloader } } - $io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].''); + $io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$data[$type].''); } } diff --git a/src/Composer/Util/Loop.php b/src/Composer/Util/Loop.php index a75888a8c..2e29b563f 100644 --- a/src/Composer/Util/Loop.php +++ b/src/Composer/Util/Loop.php @@ -85,6 +85,7 @@ class Loop $progress->start($totalJobs); } + $lastUpdate = 0; while (true) { $activeJobs = 0; @@ -95,15 +96,19 @@ class Loop $activeJobs += $this->processExecutor->countActiveJobs(); } - if ($progress) { + if ($progress && microtime(true) - $lastUpdate > 0.1) { + $lastUpdate = microtime(true); $progress->setProgress($progress->getMaxSteps() - $activeJobs); } if (!$activeJobs) { break; } + } - usleep(5000); + // as we skip progress updates if they are too quick, make sure we do one last one here at 100% + if ($progress) { + $progress->setProgress($progress->getMaxSteps()); } unset($this->currentPromises[$waitIndex]); diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index f940f49a9..5ec43859a 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -98,11 +98,15 @@ class ProcessExecutor $this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand); } + // TODO in 2.2, these two checks can be dropped as Symfony 4+ supports them out of the box // make sure that null translate to the proper directory in case the dir is a symlink // and we call a git command, because msysgit does not handle symlinks properly if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) { $cwd = realpath(getcwd()); } + if (null !== $cwd && !is_dir($cwd)) { + throw new \RuntimeException('The given CWD for the process does not exist: '.$cwd); + } $this->captureOutput = func_num_args() > 3; $this->errorOutput = null; @@ -177,6 +181,8 @@ class ProcessExecutor // signal can throw in various conditions, but we don't care if it fails } $job['process']->stop(1); + + throw new \RuntimeException('Aborted process'); }; $promise = new Promise($resolver, $canceler); @@ -233,11 +239,15 @@ class ProcessExecutor $this->io->writeError('Executing async command ('.($cwd ?: 'CWD').'): '.$safeCommand); } + // TODO in 2.2, these two checks can be dropped as Symfony 4+ supports them out of the box // make sure that null translate to the proper directory in case the dir is a symlink // and we call a git command, because msysgit does not handle symlinks properly if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) { $cwd = realpath(getcwd()); } + if (null !== $cwd && !is_dir($cwd)) { + throw new \RuntimeException('The given CWD for the process does not exist: '.$cwd); + } // TODO in v3, commands should be passed in as arrays of cmd + args if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) { diff --git a/tests/Composer/Test/AllFunctionalTest.php b/tests/Composer/Test/AllFunctionalTest.php index a38eda193..cc950b053 100644 --- a/tests/Composer/Test/AllFunctionalTest.php +++ b/tests/Composer/Test/AllFunctionalTest.php @@ -85,7 +85,7 @@ class AllFunctionalTest extends TestCase } } - $proc = new Process('php '.escapeshellarg('./bin/compile'), $target); + $proc = new Process('php -dphar.readonly=0 '.escapeshellarg('./bin/compile'), $target); $exitcode = $proc->run(); if ($exitcode !== 0 || trim($proc->getOutput())) { @@ -102,26 +102,73 @@ class AllFunctionalTest extends TestCase public function testIntegration($testFile) { $testData = $this->parseTestFile($testFile); + $this->testDir = self::getUniqueTmpDirectory(); + + // if a dir is present with the name of the .test file (without .test), we + // copy all its contents in the $testDir to be used to run the test with + $testFileSetupDir = substr($testFile, 0, -5); + if (is_dir($testFileSetupDir)) { + $fs = new Filesystem(); + $fs->copy($testFileSetupDir, $this->testDir); + } $this->oldenv = getenv('COMPOSER_HOME'); $_SERVER['COMPOSER_HOME'] = $this->testDir.'home'; putenv('COMPOSER_HOME='.$_SERVER['COMPOSER_HOME']); $cmd = 'php '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN']; - $proc = new Process($cmd, __DIR__.'/Fixtures/functional', null, null, 300); - $exitcode = $proc->run(); + $proc = new Process($cmd, $this->testDir, null, null, 300); + $output = ''; + + $exitcode = $proc->run(function ($type, $buffer) use (&$output) { + $output .= $buffer; + }); if (isset($testData['EXPECT'])) { - $this->assertEquals($testData['EXPECT'], $this->cleanOutput($proc->getOutput()), 'Error Output: '.$proc->getErrorOutput()); + $output = trim($this->cleanOutput($output)); + $expected = $testData['EXPECT']; + + $line = 1; + for ($i = 0, $j = 0; $i < strlen($expected); ) { + if ($expected[$i] === "\n") { + $line++; + } + if ($expected[$i] === '%') { + preg_match('{%(.+?)%}', substr($expected, $i), $match); + $regex = $match[1]; + + if (preg_match('{'.$regex.'}', substr($output, $j), $match)) { + $i += strlen($regex) + 2; + $j += strlen($match[0]); + continue; + } else { + $this->fail( + 'Failed to match pattern '.$regex.' at line '.$line.' / abs offset '.$i.': ' + .substr($output, $j, min(strpos($output, "\n", $j)-$j, 100)).PHP_EOL.PHP_EOL. + 'Output:'.PHP_EOL.$output + ); + } + } + if ($expected[$i] !== $output[$j]) { + $this->fail( + 'Output does not match expectation at line '.$line.' / abs offset '.$i.': '.PHP_EOL + .'-'.substr($expected, $i, min(strpos($expected, "\n", $i)-$i, 100)).PHP_EOL + .'+'.substr($output, $j, min(strpos($output, "\n", $j)-$j, 100)).PHP_EOL.PHP_EOL + .'Output:'.PHP_EOL.$output + ); + } + $i++; + $j++; + } } if (isset($testData['EXPECT-REGEX'])) { - $this->assertRegExp($testData['EXPECT-REGEX'], $this->cleanOutput($proc->getOutput()), 'Error Output: '.$proc->getErrorOutput()); + $this->assertRegExp($testData['EXPECT-REGEX'], $this->cleanOutput($output)); } - if (isset($testData['EXPECT-ERROR'])) { - $this->assertEquals($testData['EXPECT-ERROR'], $this->cleanOutput($proc->getErrorOutput())); - } - if (isset($testData['EXPECT-ERROR-REGEX'])) { - $this->assertRegExp($testData['EXPECT-ERROR-REGEX'], $this->cleanOutput($proc->getErrorOutput())); + if (isset($testData['EXPECT-REGEXES'])) { + $cleanOutput = $this->cleanOutput($output); + foreach (explode("\n", $testData['EXPECT-REGEXES']) as $regex) { + $this->assertRegExp($regex, $cleanOutput, 'Output: '.$output); + } } if (isset($testData['EXPECT-EXIT-CODE'])) { $this->assertSame($testData['EXPECT-EXIT-CODE'], $exitcode); @@ -132,7 +179,7 @@ class AllFunctionalTest extends TestCase { $tests = array(); foreach (Finder::create()->in(__DIR__.'/Fixtures/functional')->name('*.test')->files() as $file) { - $tests[] = array($file->getRealPath()); + $tests[basename($file)] = array($file->getRealPath()); } return $tests; @@ -144,23 +191,6 @@ class AllFunctionalTest extends TestCase $data = array(); $section = null; - $testDir = self::getUniqueTmpDirectory(); - $this->testDir = $testDir; - $varRegex = '#%([a-zA-Z_-]+)%#'; - $variableReplacer = function ($match) use (&$data, $testDir) { - list(, $var) = $match; - - switch ($var) { - case 'testDir': - $data['test_dir'] = $testDir; - - return $testDir; - - default: - throw new \InvalidArgumentException(sprintf('Unknown variable "%s". Supported variables: "testDir"', $var)); - } - }; - foreach ($tokens as $token) { if ('' === $token && null === $section) { continue; @@ -176,24 +206,20 @@ class AllFunctionalTest extends TestCase // Allow sections to validate, or modify their section data. switch ($section) { - case 'RUN': - $sectionData = preg_replace_callback($varRegex, $variableReplacer, $sectionData); - break; - case 'EXPECT-EXIT-CODE': $sectionData = (int) $sectionData; break; + case 'RUN': case 'EXPECT': case 'EXPECT-REGEX': - case 'EXPECT-ERROR': - case 'EXPECT-ERROR-REGEX': - $sectionData = preg_replace_callback($varRegex, $variableReplacer, $sectionData); + case 'EXPECT-REGEXES': + $sectionData = trim($sectionData); break; default: throw new \RuntimeException(sprintf( - 'Unknown section "%s". Allowed sections: "RUN", "EXPECT", "EXPECT-ERROR", "EXPECT-EXIT-CODE", "EXPECT-REGEX", "EXPECT-ERROR-REGEX". ' + 'Unknown section "%s". Allowed sections: "RUN", "EXPECT", "EXPECT-EXIT-CODE", "EXPECT-REGEX", "EXPECT-REGEXES". ' .'Section headers must be written as "--HEADER_NAME--".', $section )); @@ -207,8 +233,8 @@ class AllFunctionalTest extends TestCase if (!isset($data['RUN'])) { throw new \RuntimeException('The test file must have a section named "RUN".'); } - if (!isset($data['EXPECT']) && !isset($data['EXPECT-ERROR']) && !isset($data['EXPECT-REGEX']) && !isset($data['EXPECT-ERROR-REGEX'])) { - throw new \RuntimeException('The test file must have a section named "EXPECT", "EXPECT-ERROR", "EXPECT-REGEX", or "EXPECT-ERROR-REGEX".'); + if (!isset($data['EXPECT']) && !isset($data['EXPECT-REGEX']) && !isset($data['EXPECT-REGEXES'])) { + throw new \RuntimeException('The test file must have a section named "EXPECT", "EXPECT-REGEX", or "EXPECT-REGEXES".'); } return $data; diff --git a/tests/Composer/Test/ApplicationTest.php b/tests/Composer/Test/ApplicationTest.php index 7e78ee68f..7cecb5794 100644 --- a/tests/Composer/Test/ApplicationTest.php +++ b/tests/Composer/Test/ApplicationTest.php @@ -61,7 +61,7 @@ class ApplicationTest extends TestCase $outputMock->expects($this->at($index++)) ->method("write") - ->with($this->equalTo('You are running composer with Xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug')); + ->with($this->equalTo('Composer is operating slower than normal because you have Xdebug enabled. See https://getcomposer.org/xdebug')); } $outputMock->expects($this->at($index++)) @@ -70,7 +70,7 @@ class ApplicationTest extends TestCase $outputMock->expects($this->at($index++)) ->method("write") - ->with($this->equalTo(sprintf('Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF']))); + ->with($this->equalTo(sprintf('Warning: This development build of Composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF']))); if (!defined('COMPOSER_DEV_WARNING_TIME')) { define('COMPOSER_DEV_WARNING_TIME', time() - 1); diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 0b8334464..134ebd6b8 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -1447,9 +1447,9 @@ EOF; $package->setAutoload(array( 'psr-0' => array('Foo' => '../path/../src'), 'psr-4' => array('Acme\Foo\\' => '../path/../src-psr4'), - 'classmap' => array('../classmap'), + 'classmap' => array('../classmap', '../classmap2/subdir', 'classmap3', 'classmap4'), 'files' => array('../test.php'), - 'exclude-from-classmap' => array('./../classmap/excluded'), + 'exclude-from-classmap' => array('./../classmap/excluded', '../classmap2', 'classmap3/classes.php', 'classmap4/*/classes.php'), )); $this->repository->expects($this->once()) @@ -1458,9 +1458,15 @@ EOF; $this->fs->ensureDirectoryExists($this->workingDir.'/src/Foo'); $this->fs->ensureDirectoryExists($this->workingDir.'/classmap/excluded'); + $this->fs->ensureDirectoryExists($this->workingDir.'/classmap2/subdir'); + $this->fs->ensureDirectoryExists($this->workingDir.'/working-dir/classmap3'); + $this->fs->ensureDirectoryExists($this->workingDir.'/working-dir/classmap4/foo/'); file_put_contents($this->workingDir.'/src/Foo/Bar.php', 'workingDir.'/classmap/classes.php', 'workingDir.'/classmap/excluded/classes.php', 'workingDir.'/classmap2/subdir/classes.php', 'workingDir.'/working-dir/classmap3/classes.php', 'workingDir.'/working-dir/classmap4/foo/classes.php', 'workingDir.'/test.php', 'generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_14'); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php index fdff2bd42..390bff3bd 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php @@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoloadOrder } spl_autoload_register(array('ComposerAutoloaderInitFilesAutoloadOrder', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoloadOrder', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php index 67ce8ffe2..71397e2f5 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions.php @@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoload } spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_include_paths.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_include_paths.php index 790029096..47bb48f7f 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_include_paths.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_include_paths.php @@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoload } spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php index 7b7898df1..965542d83 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_functions_with_removed_include_paths_and_autolad_files.php @@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoload } spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php index 2747dbc0a..1bbf29cb2 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_include_path.php @@ -23,7 +23,7 @@ class ComposerAutoloaderInitIncludePath } spl_autoload_register(array('ComposerAutoloaderInitIncludePath', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitIncludePath', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php b/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php index 8ec8cdd47..7b6b58bf9 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_real_target_dir.php @@ -23,7 +23,7 @@ class ComposerAutoloaderInitTargetDir } spl_autoload_register(array('ComposerAutoloaderInitTargetDir', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitTargetDir', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); diff --git a/tests/Composer/Test/ConfigTest.php b/tests/Composer/Test/ConfigTest.php index 4a4bf011b..91d4dde07 100644 --- a/tests/Composer/Test/ConfigTest.php +++ b/tests/Composer/Test/ConfigTest.php @@ -35,7 +35,7 @@ class ConfigTest extends TestCase $data = array(); $data['local config inherits system defaults'] = array( array( - 'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true), + 'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'), ), array(), ); @@ -58,7 +58,7 @@ class ConfigTest extends TestCase array( 1 => array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'), 0 => array('type' => 'pear', 'url' => 'http://pear.composer.org'), - 'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true), + 'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'), ), array( array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'), @@ -69,7 +69,7 @@ class ConfigTest extends TestCase $data['system config adds above core defaults'] = array( array( 'example.com' => array('type' => 'composer', 'url' => 'http://example.com'), - 'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true), + 'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'), ), array(), array( @@ -104,9 +104,27 @@ class ConfigTest extends TestCase ), ); + $data['local config redefining packagist.org by URL override it if no named keys are used'] = array( + array( + array('type' => 'composer', 'url' => 'https://repo.packagist.org'), + ), + array( + array('type' => 'composer', 'url' => 'https://repo.packagist.org'), + ), + ); + + $data['local config redefining packagist.org by URL override it also with named keys'] = array( + array( + 'example' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'), + ), + array( + 'example' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'), + ), + ); + $data['incorrect local config does not cause ErrorException'] = array( array( - 'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true), + 'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'), 'type' => 'vcs', 'url' => 'http://example.com', ), diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index 2de8f329f..c16c925b6 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -122,12 +122,7 @@ class GitDownloaderTest extends TestCase $processExecutor->expects($this->at(2)) ->method('execute') - ->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(3)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) + ->with($this->equalTo($this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); $downloader = $this->getDownloaderMock(null, null, $processExecutor); @@ -198,12 +193,7 @@ class GitDownloaderTest extends TestCase $processExecutor->expects($this->at(5)) ->method('execute') - ->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(6)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) + ->with($this->equalTo($this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) ->will($this->returnValue(0)); $downloader = $this->getDownloaderMock(null, $config, $processExecutor); diff --git a/tests/Composer/Test/Fixtures/functional/create-project-command.test b/tests/Composer/Test/Fixtures/functional/create-project-command.test index 1c4813446..31ce946c3 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-command.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-command.test @@ -1,4 +1,4 @@ --RUN-- -create-project seld/jsonlint %testDir% 1.0.0 --prefer-source -n ---EXPECT-ERROR-REGEX-- -{Installing seld/jsonlint \(1.0.0\): Cloning [a-f0-9]{10}( from cache)?} +create-project seld/jsonlint foo 1.0.0 --prefer-source -n +--EXPECT-REGEX-- +{- Installing seld/jsonlint \(1.0.0\): Cloning [a-f0-9]{10}( from cache)?} diff --git a/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test index 357f51619..993f96e1a 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test @@ -1,4 +1,4 @@ --RUN-- -create-project --repository=packages.json -v seld/jsonlint %testDir% dev-master ---EXPECT-ERROR-REGEX-- -{^Installing seld/jsonlint \(dev-master [a-f0-9]{40}\)}m +create-project --repository=packages.json -v seld/jsonlint foo dev-main +--EXPECT-REGEX-- +{^Installing seld/jsonlint \(dev-main [a-f0-9]{40}\)}m diff --git a/tests/Composer/Test/Fixtures/functional/packages.json b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages/packages.json similarity index 90% rename from tests/Composer/Test/Fixtures/functional/packages.json rename to tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages/packages.json index 11dfe2d8e..1069f6581 100644 --- a/tests/Composer/Test/Fixtures/functional/packages.json +++ b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages/packages.json @@ -9,8 +9,9 @@ "validator" ], "homepage": "", - "version": "dev-master", - "version_normalized": "9999999-dev", + "version": "dev-main", + "version_normalized": "dev-main", + "default-branch": true, "license": [ "MIT" ], @@ -41,4 +42,4 @@ "php": ">=5.3.0" } } -] \ No newline at end of file +] diff --git a/tests/Composer/Test/Fixtures/installer/conflict-with-all-dependencies-option-dont-recommend-to-use-it.test b/tests/Composer/Test/Fixtures/installer/conflict-with-all-dependencies-option-dont-recommend-to-use-it.test new file mode 100644 index 000000000..d1003fd9d --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/conflict-with-all-dependencies-option-dont-recommend-to-use-it.test @@ -0,0 +1,50 @@ +--TEST-- +Verify that a conflict with all dependencies option enabled don't recommend to use the option +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "locked/pkg", "version": "dev-master", "require": {"locked/dependency": "1.0.0"}, "default-branch": true } + ] + } + ], + "require": { + "locked/pkg": "*@dev" + } +} + +--LOCK-- +{ + "packages": [ + { "name": "locked/pkg", "version": "dev-master", "require": {"locked/dependency": "1.0.0"}, "default-branch": true }, + { "name": "locked/dependency", "version": "1.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} + +--RUN-- +update locked/dependency --with-all-dependencies + +--EXPECT-EXIT-CODE-- +2 + +--EXPECT-OUTPUT-- +Loading composer repositories with package information +Updating dependencies +Your requirements could not be resolved to an installable set of packages. + + Problem 1 + - locked/pkg dev-master requires locked/dependency 1.0.0 -> found locked/dependency[1.0.0] in lock file but not in remote repositories, make sure you avoid updating this package to keep the one from lock file. + - locked/pkg is locked to version dev-master and an update of this package was not requested. + +--EXPECT-- + diff --git a/tests/Composer/Test/InstalledVersionsTest.php b/tests/Composer/Test/InstalledVersionsTest.php index c1f4bb122..2d8799727 100644 --- a/tests/Composer/Test/InstalledVersionsTest.php +++ b/tests/Composer/Test/InstalledVersionsTest.php @@ -17,6 +17,20 @@ use Composer\Semver\VersionParser; class InstalledVersionsTest extends TestCase { + public static function setUpBeforeClass() + { + // disable multiple-ClassLoader-based checks of InstalledVersions by making it seem like no + // class loaders are registered + $prop = new \ReflectionProperty('Composer\Autoload\ClassLoader', 'registeredLoaders'); + $prop->setAccessible(true); + $prop->setValue(array()); + } + + public static function tearDownAfterClass() + { + self::setUpBeforeClass(); + } + public function setUp() { InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php'); diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php index 0df2545f5..61490b4c4 100644 --- a/tests/Composer/Test/Json/JsonManipulatorTest.php +++ b/tests/Composer/Test/Json/JsonManipulatorTest.php @@ -2564,6 +2564,1312 @@ class JsonManipulatorTest extends TestCase "foo/baz": "^1.0" } } +', $manipulator->getContents()); + } + + public function testLargeFileDoesNotCauseBacktrackLimitErrorGithubIssue9595() + { + $manipulator = new JsonManipulator('{ + "name": "leoloso/pop", + "require": { + "php": "^7.4|^8.0", + "ext-mbstring": "*", + "brain/cortex": "~1.0.0", + "composer/installers": "~1.0", + "composer/semver": "^1.5", + "erusev/parsedown": "^1.7", + "guzzlehttp/guzzle": "~6.3", + "jrfnl/php-cast-to-type": "^2.0", + "league/pipeline": "^1.0", + "lkwdwrd/wp-muplugin-loader": "dev-feature-composer-v2", + "obsidian/polyfill-hrtime": "^0.1", + "psr/cache": "^1.0", + "symfony/cache": "^5.1", + "symfony/config": "^5.1", + "symfony/dependency-injection": "^5.1", + "symfony/dotenv": "^5.1", + "symfony/expression-language": "^5.1", + "symfony/polyfill-php72": "^1.18", + "symfony/polyfill-php73": "^1.18", + "symfony/polyfill-php74": "^1.18", + "symfony/polyfill-php80": "^1.18", + "symfony/property-access": "^5.1", + "symfony/yaml": "^5.1" + }, + "require-dev": { + "johnpbloch/wordpress": ">=5.5", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": ">=9.3", + "rector/rector": "^0.9", + "squizlabs/php_codesniffer": "^3.0", + "symfony/var-dumper": "^5.1", + "symplify/monorepo-builder": "^9.0", + "szepeviktor/phpstan-wordpress": "^0.6.2" + }, + "autoload": { + "psr-4": { + "GraphQLAPI\\\\ConvertCaseDirectives\\\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/src", + "GraphQLAPI\\\\GraphQLAPI\\\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/src", + "GraphQLAPI\\\\SchemaFeedback\\\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/src", + "GraphQLByPoP\\\\GraphQLClientsForWP\\\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/src", + "GraphQLByPoP\\\\GraphQLEndpointForWP\\\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/src", + "GraphQLByPoP\\\\GraphQLParser\\\\": "layers/GraphQLByPoP/packages/graphql-parser/src", + "GraphQLByPoP\\\\GraphQLQuery\\\\": "layers/GraphQLByPoP/packages/graphql-query/src", + "GraphQLByPoP\\\\GraphQLRequest\\\\": "layers/GraphQLByPoP/packages/graphql-request/src", + "GraphQLByPoP\\\\GraphQLServer\\\\": "layers/GraphQLByPoP/packages/graphql-server/src", + "Leoloso\\\\ExamplesForPoP\\\\": "layers/Misc/packages/examples-for-pop/src", + "PoPSchema\\\\BasicDirectives\\\\": "layers/Schema/packages/basic-directives/src", + "PoPSchema\\\\BlockMetadataWP\\\\": "layers/Schema/packages/block-metadata-for-wp/src", + "PoPSchema\\\\CDNDirective\\\\": "layers/Schema/packages/cdn-directive/src", + "PoPSchema\\\\CategoriesWP\\\\": "layers/Schema/packages/categories-wp/src", + "PoPSchema\\\\Categories\\\\": "layers/Schema/packages/categories/src", + "PoPSchema\\\\CommentMetaWP\\\\": "layers/Schema/packages/commentmeta-wp/src", + "PoPSchema\\\\CommentMeta\\\\": "layers/Schema/packages/commentmeta/src", + "PoPSchema\\\\CommentMutationsWP\\\\": "layers/Schema/packages/comment-mutations-wp/src", + "PoPSchema\\\\CommentMutations\\\\": "layers/Schema/packages/comment-mutations/src", + "PoPSchema\\\\CommentsWP\\\\": "layers/Schema/packages/comments-wp/src", + "PoPSchema\\\\Comments\\\\": "layers/Schema/packages/comments/src", + "PoPSchema\\\\ConvertCaseDirectives\\\\": "layers/Schema/packages/convert-case-directives/src", + "PoPSchema\\\\CustomPostMediaMutationsWP\\\\": "layers/Schema/packages/custompostmedia-mutations-wp/src", + "PoPSchema\\\\CustomPostMediaMutations\\\\": "layers/Schema/packages/custompostmedia-mutations/src", + "PoPSchema\\\\CustomPostMediaWP\\\\": "layers/Schema/packages/custompostmedia-wp/src", + "PoPSchema\\\\CustomPostMedia\\\\": "layers/Schema/packages/custompostmedia/src", + "PoPSchema\\\\CustomPostMetaWP\\\\": "layers/Schema/packages/custompostmeta-wp/src", + "PoPSchema\\\\CustomPostMeta\\\\": "layers/Schema/packages/custompostmeta/src", + "PoPSchema\\\\CustomPostMutationsWP\\\\": "layers/Schema/packages/custompost-mutations-wp/src", + "PoPSchema\\\\CustomPostMutations\\\\": "layers/Schema/packages/custompost-mutations/src", + "PoPSchema\\\\CustomPostsWP\\\\": "layers/Schema/packages/customposts-wp/src", + "PoPSchema\\\\CustomPosts\\\\": "layers/Schema/packages/customposts/src", + "PoPSchema\\\\EventMutationsWPEM\\\\": "layers/Schema/packages/event-mutations-wp-em/src", + "PoPSchema\\\\EventMutations\\\\": "layers/Schema/packages/event-mutations/src", + "PoPSchema\\\\EventsWPEM\\\\": "layers/Schema/packages/events-wp-em/src", + "PoPSchema\\\\Events\\\\": "layers/Schema/packages/events/src", + "PoPSchema\\\\EverythingElseWP\\\\": "layers/Schema/packages/everythingelse-wp/src", + "PoPSchema\\\\EverythingElse\\\\": "layers/Schema/packages/everythingelse/src", + "PoPSchema\\\\GenericCustomPosts\\\\": "layers/Schema/packages/generic-customposts/src", + "PoPSchema\\\\GoogleTranslateDirectiveForCustomPosts\\\\": "layers/Schema/packages/google-translate-directive-for-customposts/src", + "PoPSchema\\\\GoogleTranslateDirective\\\\": "layers/Schema/packages/google-translate-directive/src", + "PoPSchema\\\\HighlightsWP\\\\": "layers/Schema/packages/highlights-wp/src", + "PoPSchema\\\\Highlights\\\\": "layers/Schema/packages/highlights/src", + "PoPSchema\\\\LocationPostsWP\\\\": "layers/Schema/packages/locationposts-wp/src", + "PoPSchema\\\\LocationPosts\\\\": "layers/Schema/packages/locationposts/src", + "PoPSchema\\\\LocationsWPEM\\\\": "layers/Schema/packages/locations-wp-em/src", + "PoPSchema\\\\Locations\\\\": "layers/Schema/packages/locations/src", + "PoPSchema\\\\MediaWP\\\\": "layers/Schema/packages/media-wp/src", + "PoPSchema\\\\Media\\\\": "layers/Schema/packages/media/src", + "PoPSchema\\\\MenusWP\\\\": "layers/Schema/packages/menus-wp/src", + "PoPSchema\\\\Menus\\\\": "layers/Schema/packages/menus/src", + "PoPSchema\\\\MetaQueryWP\\\\": "layers/Schema/packages/metaquery-wp/src", + "PoPSchema\\\\MetaQuery\\\\": "layers/Schema/packages/metaquery/src", + "PoPSchema\\\\Meta\\\\": "layers/Schema/packages/meta/src", + "PoPSchema\\\\NotificationsWP\\\\": "layers/Schema/packages/notifications-wp/src", + "PoPSchema\\\\Notifications\\\\": "layers/Schema/packages/notifications/src", + "PoPSchema\\\\PagesWP\\\\": "layers/Schema/packages/pages-wp/src", + "PoPSchema\\\\Pages\\\\": "layers/Schema/packages/pages/src", + "PoPSchema\\\\PostMutations\\\\": "layers/Schema/packages/post-mutations/src", + "PoPSchema\\\\PostTagsWP\\\\": "layers/Schema/packages/post-tags-wp/src", + "PoPSchema\\\\PostTags\\\\": "layers/Schema/packages/post-tags/src", + "PoPSchema\\\\PostsWP\\\\": "layers/Schema/packages/posts-wp/src", + "PoPSchema\\\\Posts\\\\": "layers/Schema/packages/posts/src", + "PoPSchema\\\\QueriedObjectWP\\\\": "layers/Schema/packages/queriedobject-wp/src", + "PoPSchema\\\\QueriedObject\\\\": "layers/Schema/packages/queriedobject/src", + "PoPSchema\\\\SchemaCommons\\\\": "layers/Schema/packages/schema-commons/src", + "PoPSchema\\\\StancesWP\\\\": "layers/Schema/packages/stances-wp/src", + "PoPSchema\\\\Stances\\\\": "layers/Schema/packages/stances/src", + "PoPSchema\\\\TagsWP\\\\": "layers/Schema/packages/tags-wp/src", + "PoPSchema\\\\Tags\\\\": "layers/Schema/packages/tags/src", + "PoPSchema\\\\TaxonomiesWP\\\\": "layers/Schema/packages/taxonomies-wp/src", + "PoPSchema\\\\Taxonomies\\\\": "layers/Schema/packages/taxonomies/src", + "PoPSchema\\\\TaxonomyMetaWP\\\\": "layers/Schema/packages/taxonomymeta-wp/src", + "PoPSchema\\\\TaxonomyMeta\\\\": "layers/Schema/packages/taxonomymeta/src", + "PoPSchema\\\\TaxonomyQueryWP\\\\": "layers/Schema/packages/taxonomyquery-wp/src", + "PoPSchema\\\\TaxonomyQuery\\\\": "layers/Schema/packages/taxonomyquery/src", + "PoPSchema\\\\TranslateDirectiveACL\\\\": "layers/Schema/packages/translate-directive-acl/src", + "PoPSchema\\\\TranslateDirective\\\\": "layers/Schema/packages/translate-directive/src", + "PoPSchema\\\\UserMetaWP\\\\": "layers/Schema/packages/usermeta-wp/src", + "PoPSchema\\\\UserMeta\\\\": "layers/Schema/packages/usermeta/src", + "PoPSchema\\\\UserRolesACL\\\\": "layers/Schema/packages/user-roles-acl/src", + "PoPSchema\\\\UserRolesAccessControl\\\\": "layers/Schema/packages/user-roles-access-control/src", + "PoPSchema\\\\UserRolesWP\\\\": "layers/Schema/packages/user-roles-wp/src", + "PoPSchema\\\\UserRoles\\\\": "layers/Schema/packages/user-roles/src", + "PoPSchema\\\\UserStateAccessControl\\\\": "layers/Schema/packages/user-state-access-control/src", + "PoPSchema\\\\UserStateMutationsWP\\\\": "layers/Schema/packages/user-state-mutations-wp/src", + "PoPSchema\\\\UserStateMutations\\\\": "layers/Schema/packages/user-state-mutations/src", + "PoPSchema\\\\UserStateWP\\\\": "layers/Schema/packages/user-state-wp/src", + "PoPSchema\\\\UserState\\\\": "layers/Schema/packages/user-state/src", + "PoPSchema\\\\UsersWP\\\\": "layers/Schema/packages/users-wp/src", + "PoPSchema\\\\Users\\\\": "layers/Schema/packages/users/src", + "PoPSitesWassup\\\\CommentMutations\\\\": "layers/Wassup/packages/comment-mutations/src", + "PoPSitesWassup\\\\ContactUsMutations\\\\": "layers/Wassup/packages/contactus-mutations/src", + "PoPSitesWassup\\\\ContactUserMutations\\\\": "layers/Wassup/packages/contactuser-mutations/src", + "PoPSitesWassup\\\\CustomPostLinkMutations\\\\": "layers/Wassup/packages/custompostlink-mutations/src", + "PoPSitesWassup\\\\CustomPostMutations\\\\": "layers/Wassup/packages/custompost-mutations/src", + "PoPSitesWassup\\\\EventLinkMutations\\\\": "layers/Wassup/packages/eventlink-mutations/src", + "PoPSitesWassup\\\\EventMutations\\\\": "layers/Wassup/packages/event-mutations/src", + "PoPSitesWassup\\\\EverythingElseMutations\\\\": "layers/Wassup/packages/everythingelse-mutations/src", + "PoPSitesWassup\\\\FlagMutations\\\\": "layers/Wassup/packages/flag-mutations/src", + "PoPSitesWassup\\\\FormMutations\\\\": "layers/Wassup/packages/form-mutations/src", + "PoPSitesWassup\\\\GravityFormsMutations\\\\": "layers/Wassup/packages/gravityforms-mutations/src", + "PoPSitesWassup\\\\HighlightMutations\\\\": "layers/Wassup/packages/highlight-mutations/src", + "PoPSitesWassup\\\\LocationMutations\\\\": "layers/Wassup/packages/location-mutations/src", + "PoPSitesWassup\\\\LocationPostLinkMutations\\\\": "layers/Wassup/packages/locationpostlink-mutations/src", + "PoPSitesWassup\\\\LocationPostMutations\\\\": "layers/Wassup/packages/locationpost-mutations/src", + "PoPSitesWassup\\\\NewsletterMutations\\\\": "layers/Wassup/packages/newsletter-mutations/src", + "PoPSitesWassup\\\\NotificationMutations\\\\": "layers/Wassup/packages/notification-mutations/src", + "PoPSitesWassup\\\\PostLinkMutations\\\\": "layers/Wassup/packages/postlink-mutations/src", + "PoPSitesWassup\\\\PostMutations\\\\": "layers/Wassup/packages/post-mutations/src", + "PoPSitesWassup\\\\ShareMutations\\\\": "layers/Wassup/packages/share-mutations/src", + "PoPSitesWassup\\\\SocialNetworkMutations\\\\": "layers/Wassup/packages/socialnetwork-mutations/src", + "PoPSitesWassup\\\\StanceMutations\\\\": "layers/Wassup/packages/stance-mutations/src", + "PoPSitesWassup\\\\SystemMutations\\\\": "layers/Wassup/packages/system-mutations/src", + "PoPSitesWassup\\\\UserStateMutations\\\\": "layers/Wassup/packages/user-state-mutations/src", + "PoPSitesWassup\\\\VolunteerMutations\\\\": "layers/Wassup/packages/volunteer-mutations/src", + "PoPSitesWassup\\\\Wassup\\\\": "layers/Wassup/packages/wassup/src", + "PoP\\\\APIClients\\\\": "layers/API/packages/api-clients/src", + "PoP\\\\APIEndpointsForWP\\\\": "layers/API/packages/api-endpoints-for-wp/src", + "PoP\\\\APIEndpoints\\\\": "layers/API/packages/api-endpoints/src", + "PoP\\\\APIMirrorQuery\\\\": "layers/API/packages/api-mirrorquery/src", + "PoP\\\\API\\\\": "layers/API/packages/api/src", + "PoP\\\\AccessControl\\\\": "layers/Engine/packages/access-control/src", + "PoP\\\\ApplicationWP\\\\": "layers/SiteBuilder/packages/application-wp/src", + "PoP\\\\Application\\\\": "layers/SiteBuilder/packages/application/src", + "PoP\\\\Base36Definitions\\\\": "layers/SiteBuilder/packages/definitions-base36/src", + "PoP\\\\CacheControl\\\\": "layers/Engine/packages/cache-control/src", + "PoP\\\\ComponentModel\\\\": "layers/Engine/packages/component-model/src", + "PoP\\\\ConfigurableSchemaFeedback\\\\": "layers/Engine/packages/configurable-schema-feedback/src", + "PoP\\\\ConfigurationComponentModel\\\\": "layers/SiteBuilder/packages/component-model-configuration/src", + "PoP\\\\DefinitionPersistence\\\\": "layers/SiteBuilder/packages/definitionpersistence/src", + "PoP\\\\Definitions\\\\": "layers/Engine/packages/definitions/src", + "PoP\\\\EmojiDefinitions\\\\": "layers/SiteBuilder/packages/definitions-emoji/src", + "PoP\\\\EngineWP\\\\": "layers/Engine/packages/engine-wp/src", + "PoP\\\\Engine\\\\": "layers/Engine/packages/engine/src", + "PoP\\\\FieldQuery\\\\": "layers/Engine/packages/field-query/src", + "PoP\\\\FileStore\\\\": "layers/Engine/packages/filestore/src", + "PoP\\\\FunctionFields\\\\": "layers/Engine/packages/function-fields/src", + "PoP\\\\GraphQLAPI\\\\": "layers/API/packages/api-graphql/src", + "PoP\\\\GuzzleHelpers\\\\": "layers/Engine/packages/guzzle-helpers/src", + "PoP\\\\HooksWP\\\\": "layers/Engine/packages/hooks-wp/src", + "PoP\\\\Hooks\\\\": "layers/Engine/packages/hooks/src", + "PoP\\\\LooseContracts\\\\": "layers/Engine/packages/loosecontracts/src", + "PoP\\\\MandatoryDirectivesByConfiguration\\\\": "layers/Engine/packages/mandatory-directives-by-configuration/src", + "PoP\\\\ModuleRouting\\\\": "layers/Engine/packages/modulerouting/src", + "PoP\\\\Multisite\\\\": "layers/SiteBuilder/packages/multisite/src", + "PoP\\\\PoP\\\\": "src", + "PoP\\\\QueryParsing\\\\": "layers/Engine/packages/query-parsing/src", + "PoP\\\\RESTAPI\\\\": "layers/API/packages/api-rest/src", + "PoP\\\\ResourceLoader\\\\": "layers/SiteBuilder/packages/resourceloader/src", + "PoP\\\\Resources\\\\": "layers/SiteBuilder/packages/resources/src", + "PoP\\\\Root\\\\": "layers/Engine/packages/root/src", + "PoP\\\\RoutingWP\\\\": "layers/Engine/packages/routing-wp/src", + "PoP\\\\Routing\\\\": "layers/Engine/packages/routing/src", + "PoP\\\\SPA\\\\": "layers/SiteBuilder/packages/spa/src", + "PoP\\\\SSG\\\\": "layers/SiteBuilder/packages/static-site-generator/src", + "PoP\\\\SiteWP\\\\": "layers/SiteBuilder/packages/site-wp/src", + "PoP\\\\Site\\\\": "layers/SiteBuilder/packages/site/src", + "PoP\\\\TraceTools\\\\": "layers/Engine/packages/trace-tools/src", + "PoP\\\\TranslationWP\\\\": "layers/Engine/packages/translation-wp/src", + "PoP\\\\Translation\\\\": "layers/Engine/packages/translation/src" + } + }, + "autoload-dev": { + "psr-4": { + "GraphQLAPI\\\\ConvertCaseDirectives\\\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/tests", + "GraphQLAPI\\\\GraphQLAPI\\\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/tests", + "GraphQLAPI\\\\SchemaFeedback\\\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/tests", + "GraphQLByPoP\\\\GraphQLClientsForWP\\\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/tests", + "GraphQLByPoP\\\\GraphQLEndpointForWP\\\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/tests", + "GraphQLByPoP\\\\GraphQLParser\\\\": "layers/GraphQLByPoP/packages/graphql-parser/tests", + "GraphQLByPoP\\\\GraphQLQuery\\\\": "layers/GraphQLByPoP/packages/graphql-query/tests", + "GraphQLByPoP\\\\GraphQLRequest\\\\": "layers/GraphQLByPoP/packages/graphql-request/tests", + "GraphQLByPoP\\\\GraphQLServer\\\\": "layers/GraphQLByPoP/packages/graphql-server/tests", + "Leoloso\\\\ExamplesForPoP\\\\": "layers/Misc/packages/examples-for-pop/tests", + "PoPSchema\\\\BasicDirectives\\\\": "layers/Schema/packages/basic-directives/tests", + "PoPSchema\\\\BlockMetadataWP\\\\": "layers/Schema/packages/block-metadata-for-wp/tests", + "PoPSchema\\\\CDNDirective\\\\": "layers/Schema/packages/cdn-directive/tests", + "PoPSchema\\\\CategoriesWP\\\\": "layers/Schema/packages/categories-wp/tests", + "PoPSchema\\\\Categories\\\\": "layers/Schema/packages/categories/tests", + "PoPSchema\\\\CommentMetaWP\\\\": "layers/Schema/packages/commentmeta-wp/tests", + "PoPSchema\\\\CommentMeta\\\\": "layers/Schema/packages/commentmeta/tests", + "PoPSchema\\\\CommentMutationsWP\\\\": "layers/Schema/packages/comment-mutations-wp/tests", + "PoPSchema\\\\CommentMutations\\\\": "layers/Schema/packages/comment-mutations/tests", + "PoPSchema\\\\CommentsWP\\\\": "layers/Schema/packages/comments-wp/tests", + "PoPSchema\\\\Comments\\\\": "layers/Schema/packages/comments/tests", + "PoPSchema\\\\ConvertCaseDirectives\\\\": "layers/Schema/packages/convert-case-directives/tests", + "PoPSchema\\\\CustomPostMediaMutationsWP\\\\": "layers/Schema/packages/custompostmedia-mutations-wp/tests", + "PoPSchema\\\\CustomPostMediaMutations\\\\": "layers/Schema/packages/custompostmedia-mutations/tests", + "PoPSchema\\\\CustomPostMediaWP\\\\": "layers/Schema/packages/custompostmedia-wp/tests", + "PoPSchema\\\\CustomPostMedia\\\\": "layers/Schema/packages/custompostmedia/tests", + "PoPSchema\\\\CustomPostMetaWP\\\\": "layers/Schema/packages/custompostmeta-wp/tests", + "PoPSchema\\\\CustomPostMeta\\\\": "layers/Schema/packages/custompostmeta/tests", + "PoPSchema\\\\CustomPostMutationsWP\\\\": "layers/Schema/packages/custompost-mutations-wp/tests", + "PoPSchema\\\\CustomPostMutations\\\\": "layers/Schema/packages/custompost-mutations/tests", + "PoPSchema\\\\CustomPostsWP\\\\": "layers/Schema/packages/customposts-wp/tests", + "PoPSchema\\\\CustomPosts\\\\": "layers/Schema/packages/customposts/tests", + "PoPSchema\\\\EventMutationsWPEM\\\\": "layers/Schema/packages/event-mutations-wp-em/tests", + "PoPSchema\\\\EventMutations\\\\": "layers/Schema/packages/event-mutations/tests", + "PoPSchema\\\\EventsWPEM\\\\": "layers/Schema/packages/events-wp-em/tests", + "PoPSchema\\\\Events\\\\": "layers/Schema/packages/events/tests", + "PoPSchema\\\\EverythingElseWP\\\\": "layers/Schema/packages/everythingelse-wp/tests", + "PoPSchema\\\\EverythingElse\\\\": "layers/Schema/packages/everythingelse/tests", + "PoPSchema\\\\GenericCustomPosts\\\\": "layers/Schema/packages/generic-customposts/tests", + "PoPSchema\\\\GoogleTranslateDirectiveForCustomPosts\\\\": "layers/Schema/packages/google-translate-directive-for-customposts/tests", + "PoPSchema\\\\GoogleTranslateDirective\\\\": "layers/Schema/packages/google-translate-directive/tests", + "PoPSchema\\\\HighlightsWP\\\\": "layers/Schema/packages/highlights-wp/tests", + "PoPSchema\\\\Highlights\\\\": "layers/Schema/packages/highlights/tests", + "PoPSchema\\\\LocationPostsWP\\\\": "layers/Schema/packages/locationposts-wp/tests", + "PoPSchema\\\\LocationPosts\\\\": "layers/Schema/packages/locationposts/tests", + "PoPSchema\\\\LocationsWPEM\\\\": "layers/Schema/packages/locations-wp-em/tests", + "PoPSchema\\\\Locations\\\\": "layers/Schema/packages/locations/tests", + "PoPSchema\\\\MediaWP\\\\": "layers/Schema/packages/media-wp/tests", + "PoPSchema\\\\Media\\\\": "layers/Schema/packages/media/tests", + "PoPSchema\\\\MenusWP\\\\": "layers/Schema/packages/menus-wp/tests", + "PoPSchema\\\\Menus\\\\": "layers/Schema/packages/menus/tests", + "PoPSchema\\\\MetaQueryWP\\\\": "layers/Schema/packages/metaquery-wp/tests", + "PoPSchema\\\\MetaQuery\\\\": "layers/Schema/packages/metaquery/tests", + "PoPSchema\\\\Meta\\\\": "layers/Schema/packages/meta/tests", + "PoPSchema\\\\NotificationsWP\\\\": "layers/Schema/packages/notifications-wp/tests", + "PoPSchema\\\\Notifications\\\\": "layers/Schema/packages/notifications/tests", + "PoPSchema\\\\PagesWP\\\\": "layers/Schema/packages/pages-wp/tests", + "PoPSchema\\\\Pages\\\\": "layers/Schema/packages/pages/tests", + "PoPSchema\\\\PostMutations\\\\": "layers/Schema/packages/post-mutations/tests", + "PoPSchema\\\\PostTagsWP\\\\": "layers/Schema/packages/post-tags-wp/tests", + "PoPSchema\\\\PostTags\\\\": "layers/Schema/packages/post-tags/tests", + "PoPSchema\\\\PostsWP\\\\": "layers/Schema/packages/posts-wp/tests", + "PoPSchema\\\\Posts\\\\": "layers/Schema/packages/posts/tests", + "PoPSchema\\\\QueriedObjectWP\\\\": "layers/Schema/packages/queriedobject-wp/tests", + "PoPSchema\\\\QueriedObject\\\\": "layers/Schema/packages/queriedobject/tests", + "PoPSchema\\\\SchemaCommons\\\\": "layers/Schema/packages/schema-commons/tests", + "PoPSchema\\\\StancesWP\\\\": "layers/Schema/packages/stances-wp/tests", + "PoPSchema\\\\Stances\\\\": "layers/Schema/packages/stances/tests", + "PoPSchema\\\\TagsWP\\\\": "layers/Schema/packages/tags-wp/tests", + "PoPSchema\\\\Tags\\\\": "layers/Schema/packages/tags/tests", + "PoPSchema\\\\TaxonomiesWP\\\\": "layers/Schema/packages/taxonomies-wp/tests", + "PoPSchema\\\\Taxonomies\\\\": "layers/Schema/packages/taxonomies/tests", + "PoPSchema\\\\TaxonomyMetaWP\\\\": "layers/Schema/packages/taxonomymeta-wp/tests", + "PoPSchema\\\\TaxonomyMeta\\\\": "layers/Schema/packages/taxonomymeta/tests", + "PoPSchema\\\\TaxonomyQueryWP\\\\": "layers/Schema/packages/taxonomyquery-wp/tests", + "PoPSchema\\\\TaxonomyQuery\\\\": "layers/Schema/packages/taxonomyquery/tests", + "PoPSchema\\\\TranslateDirectiveACL\\\\": "layers/Schema/packages/translate-directive-acl/tests", + "PoPSchema\\\\TranslateDirective\\\\": "layers/Schema/packages/translate-directive/tests", + "PoPSchema\\\\UserMetaWP\\\\": "layers/Schema/packages/usermeta-wp/tests", + "PoPSchema\\\\UserMeta\\\\": "layers/Schema/packages/usermeta/tests", + "PoPSchema\\\\UserRolesACL\\\\": "layers/Schema/packages/user-roles-acl/tests", + "PoPSchema\\\\UserRolesAccessControl\\\\": "layers/Schema/packages/user-roles-access-control/tests", + "PoPSchema\\\\UserRolesWP\\\\": "layers/Schema/packages/user-roles-wp/tests", + "PoPSchema\\\\UserRoles\\\\": "layers/Schema/packages/user-roles/tests", + "PoPSchema\\\\UserStateAccessControl\\\\": "layers/Schema/packages/user-state-access-control/tests", + "PoPSchema\\\\UserStateMutationsWP\\\\": "layers/Schema/packages/user-state-mutations-wp/tests", + "PoPSchema\\\\UserStateMutations\\\\": "layers/Schema/packages/user-state-mutations/tests", + "PoPSchema\\\\UserStateWP\\\\": "layers/Schema/packages/user-state-wp/tests", + "PoPSchema\\\\UserState\\\\": "layers/Schema/packages/user-state/tests", + "PoPSchema\\\\UsersWP\\\\": "layers/Schema/packages/users-wp/tests", + "PoPSchema\\\\Users\\\\": "layers/Schema/packages/users/tests", + "PoPSitesWassup\\\\CommentMutations\\\\": "layers/Wassup/packages/comment-mutations/tests", + "PoPSitesWassup\\\\ContactUsMutations\\\\": "layers/Wassup/packages/contactus-mutations/tests", + "PoPSitesWassup\\\\ContactUserMutations\\\\": "layers/Wassup/packages/contactuser-mutations/tests", + "PoPSitesWassup\\\\CustomPostLinkMutations\\\\": "layers/Wassup/packages/custompostlink-mutations/tests", + "PoPSitesWassup\\\\CustomPostMutations\\\\": "layers/Wassup/packages/custompost-mutations/tests", + "PoPSitesWassup\\\\EventLinkMutations\\\\": "layers/Wassup/packages/eventlink-mutations/tests", + "PoPSitesWassup\\\\EventMutations\\\\": "layers/Wassup/packages/event-mutations/tests", + "PoPSitesWassup\\\\EverythingElseMutations\\\\": "layers/Wassup/packages/everythingelse-mutations/tests", + "PoPSitesWassup\\\\FlagMutations\\\\": "layers/Wassup/packages/flag-mutations/tests", + "PoPSitesWassup\\\\FormMutations\\\\": "layers/Wassup/packages/form-mutations/tests", + "PoPSitesWassup\\\\GravityFormsMutations\\\\": "layers/Wassup/packages/gravityforms-mutations/tests", + "PoPSitesWassup\\\\HighlightMutations\\\\": "layers/Wassup/packages/highlight-mutations/tests", + "PoPSitesWassup\\\\LocationMutations\\\\": "layers/Wassup/packages/location-mutations/tests", + "PoPSitesWassup\\\\LocationPostLinkMutations\\\\": "layers/Wassup/packages/locationpostlink-mutations/tests", + "PoPSitesWassup\\\\LocationPostMutations\\\\": "layers/Wassup/packages/locationpost-mutations/tests", + "PoPSitesWassup\\\\NewsletterMutations\\\\": "layers/Wassup/packages/newsletter-mutations/tests", + "PoPSitesWassup\\\\NotificationMutations\\\\": "layers/Wassup/packages/notification-mutations/tests", + "PoPSitesWassup\\\\PostLinkMutations\\\\": "layers/Wassup/packages/postlink-mutations/tests", + "PoPSitesWassup\\\\PostMutations\\\\": "layers/Wassup/packages/post-mutations/tests", + "PoPSitesWassup\\\\ShareMutations\\\\": "layers/Wassup/packages/share-mutations/tests", + "PoPSitesWassup\\\\SocialNetworkMutations\\\\": "layers/Wassup/packages/socialnetwork-mutations/tests", + "PoPSitesWassup\\\\StanceMutations\\\\": "layers/Wassup/packages/stance-mutations/tests", + "PoPSitesWassup\\\\SystemMutations\\\\": "layers/Wassup/packages/system-mutations/tests", + "PoPSitesWassup\\\\UserStateMutations\\\\": "layers/Wassup/packages/user-state-mutations/tests", + "PoPSitesWassup\\\\VolunteerMutations\\\\": "layers/Wassup/packages/volunteer-mutations/tests", + "PoPSitesWassup\\\\Wassup\\\\": "layers/Wassup/packages/wassup/tests", + "PoP\\\\APIClients\\\\": "layers/API/packages/api-clients/tests", + "PoP\\\\APIEndpointsForWP\\\\": "layers/API/packages/api-endpoints-for-wp/tests", + "PoP\\\\APIEndpoints\\\\": "layers/API/packages/api-endpoints/tests", + "PoP\\\\APIMirrorQuery\\\\": "layers/API/packages/api-mirrorquery/tests", + "PoP\\\\API\\\\": "layers/API/packages/api/tests", + "PoP\\\\AccessControl\\\\": "layers/Engine/packages/access-control/tests", + "PoP\\\\ApplicationWP\\\\": "layers/SiteBuilder/packages/application-wp/tests", + "PoP\\\\Application\\\\": "layers/SiteBuilder/packages/application/tests", + "PoP\\\\Base36Definitions\\\\": "layers/SiteBuilder/packages/definitions-base36/tests", + "PoP\\\\CacheControl\\\\": "layers/Engine/packages/cache-control/tests", + "PoP\\\\ComponentModel\\\\": "layers/Engine/packages/component-model/tests", + "PoP\\\\ConfigurableSchemaFeedback\\\\": "layers/Engine/packages/configurable-schema-feedback/tests", + "PoP\\\\ConfigurationComponentModel\\\\": "layers/SiteBuilder/packages/component-model-configuration/tests", + "PoP\\\\DefinitionPersistence\\\\": "layers/SiteBuilder/packages/definitionpersistence/tests", + "PoP\\\\Definitions\\\\": "layers/Engine/packages/definitions/tests", + "PoP\\\\EmojiDefinitions\\\\": "layers/SiteBuilder/packages/definitions-emoji/tests", + "PoP\\\\EngineWP\\\\": "layers/Engine/packages/engine-wp/tests", + "PoP\\\\Engine\\\\": "layers/Engine/packages/engine/tests", + "PoP\\\\FieldQuery\\\\": "layers/Engine/packages/field-query/tests", + "PoP\\\\FileStore\\\\": "layers/Engine/packages/filestore/tests", + "PoP\\\\FunctionFields\\\\": "layers/Engine/packages/function-fields/tests", + "PoP\\\\GraphQLAPI\\\\": "layers/API/packages/api-graphql/tests", + "PoP\\\\GuzzleHelpers\\\\": "layers/Engine/packages/guzzle-helpers/tests", + "PoP\\\\HooksWP\\\\": "layers/Engine/packages/hooks-wp/tests", + "PoP\\\\Hooks\\\\": "layers/Engine/packages/hooks/tests", + "PoP\\\\LooseContracts\\\\": "layers/Engine/packages/loosecontracts/tests", + "PoP\\\\MandatoryDirectivesByConfiguration\\\\": "layers/Engine/packages/mandatory-directives-by-configuration/tests", + "PoP\\\\ModuleRouting\\\\": "layers/Engine/packages/modulerouting/tests", + "PoP\\\\Multisite\\\\": "layers/SiteBuilder/packages/multisite/tests", + "PoP\\\\QueryParsing\\\\": "layers/Engine/packages/query-parsing/tests", + "PoP\\\\RESTAPI\\\\": "layers/API/packages/api-rest/tests", + "PoP\\\\ResourceLoader\\\\": "layers/SiteBuilder/packages/resourceloader/tests", + "PoP\\\\Resources\\\\": "layers/SiteBuilder/packages/resources/tests", + "PoP\\\\Root\\\\": "layers/Engine/packages/root/tests", + "PoP\\\\RoutingWP\\\\": "layers/Engine/packages/routing-wp/tests", + "PoP\\\\Routing\\\\": "layers/Engine/packages/routing/tests", + "PoP\\\\SPA\\\\": "layers/SiteBuilder/packages/spa/tests", + "PoP\\\\SSG\\\\": "layers/SiteBuilder/packages/static-site-generator/tests", + "PoP\\\\SiteWP\\\\": "layers/SiteBuilder/packages/site-wp/tests", + "PoP\\\\Site\\\\": "layers/SiteBuilder/packages/site/tests", + "PoP\\\\TraceTools\\\\": "layers/Engine/packages/trace-tools/tests", + "PoP\\\\TranslationWP\\\\": "layers/Engine/packages/translation-wp/tests", + "PoP\\\\Translation\\\\": "layers/Engine/packages/translation/tests" + } + }, + "extra": { + "wordpress-install-dir": "vendor/wordpress/wordpress", + "merge-plugin": { + "include": [ + "composer.local.json" + ], + "recurse": true, + "replace": false, + "ignore-duplicates": false, + "merge-dev": true, + "merge-extra": false, + "merge-extra-deep": false, + "merge-scripts": false + } + }, + "replace": { + "getpop/access-control": "self.version", + "getpop/api": "self.version", + "getpop/api-clients": "self.version", + "getpop/api-endpoints": "self.version", + "getpop/api-endpoints-for-wp": "self.version", + "getpop/api-graphql": "self.version", + "getpop/api-mirrorquery": "self.version", + "getpop/api-rest": "self.version", + "getpop/application": "self.version", + "getpop/application-wp": "self.version", + "getpop/cache-control": "self.version", + "getpop/component-model": "self.version", + "getpop/component-model-configuration": "self.version", + "getpop/configurable-schema-feedback": "self.version", + "getpop/definitionpersistence": "self.version", + "getpop/definitions": "self.version", + "getpop/definitions-base36": "self.version", + "getpop/definitions-emoji": "self.version", + "getpop/engine": "self.version", + "getpop/engine-wp": "self.version", + "getpop/engine-wp-bootloader": "self.version", + "getpop/field-query": "self.version", + "getpop/filestore": "self.version", + "getpop/function-fields": "self.version", + "getpop/guzzle-helpers": "self.version", + "getpop/hooks": "self.version", + "getpop/hooks-wp": "self.version", + "getpop/loosecontracts": "self.version", + "getpop/mandatory-directives-by-configuration": "self.version", + "getpop/migrate-api": "self.version", + "getpop/migrate-api-graphql": "self.version", + "getpop/migrate-component-model": "self.version", + "getpop/migrate-component-model-configuration": "self.version", + "getpop/migrate-engine": "self.version", + "getpop/migrate-engine-wp": "self.version", + "getpop/migrate-static-site-generator": "self.version", + "getpop/modulerouting": "self.version", + "getpop/multisite": "self.version", + "getpop/query-parsing": "self.version", + "getpop/resourceloader": "self.version", + "getpop/resources": "self.version", + "getpop/root": "self.version", + "getpop/routing": "self.version", + "getpop/routing-wp": "self.version", + "getpop/site": "self.version", + "getpop/site-wp": "self.version", + "getpop/spa": "self.version", + "getpop/static-site-generator": "self.version", + "getpop/trace-tools": "self.version", + "getpop/translation": "self.version", + "getpop/translation-wp": "self.version", + "graphql-api/convert-case-directives": "self.version", + "graphql-api/graphql-api-for-wp": "self.version", + "graphql-api/schema-feedback": "self.version", + "graphql-by-pop/graphql-clients-for-wp": "self.version", + "graphql-by-pop/graphql-endpoint-for-wp": "self.version", + "graphql-by-pop/graphql-parser": "self.version", + "graphql-by-pop/graphql-query": "self.version", + "graphql-by-pop/graphql-request": "self.version", + "graphql-by-pop/graphql-server": "self.version", + "leoloso/examples-for-pop": "self.version", + "pop-migrate-everythingelse/cssconverter": "self.version", + "pop-migrate-everythingelse/ssr": "self.version", + "pop-schema/basic-directives": "self.version", + "pop-schema/block-metadata-for-wp": "self.version", + "pop-schema/categories": "self.version", + "pop-schema/categories-wp": "self.version", + "pop-schema/cdn-directive": "self.version", + "pop-schema/comment-mutations": "self.version", + "pop-schema/comment-mutations-wp": "self.version", + "pop-schema/commentmeta": "self.version", + "pop-schema/commentmeta-wp": "self.version", + "pop-schema/comments": "self.version", + "pop-schema/comments-wp": "self.version", + "pop-schema/convert-case-directives": "self.version", + "pop-schema/custompost-mutations": "self.version", + "pop-schema/custompost-mutations-wp": "self.version", + "pop-schema/custompostmedia": "self.version", + "pop-schema/custompostmedia-mutations": "self.version", + "pop-schema/custompostmedia-mutations-wp": "self.version", + "pop-schema/custompostmedia-wp": "self.version", + "pop-schema/custompostmeta": "self.version", + "pop-schema/custompostmeta-wp": "self.version", + "pop-schema/customposts": "self.version", + "pop-schema/customposts-wp": "self.version", + "pop-schema/event-mutations": "self.version", + "pop-schema/event-mutations-wp-em": "self.version", + "pop-schema/events": "self.version", + "pop-schema/events-wp-em": "self.version", + "pop-schema/everythingelse": "self.version", + "pop-schema/everythingelse-wp": "self.version", + "pop-schema/generic-customposts": "self.version", + "pop-schema/google-translate-directive": "self.version", + "pop-schema/google-translate-directive-for-customposts": "self.version", + "pop-schema/highlights": "self.version", + "pop-schema/highlights-wp": "self.version", + "pop-schema/locationposts": "self.version", + "pop-schema/locationposts-wp": "self.version", + "pop-schema/locations": "self.version", + "pop-schema/locations-wp-em": "self.version", + "pop-schema/media": "self.version", + "pop-schema/media-wp": "self.version", + "pop-schema/menus": "self.version", + "pop-schema/menus-wp": "self.version", + "pop-schema/meta": "self.version", + "pop-schema/metaquery": "self.version", + "pop-schema/metaquery-wp": "self.version", + "pop-schema/migrate-categories": "self.version", + "pop-schema/migrate-categories-wp": "self.version", + "pop-schema/migrate-commentmeta": "self.version", + "pop-schema/migrate-commentmeta-wp": "self.version", + "pop-schema/migrate-comments": "self.version", + "pop-schema/migrate-comments-wp": "self.version", + "pop-schema/migrate-custompostmedia": "self.version", + "pop-schema/migrate-custompostmedia-wp": "self.version", + "pop-schema/migrate-custompostmeta": "self.version", + "pop-schema/migrate-custompostmeta-wp": "self.version", + "pop-schema/migrate-customposts": "self.version", + "pop-schema/migrate-customposts-wp": "self.version", + "pop-schema/migrate-events": "self.version", + "pop-schema/migrate-events-wp-em": "self.version", + "pop-schema/migrate-everythingelse": "self.version", + "pop-schema/migrate-locations": "self.version", + "pop-schema/migrate-locations-wp-em": "self.version", + "pop-schema/migrate-media": "self.version", + "pop-schema/migrate-media-wp": "self.version", + "pop-schema/migrate-meta": "self.version", + "pop-schema/migrate-metaquery": "self.version", + "pop-schema/migrate-metaquery-wp": "self.version", + "pop-schema/migrate-pages": "self.version", + "pop-schema/migrate-pages-wp": "self.version", + "pop-schema/migrate-post-tags": "self.version", + "pop-schema/migrate-post-tags-wp": "self.version", + "pop-schema/migrate-posts": "self.version", + "pop-schema/migrate-posts-wp": "self.version", + "pop-schema/migrate-queriedobject": "self.version", + "pop-schema/migrate-queriedobject-wp": "self.version", + "pop-schema/migrate-tags": "self.version", + "pop-schema/migrate-tags-wp": "self.version", + "pop-schema/migrate-taxonomies": "self.version", + "pop-schema/migrate-taxonomies-wp": "self.version", + "pop-schema/migrate-taxonomymeta": "self.version", + "pop-schema/migrate-taxonomymeta-wp": "self.version", + "pop-schema/migrate-taxonomyquery": "self.version", + "pop-schema/migrate-taxonomyquery-wp": "self.version", + "pop-schema/migrate-usermeta": "self.version", + "pop-schema/migrate-usermeta-wp": "self.version", + "pop-schema/migrate-users": "self.version", + "pop-schema/migrate-users-wp": "self.version", + "pop-schema/notifications": "self.version", + "pop-schema/notifications-wp": "self.version", + "pop-schema/pages": "self.version", + "pop-schema/pages-wp": "self.version", + "pop-schema/post-mutations": "self.version", + "pop-schema/post-tags": "self.version", + "pop-schema/post-tags-wp": "self.version", + "pop-schema/posts": "self.version", + "pop-schema/posts-wp": "self.version", + "pop-schema/queriedobject": "self.version", + "pop-schema/queriedobject-wp": "self.version", + "pop-schema/schema-commons": "self.version", + "pop-schema/stances": "self.version", + "pop-schema/stances-wp": "self.version", + "pop-schema/tags": "self.version", + "pop-schema/tags-wp": "self.version", + "pop-schema/taxonomies": "self.version", + "pop-schema/taxonomies-wp": "self.version", + "pop-schema/taxonomymeta": "self.version", + "pop-schema/taxonomymeta-wp": "self.version", + "pop-schema/taxonomyquery": "self.version", + "pop-schema/taxonomyquery-wp": "self.version", + "pop-schema/translate-directive": "self.version", + "pop-schema/translate-directive-acl": "self.version", + "pop-schema/user-roles": "self.version", + "pop-schema/user-roles-access-control": "self.version", + "pop-schema/user-roles-acl": "self.version", + "pop-schema/user-roles-wp": "self.version", + "pop-schema/user-state": "self.version", + "pop-schema/user-state-access-control": "self.version", + "pop-schema/user-state-mutations": "self.version", + "pop-schema/user-state-mutations-wp": "self.version", + "pop-schema/user-state-wp": "self.version", + "pop-schema/usermeta": "self.version", + "pop-schema/usermeta-wp": "self.version", + "pop-schema/users": "self.version", + "pop-schema/users-wp": "self.version", + "pop-sites-wassup/comment-mutations": "self.version", + "pop-sites-wassup/contactus-mutations": "self.version", + "pop-sites-wassup/contactuser-mutations": "self.version", + "pop-sites-wassup/custompost-mutations": "self.version", + "pop-sites-wassup/custompostlink-mutations": "self.version", + "pop-sites-wassup/event-mutations": "self.version", + "pop-sites-wassup/eventlink-mutations": "self.version", + "pop-sites-wassup/everythingelse-mutations": "self.version", + "pop-sites-wassup/flag-mutations": "self.version", + "pop-sites-wassup/form-mutations": "self.version", + "pop-sites-wassup/gravityforms-mutations": "self.version", + "pop-sites-wassup/highlight-mutations": "self.version", + "pop-sites-wassup/location-mutations": "self.version", + "pop-sites-wassup/locationpost-mutations": "self.version", + "pop-sites-wassup/locationpostlink-mutations": "self.version", + "pop-sites-wassup/newsletter-mutations": "self.version", + "pop-sites-wassup/notification-mutations": "self.version", + "pop-sites-wassup/post-mutations": "self.version", + "pop-sites-wassup/postlink-mutations": "self.version", + "pop-sites-wassup/share-mutations": "self.version", + "pop-sites-wassup/socialnetwork-mutations": "self.version", + "pop-sites-wassup/stance-mutations": "self.version", + "pop-sites-wassup/system-mutations": "self.version", + "pop-sites-wassup/user-state-mutations": "self.version", + "pop-sites-wassup/volunteer-mutations": "self.version", + "pop-sites-wassup/wassup": "self.version" + }, + "authors": [ + { + "name": "Leonardo Losoviz", + "email": "leo@getpop.org", + "homepage": "https://getpop.org" + } + ], + "description": "Monorepo for all the PoP packages", + "license": "GPL-2.0-or-later", + "config": { + "sort-packages": true + }, + "repositories": [ + { + "type": "composer", + "url": "https://wpackagist.org" + }, + { + "type": "vcs", + "url": "https://github.com/leoloso/wp-muplugin-loader.git" + }, + { + "type": "vcs", + "url": "https://github.com/mcaskill/composer-merge-plugin.git" + } + ], + "scripts": { + "test": "phpunit", + "check-style": "phpcs -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)", + "fix-style": "phpcbf -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)", + "analyse": "ci/phpstan.sh \\". $(monorepo-builder source-packages --skip-unmigrated)\\"", + "preview-src-downgrade": "rector process $(monorepo-builder source-packages --subfolder=src) --config=rector-downgrade-code.php --ansi --dry-run || true", + "preview-vendor-downgrade": "layers/Engine/packages/root/ci/downgrade_code.sh 7.1 rector-downgrade-code.php --dry-run || true", + "preview-code-downgrade": [ + "@preview-src-downgrade", + "@preview-vendor-downgrade" + ], + "build-server": [ + "lando init --source remote --remote-url https://wordpress.org/latest.tar.gz --recipe wordpress --webroot wordpress --name graphql-api-dev", + "@start-server" + ], + "start-server": [ + "cd layers/GraphQLAPIForWP/plugins/graphql-api-for-wp && composer install", + "lando start" + ], + "rebuild-server": "lando rebuild -y", + "merge-monorepo": "monorepo-builder merge --ansi", + "propagate-monorepo": "monorepo-builder propagate --ansi", + "validate-monorepo": "monorepo-builder validate --ansi", + "release": "monorepo-builder release patch --ansi" + }, + "minimum-stability": "dev", + "prefer-stable": true +}'); + + $this->assertTrue($manipulator->addSubNode('config', 'platform-check', false)); + $this->assertEquals('{ + "name": "leoloso/pop", + "require": { + "php": "^7.4|^8.0", + "ext-mbstring": "*", + "brain/cortex": "~1.0.0", + "composer/installers": "~1.0", + "composer/semver": "^1.5", + "erusev/parsedown": "^1.7", + "guzzlehttp/guzzle": "~6.3", + "jrfnl/php-cast-to-type": "^2.0", + "league/pipeline": "^1.0", + "lkwdwrd/wp-muplugin-loader": "dev-feature-composer-v2", + "obsidian/polyfill-hrtime": "^0.1", + "psr/cache": "^1.0", + "symfony/cache": "^5.1", + "symfony/config": "^5.1", + "symfony/dependency-injection": "^5.1", + "symfony/dotenv": "^5.1", + "symfony/expression-language": "^5.1", + "symfony/polyfill-php72": "^1.18", + "symfony/polyfill-php73": "^1.18", + "symfony/polyfill-php74": "^1.18", + "symfony/polyfill-php80": "^1.18", + "symfony/property-access": "^5.1", + "symfony/yaml": "^5.1" + }, + "require-dev": { + "johnpbloch/wordpress": ">=5.5", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": ">=9.3", + "rector/rector": "^0.9", + "squizlabs/php_codesniffer": "^3.0", + "symfony/var-dumper": "^5.1", + "symplify/monorepo-builder": "^9.0", + "szepeviktor/phpstan-wordpress": "^0.6.2" + }, + "autoload": { + "psr-4": { + "GraphQLAPI\\\\ConvertCaseDirectives\\\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/src", + "GraphQLAPI\\\\GraphQLAPI\\\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/src", + "GraphQLAPI\\\\SchemaFeedback\\\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/src", + "GraphQLByPoP\\\\GraphQLClientsForWP\\\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/src", + "GraphQLByPoP\\\\GraphQLEndpointForWP\\\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/src", + "GraphQLByPoP\\\\GraphQLParser\\\\": "layers/GraphQLByPoP/packages/graphql-parser/src", + "GraphQLByPoP\\\\GraphQLQuery\\\\": "layers/GraphQLByPoP/packages/graphql-query/src", + "GraphQLByPoP\\\\GraphQLRequest\\\\": "layers/GraphQLByPoP/packages/graphql-request/src", + "GraphQLByPoP\\\\GraphQLServer\\\\": "layers/GraphQLByPoP/packages/graphql-server/src", + "Leoloso\\\\ExamplesForPoP\\\\": "layers/Misc/packages/examples-for-pop/src", + "PoPSchema\\\\BasicDirectives\\\\": "layers/Schema/packages/basic-directives/src", + "PoPSchema\\\\BlockMetadataWP\\\\": "layers/Schema/packages/block-metadata-for-wp/src", + "PoPSchema\\\\CDNDirective\\\\": "layers/Schema/packages/cdn-directive/src", + "PoPSchema\\\\CategoriesWP\\\\": "layers/Schema/packages/categories-wp/src", + "PoPSchema\\\\Categories\\\\": "layers/Schema/packages/categories/src", + "PoPSchema\\\\CommentMetaWP\\\\": "layers/Schema/packages/commentmeta-wp/src", + "PoPSchema\\\\CommentMeta\\\\": "layers/Schema/packages/commentmeta/src", + "PoPSchema\\\\CommentMutationsWP\\\\": "layers/Schema/packages/comment-mutations-wp/src", + "PoPSchema\\\\CommentMutations\\\\": "layers/Schema/packages/comment-mutations/src", + "PoPSchema\\\\CommentsWP\\\\": "layers/Schema/packages/comments-wp/src", + "PoPSchema\\\\Comments\\\\": "layers/Schema/packages/comments/src", + "PoPSchema\\\\ConvertCaseDirectives\\\\": "layers/Schema/packages/convert-case-directives/src", + "PoPSchema\\\\CustomPostMediaMutationsWP\\\\": "layers/Schema/packages/custompostmedia-mutations-wp/src", + "PoPSchema\\\\CustomPostMediaMutations\\\\": "layers/Schema/packages/custompostmedia-mutations/src", + "PoPSchema\\\\CustomPostMediaWP\\\\": "layers/Schema/packages/custompostmedia-wp/src", + "PoPSchema\\\\CustomPostMedia\\\\": "layers/Schema/packages/custompostmedia/src", + "PoPSchema\\\\CustomPostMetaWP\\\\": "layers/Schema/packages/custompostmeta-wp/src", + "PoPSchema\\\\CustomPostMeta\\\\": "layers/Schema/packages/custompostmeta/src", + "PoPSchema\\\\CustomPostMutationsWP\\\\": "layers/Schema/packages/custompost-mutations-wp/src", + "PoPSchema\\\\CustomPostMutations\\\\": "layers/Schema/packages/custompost-mutations/src", + "PoPSchema\\\\CustomPostsWP\\\\": "layers/Schema/packages/customposts-wp/src", + "PoPSchema\\\\CustomPosts\\\\": "layers/Schema/packages/customposts/src", + "PoPSchema\\\\EventMutationsWPEM\\\\": "layers/Schema/packages/event-mutations-wp-em/src", + "PoPSchema\\\\EventMutations\\\\": "layers/Schema/packages/event-mutations/src", + "PoPSchema\\\\EventsWPEM\\\\": "layers/Schema/packages/events-wp-em/src", + "PoPSchema\\\\Events\\\\": "layers/Schema/packages/events/src", + "PoPSchema\\\\EverythingElseWP\\\\": "layers/Schema/packages/everythingelse-wp/src", + "PoPSchema\\\\EverythingElse\\\\": "layers/Schema/packages/everythingelse/src", + "PoPSchema\\\\GenericCustomPosts\\\\": "layers/Schema/packages/generic-customposts/src", + "PoPSchema\\\\GoogleTranslateDirectiveForCustomPosts\\\\": "layers/Schema/packages/google-translate-directive-for-customposts/src", + "PoPSchema\\\\GoogleTranslateDirective\\\\": "layers/Schema/packages/google-translate-directive/src", + "PoPSchema\\\\HighlightsWP\\\\": "layers/Schema/packages/highlights-wp/src", + "PoPSchema\\\\Highlights\\\\": "layers/Schema/packages/highlights/src", + "PoPSchema\\\\LocationPostsWP\\\\": "layers/Schema/packages/locationposts-wp/src", + "PoPSchema\\\\LocationPosts\\\\": "layers/Schema/packages/locationposts/src", + "PoPSchema\\\\LocationsWPEM\\\\": "layers/Schema/packages/locations-wp-em/src", + "PoPSchema\\\\Locations\\\\": "layers/Schema/packages/locations/src", + "PoPSchema\\\\MediaWP\\\\": "layers/Schema/packages/media-wp/src", + "PoPSchema\\\\Media\\\\": "layers/Schema/packages/media/src", + "PoPSchema\\\\MenusWP\\\\": "layers/Schema/packages/menus-wp/src", + "PoPSchema\\\\Menus\\\\": "layers/Schema/packages/menus/src", + "PoPSchema\\\\MetaQueryWP\\\\": "layers/Schema/packages/metaquery-wp/src", + "PoPSchema\\\\MetaQuery\\\\": "layers/Schema/packages/metaquery/src", + "PoPSchema\\\\Meta\\\\": "layers/Schema/packages/meta/src", + "PoPSchema\\\\NotificationsWP\\\\": "layers/Schema/packages/notifications-wp/src", + "PoPSchema\\\\Notifications\\\\": "layers/Schema/packages/notifications/src", + "PoPSchema\\\\PagesWP\\\\": "layers/Schema/packages/pages-wp/src", + "PoPSchema\\\\Pages\\\\": "layers/Schema/packages/pages/src", + "PoPSchema\\\\PostMutations\\\\": "layers/Schema/packages/post-mutations/src", + "PoPSchema\\\\PostTagsWP\\\\": "layers/Schema/packages/post-tags-wp/src", + "PoPSchema\\\\PostTags\\\\": "layers/Schema/packages/post-tags/src", + "PoPSchema\\\\PostsWP\\\\": "layers/Schema/packages/posts-wp/src", + "PoPSchema\\\\Posts\\\\": "layers/Schema/packages/posts/src", + "PoPSchema\\\\QueriedObjectWP\\\\": "layers/Schema/packages/queriedobject-wp/src", + "PoPSchema\\\\QueriedObject\\\\": "layers/Schema/packages/queriedobject/src", + "PoPSchema\\\\SchemaCommons\\\\": "layers/Schema/packages/schema-commons/src", + "PoPSchema\\\\StancesWP\\\\": "layers/Schema/packages/stances-wp/src", + "PoPSchema\\\\Stances\\\\": "layers/Schema/packages/stances/src", + "PoPSchema\\\\TagsWP\\\\": "layers/Schema/packages/tags-wp/src", + "PoPSchema\\\\Tags\\\\": "layers/Schema/packages/tags/src", + "PoPSchema\\\\TaxonomiesWP\\\\": "layers/Schema/packages/taxonomies-wp/src", + "PoPSchema\\\\Taxonomies\\\\": "layers/Schema/packages/taxonomies/src", + "PoPSchema\\\\TaxonomyMetaWP\\\\": "layers/Schema/packages/taxonomymeta-wp/src", + "PoPSchema\\\\TaxonomyMeta\\\\": "layers/Schema/packages/taxonomymeta/src", + "PoPSchema\\\\TaxonomyQueryWP\\\\": "layers/Schema/packages/taxonomyquery-wp/src", + "PoPSchema\\\\TaxonomyQuery\\\\": "layers/Schema/packages/taxonomyquery/src", + "PoPSchema\\\\TranslateDirectiveACL\\\\": "layers/Schema/packages/translate-directive-acl/src", + "PoPSchema\\\\TranslateDirective\\\\": "layers/Schema/packages/translate-directive/src", + "PoPSchema\\\\UserMetaWP\\\\": "layers/Schema/packages/usermeta-wp/src", + "PoPSchema\\\\UserMeta\\\\": "layers/Schema/packages/usermeta/src", + "PoPSchema\\\\UserRolesACL\\\\": "layers/Schema/packages/user-roles-acl/src", + "PoPSchema\\\\UserRolesAccessControl\\\\": "layers/Schema/packages/user-roles-access-control/src", + "PoPSchema\\\\UserRolesWP\\\\": "layers/Schema/packages/user-roles-wp/src", + "PoPSchema\\\\UserRoles\\\\": "layers/Schema/packages/user-roles/src", + "PoPSchema\\\\UserStateAccessControl\\\\": "layers/Schema/packages/user-state-access-control/src", + "PoPSchema\\\\UserStateMutationsWP\\\\": "layers/Schema/packages/user-state-mutations-wp/src", + "PoPSchema\\\\UserStateMutations\\\\": "layers/Schema/packages/user-state-mutations/src", + "PoPSchema\\\\UserStateWP\\\\": "layers/Schema/packages/user-state-wp/src", + "PoPSchema\\\\UserState\\\\": "layers/Schema/packages/user-state/src", + "PoPSchema\\\\UsersWP\\\\": "layers/Schema/packages/users-wp/src", + "PoPSchema\\\\Users\\\\": "layers/Schema/packages/users/src", + "PoPSitesWassup\\\\CommentMutations\\\\": "layers/Wassup/packages/comment-mutations/src", + "PoPSitesWassup\\\\ContactUsMutations\\\\": "layers/Wassup/packages/contactus-mutations/src", + "PoPSitesWassup\\\\ContactUserMutations\\\\": "layers/Wassup/packages/contactuser-mutations/src", + "PoPSitesWassup\\\\CustomPostLinkMutations\\\\": "layers/Wassup/packages/custompostlink-mutations/src", + "PoPSitesWassup\\\\CustomPostMutations\\\\": "layers/Wassup/packages/custompost-mutations/src", + "PoPSitesWassup\\\\EventLinkMutations\\\\": "layers/Wassup/packages/eventlink-mutations/src", + "PoPSitesWassup\\\\EventMutations\\\\": "layers/Wassup/packages/event-mutations/src", + "PoPSitesWassup\\\\EverythingElseMutations\\\\": "layers/Wassup/packages/everythingelse-mutations/src", + "PoPSitesWassup\\\\FlagMutations\\\\": "layers/Wassup/packages/flag-mutations/src", + "PoPSitesWassup\\\\FormMutations\\\\": "layers/Wassup/packages/form-mutations/src", + "PoPSitesWassup\\\\GravityFormsMutations\\\\": "layers/Wassup/packages/gravityforms-mutations/src", + "PoPSitesWassup\\\\HighlightMutations\\\\": "layers/Wassup/packages/highlight-mutations/src", + "PoPSitesWassup\\\\LocationMutations\\\\": "layers/Wassup/packages/location-mutations/src", + "PoPSitesWassup\\\\LocationPostLinkMutations\\\\": "layers/Wassup/packages/locationpostlink-mutations/src", + "PoPSitesWassup\\\\LocationPostMutations\\\\": "layers/Wassup/packages/locationpost-mutations/src", + "PoPSitesWassup\\\\NewsletterMutations\\\\": "layers/Wassup/packages/newsletter-mutations/src", + "PoPSitesWassup\\\\NotificationMutations\\\\": "layers/Wassup/packages/notification-mutations/src", + "PoPSitesWassup\\\\PostLinkMutations\\\\": "layers/Wassup/packages/postlink-mutations/src", + "PoPSitesWassup\\\\PostMutations\\\\": "layers/Wassup/packages/post-mutations/src", + "PoPSitesWassup\\\\ShareMutations\\\\": "layers/Wassup/packages/share-mutations/src", + "PoPSitesWassup\\\\SocialNetworkMutations\\\\": "layers/Wassup/packages/socialnetwork-mutations/src", + "PoPSitesWassup\\\\StanceMutations\\\\": "layers/Wassup/packages/stance-mutations/src", + "PoPSitesWassup\\\\SystemMutations\\\\": "layers/Wassup/packages/system-mutations/src", + "PoPSitesWassup\\\\UserStateMutations\\\\": "layers/Wassup/packages/user-state-mutations/src", + "PoPSitesWassup\\\\VolunteerMutations\\\\": "layers/Wassup/packages/volunteer-mutations/src", + "PoPSitesWassup\\\\Wassup\\\\": "layers/Wassup/packages/wassup/src", + "PoP\\\\APIClients\\\\": "layers/API/packages/api-clients/src", + "PoP\\\\APIEndpointsForWP\\\\": "layers/API/packages/api-endpoints-for-wp/src", + "PoP\\\\APIEndpoints\\\\": "layers/API/packages/api-endpoints/src", + "PoP\\\\APIMirrorQuery\\\\": "layers/API/packages/api-mirrorquery/src", + "PoP\\\\API\\\\": "layers/API/packages/api/src", + "PoP\\\\AccessControl\\\\": "layers/Engine/packages/access-control/src", + "PoP\\\\ApplicationWP\\\\": "layers/SiteBuilder/packages/application-wp/src", + "PoP\\\\Application\\\\": "layers/SiteBuilder/packages/application/src", + "PoP\\\\Base36Definitions\\\\": "layers/SiteBuilder/packages/definitions-base36/src", + "PoP\\\\CacheControl\\\\": "layers/Engine/packages/cache-control/src", + "PoP\\\\ComponentModel\\\\": "layers/Engine/packages/component-model/src", + "PoP\\\\ConfigurableSchemaFeedback\\\\": "layers/Engine/packages/configurable-schema-feedback/src", + "PoP\\\\ConfigurationComponentModel\\\\": "layers/SiteBuilder/packages/component-model-configuration/src", + "PoP\\\\DefinitionPersistence\\\\": "layers/SiteBuilder/packages/definitionpersistence/src", + "PoP\\\\Definitions\\\\": "layers/Engine/packages/definitions/src", + "PoP\\\\EmojiDefinitions\\\\": "layers/SiteBuilder/packages/definitions-emoji/src", + "PoP\\\\EngineWP\\\\": "layers/Engine/packages/engine-wp/src", + "PoP\\\\Engine\\\\": "layers/Engine/packages/engine/src", + "PoP\\\\FieldQuery\\\\": "layers/Engine/packages/field-query/src", + "PoP\\\\FileStore\\\\": "layers/Engine/packages/filestore/src", + "PoP\\\\FunctionFields\\\\": "layers/Engine/packages/function-fields/src", + "PoP\\\\GraphQLAPI\\\\": "layers/API/packages/api-graphql/src", + "PoP\\\\GuzzleHelpers\\\\": "layers/Engine/packages/guzzle-helpers/src", + "PoP\\\\HooksWP\\\\": "layers/Engine/packages/hooks-wp/src", + "PoP\\\\Hooks\\\\": "layers/Engine/packages/hooks/src", + "PoP\\\\LooseContracts\\\\": "layers/Engine/packages/loosecontracts/src", + "PoP\\\\MandatoryDirectivesByConfiguration\\\\": "layers/Engine/packages/mandatory-directives-by-configuration/src", + "PoP\\\\ModuleRouting\\\\": "layers/Engine/packages/modulerouting/src", + "PoP\\\\Multisite\\\\": "layers/SiteBuilder/packages/multisite/src", + "PoP\\\\PoP\\\\": "src", + "PoP\\\\QueryParsing\\\\": "layers/Engine/packages/query-parsing/src", + "PoP\\\\RESTAPI\\\\": "layers/API/packages/api-rest/src", + "PoP\\\\ResourceLoader\\\\": "layers/SiteBuilder/packages/resourceloader/src", + "PoP\\\\Resources\\\\": "layers/SiteBuilder/packages/resources/src", + "PoP\\\\Root\\\\": "layers/Engine/packages/root/src", + "PoP\\\\RoutingWP\\\\": "layers/Engine/packages/routing-wp/src", + "PoP\\\\Routing\\\\": "layers/Engine/packages/routing/src", + "PoP\\\\SPA\\\\": "layers/SiteBuilder/packages/spa/src", + "PoP\\\\SSG\\\\": "layers/SiteBuilder/packages/static-site-generator/src", + "PoP\\\\SiteWP\\\\": "layers/SiteBuilder/packages/site-wp/src", + "PoP\\\\Site\\\\": "layers/SiteBuilder/packages/site/src", + "PoP\\\\TraceTools\\\\": "layers/Engine/packages/trace-tools/src", + "PoP\\\\TranslationWP\\\\": "layers/Engine/packages/translation-wp/src", + "PoP\\\\Translation\\\\": "layers/Engine/packages/translation/src" + } + }, + "autoload-dev": { + "psr-4": { + "GraphQLAPI\\\\ConvertCaseDirectives\\\\": "layers/GraphQLAPIForWP/plugins/convert-case-directives/tests", + "GraphQLAPI\\\\GraphQLAPI\\\\": "layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/tests", + "GraphQLAPI\\\\SchemaFeedback\\\\": "layers/GraphQLAPIForWP/plugins/schema-feedback/tests", + "GraphQLByPoP\\\\GraphQLClientsForWP\\\\": "layers/GraphQLByPoP/packages/graphql-clients-for-wp/tests", + "GraphQLByPoP\\\\GraphQLEndpointForWP\\\\": "layers/GraphQLByPoP/packages/graphql-endpoint-for-wp/tests", + "GraphQLByPoP\\\\GraphQLParser\\\\": "layers/GraphQLByPoP/packages/graphql-parser/tests", + "GraphQLByPoP\\\\GraphQLQuery\\\\": "layers/GraphQLByPoP/packages/graphql-query/tests", + "GraphQLByPoP\\\\GraphQLRequest\\\\": "layers/GraphQLByPoP/packages/graphql-request/tests", + "GraphQLByPoP\\\\GraphQLServer\\\\": "layers/GraphQLByPoP/packages/graphql-server/tests", + "Leoloso\\\\ExamplesForPoP\\\\": "layers/Misc/packages/examples-for-pop/tests", + "PoPSchema\\\\BasicDirectives\\\\": "layers/Schema/packages/basic-directives/tests", + "PoPSchema\\\\BlockMetadataWP\\\\": "layers/Schema/packages/block-metadata-for-wp/tests", + "PoPSchema\\\\CDNDirective\\\\": "layers/Schema/packages/cdn-directive/tests", + "PoPSchema\\\\CategoriesWP\\\\": "layers/Schema/packages/categories-wp/tests", + "PoPSchema\\\\Categories\\\\": "layers/Schema/packages/categories/tests", + "PoPSchema\\\\CommentMetaWP\\\\": "layers/Schema/packages/commentmeta-wp/tests", + "PoPSchema\\\\CommentMeta\\\\": "layers/Schema/packages/commentmeta/tests", + "PoPSchema\\\\CommentMutationsWP\\\\": "layers/Schema/packages/comment-mutations-wp/tests", + "PoPSchema\\\\CommentMutations\\\\": "layers/Schema/packages/comment-mutations/tests", + "PoPSchema\\\\CommentsWP\\\\": "layers/Schema/packages/comments-wp/tests", + "PoPSchema\\\\Comments\\\\": "layers/Schema/packages/comments/tests", + "PoPSchema\\\\ConvertCaseDirectives\\\\": "layers/Schema/packages/convert-case-directives/tests", + "PoPSchema\\\\CustomPostMediaMutationsWP\\\\": "layers/Schema/packages/custompostmedia-mutations-wp/tests", + "PoPSchema\\\\CustomPostMediaMutations\\\\": "layers/Schema/packages/custompostmedia-mutations/tests", + "PoPSchema\\\\CustomPostMediaWP\\\\": "layers/Schema/packages/custompostmedia-wp/tests", + "PoPSchema\\\\CustomPostMedia\\\\": "layers/Schema/packages/custompostmedia/tests", + "PoPSchema\\\\CustomPostMetaWP\\\\": "layers/Schema/packages/custompostmeta-wp/tests", + "PoPSchema\\\\CustomPostMeta\\\\": "layers/Schema/packages/custompostmeta/tests", + "PoPSchema\\\\CustomPostMutationsWP\\\\": "layers/Schema/packages/custompost-mutations-wp/tests", + "PoPSchema\\\\CustomPostMutations\\\\": "layers/Schema/packages/custompost-mutations/tests", + "PoPSchema\\\\CustomPostsWP\\\\": "layers/Schema/packages/customposts-wp/tests", + "PoPSchema\\\\CustomPosts\\\\": "layers/Schema/packages/customposts/tests", + "PoPSchema\\\\EventMutationsWPEM\\\\": "layers/Schema/packages/event-mutations-wp-em/tests", + "PoPSchema\\\\EventMutations\\\\": "layers/Schema/packages/event-mutations/tests", + "PoPSchema\\\\EventsWPEM\\\\": "layers/Schema/packages/events-wp-em/tests", + "PoPSchema\\\\Events\\\\": "layers/Schema/packages/events/tests", + "PoPSchema\\\\EverythingElseWP\\\\": "layers/Schema/packages/everythingelse-wp/tests", + "PoPSchema\\\\EverythingElse\\\\": "layers/Schema/packages/everythingelse/tests", + "PoPSchema\\\\GenericCustomPosts\\\\": "layers/Schema/packages/generic-customposts/tests", + "PoPSchema\\\\GoogleTranslateDirectiveForCustomPosts\\\\": "layers/Schema/packages/google-translate-directive-for-customposts/tests", + "PoPSchema\\\\GoogleTranslateDirective\\\\": "layers/Schema/packages/google-translate-directive/tests", + "PoPSchema\\\\HighlightsWP\\\\": "layers/Schema/packages/highlights-wp/tests", + "PoPSchema\\\\Highlights\\\\": "layers/Schema/packages/highlights/tests", + "PoPSchema\\\\LocationPostsWP\\\\": "layers/Schema/packages/locationposts-wp/tests", + "PoPSchema\\\\LocationPosts\\\\": "layers/Schema/packages/locationposts/tests", + "PoPSchema\\\\LocationsWPEM\\\\": "layers/Schema/packages/locations-wp-em/tests", + "PoPSchema\\\\Locations\\\\": "layers/Schema/packages/locations/tests", + "PoPSchema\\\\MediaWP\\\\": "layers/Schema/packages/media-wp/tests", + "PoPSchema\\\\Media\\\\": "layers/Schema/packages/media/tests", + "PoPSchema\\\\MenusWP\\\\": "layers/Schema/packages/menus-wp/tests", + "PoPSchema\\\\Menus\\\\": "layers/Schema/packages/menus/tests", + "PoPSchema\\\\MetaQueryWP\\\\": "layers/Schema/packages/metaquery-wp/tests", + "PoPSchema\\\\MetaQuery\\\\": "layers/Schema/packages/metaquery/tests", + "PoPSchema\\\\Meta\\\\": "layers/Schema/packages/meta/tests", + "PoPSchema\\\\NotificationsWP\\\\": "layers/Schema/packages/notifications-wp/tests", + "PoPSchema\\\\Notifications\\\\": "layers/Schema/packages/notifications/tests", + "PoPSchema\\\\PagesWP\\\\": "layers/Schema/packages/pages-wp/tests", + "PoPSchema\\\\Pages\\\\": "layers/Schema/packages/pages/tests", + "PoPSchema\\\\PostMutations\\\\": "layers/Schema/packages/post-mutations/tests", + "PoPSchema\\\\PostTagsWP\\\\": "layers/Schema/packages/post-tags-wp/tests", + "PoPSchema\\\\PostTags\\\\": "layers/Schema/packages/post-tags/tests", + "PoPSchema\\\\PostsWP\\\\": "layers/Schema/packages/posts-wp/tests", + "PoPSchema\\\\Posts\\\\": "layers/Schema/packages/posts/tests", + "PoPSchema\\\\QueriedObjectWP\\\\": "layers/Schema/packages/queriedobject-wp/tests", + "PoPSchema\\\\QueriedObject\\\\": "layers/Schema/packages/queriedobject/tests", + "PoPSchema\\\\SchemaCommons\\\\": "layers/Schema/packages/schema-commons/tests", + "PoPSchema\\\\StancesWP\\\\": "layers/Schema/packages/stances-wp/tests", + "PoPSchema\\\\Stances\\\\": "layers/Schema/packages/stances/tests", + "PoPSchema\\\\TagsWP\\\\": "layers/Schema/packages/tags-wp/tests", + "PoPSchema\\\\Tags\\\\": "layers/Schema/packages/tags/tests", + "PoPSchema\\\\TaxonomiesWP\\\\": "layers/Schema/packages/taxonomies-wp/tests", + "PoPSchema\\\\Taxonomies\\\\": "layers/Schema/packages/taxonomies/tests", + "PoPSchema\\\\TaxonomyMetaWP\\\\": "layers/Schema/packages/taxonomymeta-wp/tests", + "PoPSchema\\\\TaxonomyMeta\\\\": "layers/Schema/packages/taxonomymeta/tests", + "PoPSchema\\\\TaxonomyQueryWP\\\\": "layers/Schema/packages/taxonomyquery-wp/tests", + "PoPSchema\\\\TaxonomyQuery\\\\": "layers/Schema/packages/taxonomyquery/tests", + "PoPSchema\\\\TranslateDirectiveACL\\\\": "layers/Schema/packages/translate-directive-acl/tests", + "PoPSchema\\\\TranslateDirective\\\\": "layers/Schema/packages/translate-directive/tests", + "PoPSchema\\\\UserMetaWP\\\\": "layers/Schema/packages/usermeta-wp/tests", + "PoPSchema\\\\UserMeta\\\\": "layers/Schema/packages/usermeta/tests", + "PoPSchema\\\\UserRolesACL\\\\": "layers/Schema/packages/user-roles-acl/tests", + "PoPSchema\\\\UserRolesAccessControl\\\\": "layers/Schema/packages/user-roles-access-control/tests", + "PoPSchema\\\\UserRolesWP\\\\": "layers/Schema/packages/user-roles-wp/tests", + "PoPSchema\\\\UserRoles\\\\": "layers/Schema/packages/user-roles/tests", + "PoPSchema\\\\UserStateAccessControl\\\\": "layers/Schema/packages/user-state-access-control/tests", + "PoPSchema\\\\UserStateMutationsWP\\\\": "layers/Schema/packages/user-state-mutations-wp/tests", + "PoPSchema\\\\UserStateMutations\\\\": "layers/Schema/packages/user-state-mutations/tests", + "PoPSchema\\\\UserStateWP\\\\": "layers/Schema/packages/user-state-wp/tests", + "PoPSchema\\\\UserState\\\\": "layers/Schema/packages/user-state/tests", + "PoPSchema\\\\UsersWP\\\\": "layers/Schema/packages/users-wp/tests", + "PoPSchema\\\\Users\\\\": "layers/Schema/packages/users/tests", + "PoPSitesWassup\\\\CommentMutations\\\\": "layers/Wassup/packages/comment-mutations/tests", + "PoPSitesWassup\\\\ContactUsMutations\\\\": "layers/Wassup/packages/contactus-mutations/tests", + "PoPSitesWassup\\\\ContactUserMutations\\\\": "layers/Wassup/packages/contactuser-mutations/tests", + "PoPSitesWassup\\\\CustomPostLinkMutations\\\\": "layers/Wassup/packages/custompostlink-mutations/tests", + "PoPSitesWassup\\\\CustomPostMutations\\\\": "layers/Wassup/packages/custompost-mutations/tests", + "PoPSitesWassup\\\\EventLinkMutations\\\\": "layers/Wassup/packages/eventlink-mutations/tests", + "PoPSitesWassup\\\\EventMutations\\\\": "layers/Wassup/packages/event-mutations/tests", + "PoPSitesWassup\\\\EverythingElseMutations\\\\": "layers/Wassup/packages/everythingelse-mutations/tests", + "PoPSitesWassup\\\\FlagMutations\\\\": "layers/Wassup/packages/flag-mutations/tests", + "PoPSitesWassup\\\\FormMutations\\\\": "layers/Wassup/packages/form-mutations/tests", + "PoPSitesWassup\\\\GravityFormsMutations\\\\": "layers/Wassup/packages/gravityforms-mutations/tests", + "PoPSitesWassup\\\\HighlightMutations\\\\": "layers/Wassup/packages/highlight-mutations/tests", + "PoPSitesWassup\\\\LocationMutations\\\\": "layers/Wassup/packages/location-mutations/tests", + "PoPSitesWassup\\\\LocationPostLinkMutations\\\\": "layers/Wassup/packages/locationpostlink-mutations/tests", + "PoPSitesWassup\\\\LocationPostMutations\\\\": "layers/Wassup/packages/locationpost-mutations/tests", + "PoPSitesWassup\\\\NewsletterMutations\\\\": "layers/Wassup/packages/newsletter-mutations/tests", + "PoPSitesWassup\\\\NotificationMutations\\\\": "layers/Wassup/packages/notification-mutations/tests", + "PoPSitesWassup\\\\PostLinkMutations\\\\": "layers/Wassup/packages/postlink-mutations/tests", + "PoPSitesWassup\\\\PostMutations\\\\": "layers/Wassup/packages/post-mutations/tests", + "PoPSitesWassup\\\\ShareMutations\\\\": "layers/Wassup/packages/share-mutations/tests", + "PoPSitesWassup\\\\SocialNetworkMutations\\\\": "layers/Wassup/packages/socialnetwork-mutations/tests", + "PoPSitesWassup\\\\StanceMutations\\\\": "layers/Wassup/packages/stance-mutations/tests", + "PoPSitesWassup\\\\SystemMutations\\\\": "layers/Wassup/packages/system-mutations/tests", + "PoPSitesWassup\\\\UserStateMutations\\\\": "layers/Wassup/packages/user-state-mutations/tests", + "PoPSitesWassup\\\\VolunteerMutations\\\\": "layers/Wassup/packages/volunteer-mutations/tests", + "PoPSitesWassup\\\\Wassup\\\\": "layers/Wassup/packages/wassup/tests", + "PoP\\\\APIClients\\\\": "layers/API/packages/api-clients/tests", + "PoP\\\\APIEndpointsForWP\\\\": "layers/API/packages/api-endpoints-for-wp/tests", + "PoP\\\\APIEndpoints\\\\": "layers/API/packages/api-endpoints/tests", + "PoP\\\\APIMirrorQuery\\\\": "layers/API/packages/api-mirrorquery/tests", + "PoP\\\\API\\\\": "layers/API/packages/api/tests", + "PoP\\\\AccessControl\\\\": "layers/Engine/packages/access-control/tests", + "PoP\\\\ApplicationWP\\\\": "layers/SiteBuilder/packages/application-wp/tests", + "PoP\\\\Application\\\\": "layers/SiteBuilder/packages/application/tests", + "PoP\\\\Base36Definitions\\\\": "layers/SiteBuilder/packages/definitions-base36/tests", + "PoP\\\\CacheControl\\\\": "layers/Engine/packages/cache-control/tests", + "PoP\\\\ComponentModel\\\\": "layers/Engine/packages/component-model/tests", + "PoP\\\\ConfigurableSchemaFeedback\\\\": "layers/Engine/packages/configurable-schema-feedback/tests", + "PoP\\\\ConfigurationComponentModel\\\\": "layers/SiteBuilder/packages/component-model-configuration/tests", + "PoP\\\\DefinitionPersistence\\\\": "layers/SiteBuilder/packages/definitionpersistence/tests", + "PoP\\\\Definitions\\\\": "layers/Engine/packages/definitions/tests", + "PoP\\\\EmojiDefinitions\\\\": "layers/SiteBuilder/packages/definitions-emoji/tests", + "PoP\\\\EngineWP\\\\": "layers/Engine/packages/engine-wp/tests", + "PoP\\\\Engine\\\\": "layers/Engine/packages/engine/tests", + "PoP\\\\FieldQuery\\\\": "layers/Engine/packages/field-query/tests", + "PoP\\\\FileStore\\\\": "layers/Engine/packages/filestore/tests", + "PoP\\\\FunctionFields\\\\": "layers/Engine/packages/function-fields/tests", + "PoP\\\\GraphQLAPI\\\\": "layers/API/packages/api-graphql/tests", + "PoP\\\\GuzzleHelpers\\\\": "layers/Engine/packages/guzzle-helpers/tests", + "PoP\\\\HooksWP\\\\": "layers/Engine/packages/hooks-wp/tests", + "PoP\\\\Hooks\\\\": "layers/Engine/packages/hooks/tests", + "PoP\\\\LooseContracts\\\\": "layers/Engine/packages/loosecontracts/tests", + "PoP\\\\MandatoryDirectivesByConfiguration\\\\": "layers/Engine/packages/mandatory-directives-by-configuration/tests", + "PoP\\\\ModuleRouting\\\\": "layers/Engine/packages/modulerouting/tests", + "PoP\\\\Multisite\\\\": "layers/SiteBuilder/packages/multisite/tests", + "PoP\\\\QueryParsing\\\\": "layers/Engine/packages/query-parsing/tests", + "PoP\\\\RESTAPI\\\\": "layers/API/packages/api-rest/tests", + "PoP\\\\ResourceLoader\\\\": "layers/SiteBuilder/packages/resourceloader/tests", + "PoP\\\\Resources\\\\": "layers/SiteBuilder/packages/resources/tests", + "PoP\\\\Root\\\\": "layers/Engine/packages/root/tests", + "PoP\\\\RoutingWP\\\\": "layers/Engine/packages/routing-wp/tests", + "PoP\\\\Routing\\\\": "layers/Engine/packages/routing/tests", + "PoP\\\\SPA\\\\": "layers/SiteBuilder/packages/spa/tests", + "PoP\\\\SSG\\\\": "layers/SiteBuilder/packages/static-site-generator/tests", + "PoP\\\\SiteWP\\\\": "layers/SiteBuilder/packages/site-wp/tests", + "PoP\\\\Site\\\\": "layers/SiteBuilder/packages/site/tests", + "PoP\\\\TraceTools\\\\": "layers/Engine/packages/trace-tools/tests", + "PoP\\\\TranslationWP\\\\": "layers/Engine/packages/translation-wp/tests", + "PoP\\\\Translation\\\\": "layers/Engine/packages/translation/tests" + } + }, + "extra": { + "wordpress-install-dir": "vendor/wordpress/wordpress", + "merge-plugin": { + "include": [ + "composer.local.json" + ], + "recurse": true, + "replace": false, + "ignore-duplicates": false, + "merge-dev": true, + "merge-extra": false, + "merge-extra-deep": false, + "merge-scripts": false + } + }, + "replace": { + "getpop/access-control": "self.version", + "getpop/api": "self.version", + "getpop/api-clients": "self.version", + "getpop/api-endpoints": "self.version", + "getpop/api-endpoints-for-wp": "self.version", + "getpop/api-graphql": "self.version", + "getpop/api-mirrorquery": "self.version", + "getpop/api-rest": "self.version", + "getpop/application": "self.version", + "getpop/application-wp": "self.version", + "getpop/cache-control": "self.version", + "getpop/component-model": "self.version", + "getpop/component-model-configuration": "self.version", + "getpop/configurable-schema-feedback": "self.version", + "getpop/definitionpersistence": "self.version", + "getpop/definitions": "self.version", + "getpop/definitions-base36": "self.version", + "getpop/definitions-emoji": "self.version", + "getpop/engine": "self.version", + "getpop/engine-wp": "self.version", + "getpop/engine-wp-bootloader": "self.version", + "getpop/field-query": "self.version", + "getpop/filestore": "self.version", + "getpop/function-fields": "self.version", + "getpop/guzzle-helpers": "self.version", + "getpop/hooks": "self.version", + "getpop/hooks-wp": "self.version", + "getpop/loosecontracts": "self.version", + "getpop/mandatory-directives-by-configuration": "self.version", + "getpop/migrate-api": "self.version", + "getpop/migrate-api-graphql": "self.version", + "getpop/migrate-component-model": "self.version", + "getpop/migrate-component-model-configuration": "self.version", + "getpop/migrate-engine": "self.version", + "getpop/migrate-engine-wp": "self.version", + "getpop/migrate-static-site-generator": "self.version", + "getpop/modulerouting": "self.version", + "getpop/multisite": "self.version", + "getpop/query-parsing": "self.version", + "getpop/resourceloader": "self.version", + "getpop/resources": "self.version", + "getpop/root": "self.version", + "getpop/routing": "self.version", + "getpop/routing-wp": "self.version", + "getpop/site": "self.version", + "getpop/site-wp": "self.version", + "getpop/spa": "self.version", + "getpop/static-site-generator": "self.version", + "getpop/trace-tools": "self.version", + "getpop/translation": "self.version", + "getpop/translation-wp": "self.version", + "graphql-api/convert-case-directives": "self.version", + "graphql-api/graphql-api-for-wp": "self.version", + "graphql-api/schema-feedback": "self.version", + "graphql-by-pop/graphql-clients-for-wp": "self.version", + "graphql-by-pop/graphql-endpoint-for-wp": "self.version", + "graphql-by-pop/graphql-parser": "self.version", + "graphql-by-pop/graphql-query": "self.version", + "graphql-by-pop/graphql-request": "self.version", + "graphql-by-pop/graphql-server": "self.version", + "leoloso/examples-for-pop": "self.version", + "pop-migrate-everythingelse/cssconverter": "self.version", + "pop-migrate-everythingelse/ssr": "self.version", + "pop-schema/basic-directives": "self.version", + "pop-schema/block-metadata-for-wp": "self.version", + "pop-schema/categories": "self.version", + "pop-schema/categories-wp": "self.version", + "pop-schema/cdn-directive": "self.version", + "pop-schema/comment-mutations": "self.version", + "pop-schema/comment-mutations-wp": "self.version", + "pop-schema/commentmeta": "self.version", + "pop-schema/commentmeta-wp": "self.version", + "pop-schema/comments": "self.version", + "pop-schema/comments-wp": "self.version", + "pop-schema/convert-case-directives": "self.version", + "pop-schema/custompost-mutations": "self.version", + "pop-schema/custompost-mutations-wp": "self.version", + "pop-schema/custompostmedia": "self.version", + "pop-schema/custompostmedia-mutations": "self.version", + "pop-schema/custompostmedia-mutations-wp": "self.version", + "pop-schema/custompostmedia-wp": "self.version", + "pop-schema/custompostmeta": "self.version", + "pop-schema/custompostmeta-wp": "self.version", + "pop-schema/customposts": "self.version", + "pop-schema/customposts-wp": "self.version", + "pop-schema/event-mutations": "self.version", + "pop-schema/event-mutations-wp-em": "self.version", + "pop-schema/events": "self.version", + "pop-schema/events-wp-em": "self.version", + "pop-schema/everythingelse": "self.version", + "pop-schema/everythingelse-wp": "self.version", + "pop-schema/generic-customposts": "self.version", + "pop-schema/google-translate-directive": "self.version", + "pop-schema/google-translate-directive-for-customposts": "self.version", + "pop-schema/highlights": "self.version", + "pop-schema/highlights-wp": "self.version", + "pop-schema/locationposts": "self.version", + "pop-schema/locationposts-wp": "self.version", + "pop-schema/locations": "self.version", + "pop-schema/locations-wp-em": "self.version", + "pop-schema/media": "self.version", + "pop-schema/media-wp": "self.version", + "pop-schema/menus": "self.version", + "pop-schema/menus-wp": "self.version", + "pop-schema/meta": "self.version", + "pop-schema/metaquery": "self.version", + "pop-schema/metaquery-wp": "self.version", + "pop-schema/migrate-categories": "self.version", + "pop-schema/migrate-categories-wp": "self.version", + "pop-schema/migrate-commentmeta": "self.version", + "pop-schema/migrate-commentmeta-wp": "self.version", + "pop-schema/migrate-comments": "self.version", + "pop-schema/migrate-comments-wp": "self.version", + "pop-schema/migrate-custompostmedia": "self.version", + "pop-schema/migrate-custompostmedia-wp": "self.version", + "pop-schema/migrate-custompostmeta": "self.version", + "pop-schema/migrate-custompostmeta-wp": "self.version", + "pop-schema/migrate-customposts": "self.version", + "pop-schema/migrate-customposts-wp": "self.version", + "pop-schema/migrate-events": "self.version", + "pop-schema/migrate-events-wp-em": "self.version", + "pop-schema/migrate-everythingelse": "self.version", + "pop-schema/migrate-locations": "self.version", + "pop-schema/migrate-locations-wp-em": "self.version", + "pop-schema/migrate-media": "self.version", + "pop-schema/migrate-media-wp": "self.version", + "pop-schema/migrate-meta": "self.version", + "pop-schema/migrate-metaquery": "self.version", + "pop-schema/migrate-metaquery-wp": "self.version", + "pop-schema/migrate-pages": "self.version", + "pop-schema/migrate-pages-wp": "self.version", + "pop-schema/migrate-post-tags": "self.version", + "pop-schema/migrate-post-tags-wp": "self.version", + "pop-schema/migrate-posts": "self.version", + "pop-schema/migrate-posts-wp": "self.version", + "pop-schema/migrate-queriedobject": "self.version", + "pop-schema/migrate-queriedobject-wp": "self.version", + "pop-schema/migrate-tags": "self.version", + "pop-schema/migrate-tags-wp": "self.version", + "pop-schema/migrate-taxonomies": "self.version", + "pop-schema/migrate-taxonomies-wp": "self.version", + "pop-schema/migrate-taxonomymeta": "self.version", + "pop-schema/migrate-taxonomymeta-wp": "self.version", + "pop-schema/migrate-taxonomyquery": "self.version", + "pop-schema/migrate-taxonomyquery-wp": "self.version", + "pop-schema/migrate-usermeta": "self.version", + "pop-schema/migrate-usermeta-wp": "self.version", + "pop-schema/migrate-users": "self.version", + "pop-schema/migrate-users-wp": "self.version", + "pop-schema/notifications": "self.version", + "pop-schema/notifications-wp": "self.version", + "pop-schema/pages": "self.version", + "pop-schema/pages-wp": "self.version", + "pop-schema/post-mutations": "self.version", + "pop-schema/post-tags": "self.version", + "pop-schema/post-tags-wp": "self.version", + "pop-schema/posts": "self.version", + "pop-schema/posts-wp": "self.version", + "pop-schema/queriedobject": "self.version", + "pop-schema/queriedobject-wp": "self.version", + "pop-schema/schema-commons": "self.version", + "pop-schema/stances": "self.version", + "pop-schema/stances-wp": "self.version", + "pop-schema/tags": "self.version", + "pop-schema/tags-wp": "self.version", + "pop-schema/taxonomies": "self.version", + "pop-schema/taxonomies-wp": "self.version", + "pop-schema/taxonomymeta": "self.version", + "pop-schema/taxonomymeta-wp": "self.version", + "pop-schema/taxonomyquery": "self.version", + "pop-schema/taxonomyquery-wp": "self.version", + "pop-schema/translate-directive": "self.version", + "pop-schema/translate-directive-acl": "self.version", + "pop-schema/user-roles": "self.version", + "pop-schema/user-roles-access-control": "self.version", + "pop-schema/user-roles-acl": "self.version", + "pop-schema/user-roles-wp": "self.version", + "pop-schema/user-state": "self.version", + "pop-schema/user-state-access-control": "self.version", + "pop-schema/user-state-mutations": "self.version", + "pop-schema/user-state-mutations-wp": "self.version", + "pop-schema/user-state-wp": "self.version", + "pop-schema/usermeta": "self.version", + "pop-schema/usermeta-wp": "self.version", + "pop-schema/users": "self.version", + "pop-schema/users-wp": "self.version", + "pop-sites-wassup/comment-mutations": "self.version", + "pop-sites-wassup/contactus-mutations": "self.version", + "pop-sites-wassup/contactuser-mutations": "self.version", + "pop-sites-wassup/custompost-mutations": "self.version", + "pop-sites-wassup/custompostlink-mutations": "self.version", + "pop-sites-wassup/event-mutations": "self.version", + "pop-sites-wassup/eventlink-mutations": "self.version", + "pop-sites-wassup/everythingelse-mutations": "self.version", + "pop-sites-wassup/flag-mutations": "self.version", + "pop-sites-wassup/form-mutations": "self.version", + "pop-sites-wassup/gravityforms-mutations": "self.version", + "pop-sites-wassup/highlight-mutations": "self.version", + "pop-sites-wassup/location-mutations": "self.version", + "pop-sites-wassup/locationpost-mutations": "self.version", + "pop-sites-wassup/locationpostlink-mutations": "self.version", + "pop-sites-wassup/newsletter-mutations": "self.version", + "pop-sites-wassup/notification-mutations": "self.version", + "pop-sites-wassup/post-mutations": "self.version", + "pop-sites-wassup/postlink-mutations": "self.version", + "pop-sites-wassup/share-mutations": "self.version", + "pop-sites-wassup/socialnetwork-mutations": "self.version", + "pop-sites-wassup/stance-mutations": "self.version", + "pop-sites-wassup/system-mutations": "self.version", + "pop-sites-wassup/user-state-mutations": "self.version", + "pop-sites-wassup/volunteer-mutations": "self.version", + "pop-sites-wassup/wassup": "self.version" + }, + "authors": [ + { + "name": "Leonardo Losoviz", + "email": "leo@getpop.org", + "homepage": "https://getpop.org" + } + ], + "description": "Monorepo for all the PoP packages", + "license": "GPL-2.0-or-later", + "config": { + "sort-packages": true, + "platform-check": false + }, + "repositories": [ + { + "type": "composer", + "url": "https://wpackagist.org" + }, + { + "type": "vcs", + "url": "https://github.com/leoloso/wp-muplugin-loader.git" + }, + { + "type": "vcs", + "url": "https://github.com/mcaskill/composer-merge-plugin.git" + } + ], + "scripts": { + "test": "phpunit", + "check-style": "phpcs -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)", + "fix-style": "phpcbf -n src $(monorepo-builder source-packages --subfolder=src --subfolder=tests)", + "analyse": "ci/phpstan.sh \\". $(monorepo-builder source-packages --skip-unmigrated)\\"", + "preview-src-downgrade": "rector process $(monorepo-builder source-packages --subfolder=src) --config=rector-downgrade-code.php --ansi --dry-run || true", + "preview-vendor-downgrade": "layers/Engine/packages/root/ci/downgrade_code.sh 7.1 rector-downgrade-code.php --dry-run || true", + "preview-code-downgrade": [ + "@preview-src-downgrade", + "@preview-vendor-downgrade" + ], + "build-server": [ + "lando init --source remote --remote-url https://wordpress.org/latest.tar.gz --recipe wordpress --webroot wordpress --name graphql-api-dev", + "@start-server" + ], + "start-server": [ + "cd layers/GraphQLAPIForWP/plugins/graphql-api-for-wp && composer install", + "lando start" + ], + "rebuild-server": "lando rebuild -y", + "merge-monorepo": "monorepo-builder merge --ansi", + "propagate-monorepo": "monorepo-builder propagate --ansi", + "validate-monorepo": "monorepo-builder validate --ansi", + "release": "monorepo-builder release patch --ansi" + }, + "minimum-stability": "dev", + "prefer-stable": true +} ', $manipulator->getContents()); } } diff --git a/tests/Composer/Test/Package/Archiver/ZipArchiverTest.php b/tests/Composer/Test/Package/Archiver/ZipArchiverTest.php index be1b5b6d1..ca179b21c 100644 --- a/tests/Composer/Test/Package/Archiver/ZipArchiverTest.php +++ b/tests/Composer/Test/Package/Archiver/ZipArchiverTest.php @@ -18,20 +18,44 @@ use Composer\Package\Archiver\ZipArchiver; class ZipArchiverTest extends ArchiverTest { - public function testZipArchive() + /** + * @param string $include + * + * @dataProvider provideGitignoreExcludeNegationTestCases + */ + public function testGitignoreExcludeNegation($include) + { + $this->testZipArchive(array( + 'docs/README.md' => '# The doc', + '.gitignore' => "/*\n.*\n!.git*\n$include", + )); + } + + public function provideGitignoreExcludeNegationTestCases() + { + return array( + array('!/docs'), + array('!/docs/'), + ); + } + + public function testZipArchive(array $files = array()) { if (!class_exists('ZipArchive')) { $this->markTestSkipped('Cannot run ZipArchiverTest, missing class "ZipArchive".'); } - $files = array( - 'file.txt', - 'foo/bar/baz', - 'x/baz', - 'x/includeme', - ); - if (!Platform::isWindows()) { - $files[] = 'foo' . getcwd() . '/file.txt'; + if (empty($files)) { + $files = array( + 'file.txt' => NULL, + 'foo/bar/baz' => NULL, + 'x/baz' => NULL, + 'x/includeme' => NULL, + ); + + if (!Platform::isWindows()) { + $files['foo' . getcwd() . '/file.txt'] = NULL; + } } // Set up repository $this->setupDummyRepo($files); @@ -41,12 +65,12 @@ class ZipArchiverTest extends ArchiverTest // Test archive $archiver = new ZipArchiver(); $archiver->archive($package->getSourceUrl(), $target, 'zip'); - $this->assertFileExists($target); + static::assertFileExists($target); $zip = new ZipArchive(); $res = $zip->open($target); - self::assertTrue($res, 'Failed asserting that Zip file can be opened'); - foreach ($files as $file) { - $this->assertSame('content', $zip->getFromName($file), 'Failed asserting that Zip contains ' . $file); + static::assertTrue($res, 'Failed asserting that Zip file can be opened'); + foreach ($files as $path => $content) { + static::assertSame($content, $zip->getFromName($path), 'Failed asserting that Zip contains ' . $path); } $zip->close(); @@ -57,12 +81,15 @@ class ZipArchiverTest extends ArchiverTest * Create a local dummy repository to run tests against! * @param array $files */ - protected function setupDummyRepo($files) + protected function setupDummyRepo(array &$files) { $currentWorkDir = getcwd(); chdir($this->testDir); - foreach ($files as $file) { - $this->writeFile($file, 'content', $currentWorkDir); + foreach ($files as $path => $content) { + if ($files[$path] === NULL) { + $files[$path] = 'content'; + } + $this->writeFile($path, $files[$path], $currentWorkDir); } chdir($currentWorkDir); diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php index ade220950..880b6f766 100644 --- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php @@ -202,28 +202,4 @@ class RootPackageLoaderTest extends TestCase $this->assertEquals("dev-latest-production", $package->getPrettyVersion()); } - - /** - * @dataProvider provideExtraBranchVersion - */ - public function testLoadExtraBranchVersion($branchVersion) - { - $package = $this->loadPackage(array( - 'extra' => array( - 'branch-version' => $branchVersion, - ), - )); - - $this->assertEquals('1.2.x-dev', $package->getPrettyVersion()); - } - - public function provideExtraBranchVersion() - { - return array( - array('1.2'), - array('1.2.x'), - array('1.2-dev'), - array('1.2.x-dev'), - ); - } } diff --git a/tests/Composer/Test/Plugin/PluginInstallerTest.php b/tests/Composer/Test/Plugin/PluginInstallerTest.php index fd6f182bb..c5c587b3e 100644 --- a/tests/Composer/Test/Plugin/PluginInstallerTest.php +++ b/tests/Composer/Test/Plugin/PluginInstallerTest.php @@ -18,6 +18,7 @@ use Composer\Installer\PluginInstaller; use Composer\Package\CompletePackage; use Composer\Package\Loader\JsonLoader; use Composer\Package\Loader\ArrayLoader; +use Composer\Package\RootPackage; use Composer\Plugin\PluginManager; use Composer\IO\BufferIO; use Composer\EventDispatcher\EventDispatcher; @@ -111,6 +112,7 @@ class PluginInstallerTest extends TestCase $this->composer->setInstallationManager($im); $this->composer->setAutoloadGenerator($this->autoloadGenerator); $this->composer->setEventDispatcher(new EventDispatcher($this->composer, $this->io)); + $this->composer->setPackage(new RootPackage('dummy/root', '1.0.0.0', '1.0.0')); $this->pm = new PluginManager($this->io, $this->composer); $this->composer->setPluginManager($this->pm); diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index b000088a2..d7e2ab1f7 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -55,7 +55,7 @@ class ComposerRepositoryTest extends TestCase $repository ->expects($this->at(2)) ->method('createPackages') - ->with($this->identicalTo($expected), $this->equalTo('Composer\Package\CompletePackage')) + ->with($this->identicalTo($expected), $this->equalTo('root file (http://example.org/packages.json)')) ->will($this->returnValue($stubs)); // Triggers initialization diff --git a/tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json b/tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json deleted file mode 100644 index 75545d5f9..000000000 --- a/tests/Composer/Test/Repository/Fixtures/path/with-branch-version/composer.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "test/path-branch-versioned", - "extra": { - "branch-version": "1.2" - } -} diff --git a/tests/Composer/Test/Repository/PathRepositoryTest.php b/tests/Composer/Test/Repository/PathRepositoryTest.php index 1d654c02f..326434d26 100644 --- a/tests/Composer/Test/Repository/PathRepositoryTest.php +++ b/tests/Composer/Test/Repository/PathRepositoryTest.php @@ -67,23 +67,6 @@ class PathRepositoryTest extends TestCase $this->assertNotEmpty($packageVersion); } - public function testLoadPackageFromFileSystemWithExtraBranchVersion() - { - $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') - ->getMock(); - - $config = new \Composer\Config(); - $versionGuesser = null; - - $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'with-branch-version')); - $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config); - $packages = $repository->getPackages(); - - $this->assertEquals(1, $repository->count()); - - $this->assertTrue($repository->hasPackage($this->getPackage('test/path-branch-versioned', '1.2.x-dev'))); - } - public function testLoadPackageFromFileSystemWithWildcard() { $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') @@ -95,16 +78,50 @@ class PathRepositoryTest extends TestCase $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*')); $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config); $packages = $repository->getPackages(); - $result = array(); + $names = array(); - $this->assertGreaterThanOrEqual(3, $repository->count()); + $this->assertEquals(2, $repository->count()); - foreach ($packages as $package) { - $result[$package->getName()] = $package->getPrettyVersion(); - } + $package = $packages[0]; + $names[] = $package->getName(); - ksort($result); - $this->assertSame(array('test/path-branch-versioned' => '1.2.x-dev', 'test/path-unversioned' => $result['test/path-unversioned'], 'test/path-versioned' => '0.0.2'), $result); + $package = $packages[1]; + $names[] = $package->getName(); + + sort($names); + $this->assertEquals(array('test/path-unversioned', 'test/path-versioned'), $names); + } + + public function testLoadPackageWithExplicitVersions() + { + $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') + ->getMock(); + + $config = new \Composer\Config(); + $versionGuesser = null; + + $options = array( + 'versions' => array( + 'test/path-unversioned' => '4.3.2.1', + 'test/path-versioned' => '3.2.1.0', + ), + ); + $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*')); + $repository = new PathRepository(array('url' => $repositoryUrl, 'options' => $options), $ioInterface, $config); + $packages = $repository->getPackages(); + + $versions = array(); + + $this->assertEquals(2, $repository->count()); + + $package = $packages[0]; + $versions[$package->getName()] = $package->getVersion(); + + $package = $packages[1]; + $versions[$package->getName()] = $package->getVersion(); + + ksort($versions); + $this->assertSame(array('test/path-unversioned' => '4.3.2.1', 'test/path-versioned' => '3.2.1.0'), $versions); } /**