Merge remote-tracking branch 'upstream/main' into git-merge-composer.lock-detection
commit
da2ecc6228
|
@ -24,3 +24,6 @@
|
|||
/PORTING_INFO export-ignore
|
||||
/README.md export-ignore
|
||||
/UPGRADE-2.0.md export-ignore
|
||||
|
||||
# Ref https://github.com/composer/composer/issues/11507
|
||||
/phpstan/rules.neon -export-ignore
|
||||
|
|
|
@ -9,4 +9,5 @@ phpunit.xml
|
|||
.vagrant
|
||||
Vagrantfile
|
||||
.idea
|
||||
.vscode
|
||||
.php-cs-fixer.cache
|
||||
|
|
18
README.md
18
README.md
|
@ -50,6 +50,24 @@ PHP versions 5.3.2 - 8.1 are still supported via the LTS releases of Composer (2
|
|||
run the installer or the `self-update` command the appropriate Composer version for your PHP
|
||||
should be automatically selected.
|
||||
|
||||
#### Binary dependencies
|
||||
|
||||
- `7z` (or `7zz`)
|
||||
- `unzip` (if `7z` is missing)
|
||||
- `gzip`
|
||||
- `tar`
|
||||
- `unrar`
|
||||
- `xz`
|
||||
- Git (`git`)
|
||||
- Mercurial (`hg`)
|
||||
- Fossil (`fossil`)
|
||||
- Perforce (`p4`)
|
||||
- Subversion (`svn`)
|
||||
|
||||
It's important to note that the need for these binary dependencies may vary
|
||||
depending on individual use cases. However, for most users, only 2 dependencies
|
||||
are essential for Composer: `7z` (or `7zz` or `unzip`), and `git`.
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"composer/ca-bundle": "^1.0",
|
||||
"composer/class-map-generator": "^1.0",
|
||||
"composer/metadata-minifier": "^1.0",
|
||||
"composer/semver": "^3.0",
|
||||
"composer/semver": "^3.2.5",
|
||||
"composer/spdx-licenses": "^1.5.7",
|
||||
"composer/xdebug-handler": "^2.0.2 || ^3.0.3",
|
||||
"justinrainbow/json-schema": "^5.2.11",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "cc535e8c9fc8f1414a1cede463898453",
|
||||
"content-hash": "c50c89580fa044b7523cb55c2d557c87",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
|
@ -84,22 +84,22 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/class-map-generator",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/class-map-generator.git",
|
||||
"reference": "1e1cb2b791facb2dfe32932a7718cf2571187513"
|
||||
"reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/1e1cb2b791facb2dfe32932a7718cf2571187513",
|
||||
"reference": "1e1cb2b791facb2dfe32932a7718cf2571187513",
|
||||
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/953cc4ea32e0c31f2185549c7d216d7921f03da9",
|
||||
"reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/pcre": "^2 || ^3",
|
||||
"composer/pcre": "^2.1 || ^3.1",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"symfony/finder": "^4.4 || ^5.3 || ^6"
|
||||
"symfony/finder": "^4.4 || ^5.3 || ^6 || ^7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.6",
|
||||
|
@ -137,7 +137,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/class-map-generator/issues",
|
||||
"source": "https://github.com/composer/class-map-generator/tree/1.0.0"
|
||||
"source": "https://github.com/composer/class-map-generator/tree/1.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -153,7 +153,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-06-19T11:31:27+00:00"
|
||||
"time": "2023-06-30T13:58:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/metadata-minifier",
|
||||
|
@ -1103,16 +1103,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v5.4.23",
|
||||
"version": "v5.4.25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5"
|
||||
"reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5",
|
||||
"reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364",
|
||||
"reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1147,7 +1147,7 @@
|
|||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.4.23"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.4.25"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1163,7 +1163,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-02T11:38:35+00:00"
|
||||
"time": "2023-05-31T13:04:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
|
@ -2034,16 +2034,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.16",
|
||||
"version": "1.10.25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "352bdbb960bb523e3d71b834862589f910921c23"
|
||||
"reference": "578f4e70d117f9a90699324c555922800ac38d8c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/352bdbb960bb523e3d71b834862589f910921c23",
|
||||
"reference": "352bdbb960bb523e3d71b834862589f910921c23",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/578f4e70d117f9a90699324c555922800ac38d8c",
|
||||
"reference": "578f4e70d117f9a90699324c555922800ac38d8c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2092,7 +2092,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-06-05T08:21:46+00:00"
|
||||
"time": "2023-07-06T12:11:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-deprecation-rules",
|
||||
|
@ -2316,16 +2316,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/phpunit-bridge",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/phpunit-bridge.git",
|
||||
"reference": "f8d75b4d9bf7243979b2c2e5e6cd73f03e10579f"
|
||||
"reference": "0b0bf59b0d9bd1422145a123a67fb12af546ef0d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/f8d75b4d9bf7243979b2c2e5e6cd73f03e10579f",
|
||||
"reference": "f8d75b4d9bf7243979b2c2e5e6cd73f03e10579f",
|
||||
"url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/0b0bf59b0d9bd1422145a123a67fb12af546ef0d",
|
||||
"reference": "0b0bf59b0d9bd1422145a123a67fb12af546ef0d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2377,7 +2377,7 @@
|
|||
"description": "Provides utilities for PHPUnit, especially user deprecation notices management",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/phpunit-bridge/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/phpunit-bridge/tree/v6.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2393,7 +2393,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-30T09:01:24+00:00"
|
||||
"time": "2023-06-23T13:25:16+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -39,8 +39,14 @@ a legacy PHP version. A few sensitive php settings and compile flags are also
|
|||
required, but when using the installer you will be warned about any
|
||||
incompatibilities.
|
||||
|
||||
To install packages from sources instead of plain zip archives, you will need
|
||||
git, svn, fossil or hg depending on how the package is version-controlled.
|
||||
Composer needs several supporting applications to work effectively, making the
|
||||
process of handling package dependencies more efficient. For decompressing
|
||||
files, Composer relies on tools like `7z` (or `7zz`), `gzip`, `tar`, `unrar`,
|
||||
`unzip` and `xz`. As for version control systems, Composer integrates seamlessly
|
||||
with Fossil, Git, Mercurial, Perforce and Subversion, thereby ensuring the
|
||||
application's smooth operation and management of library repositories. Before
|
||||
using Composer, ensure that these dependencies are correctly installed on your
|
||||
system.
|
||||
|
||||
Composer is multi-platform and we strive to make it run equally well on Windows,
|
||||
Linux and macOS.
|
||||
|
|
|
@ -35,7 +35,7 @@ separated by `/`. Examples:
|
|||
* igorw/event-source
|
||||
|
||||
The name must be lowercase and consist of words separated by `-`, `.` or `_`.
|
||||
The complete name should match `^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{0,2})[a-z0-9]+)*$`.
|
||||
The complete name should match `^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$`.
|
||||
|
||||
The `name` property is required for published packages (libraries).
|
||||
|
||||
|
|
|
@ -284,6 +284,10 @@ Now the `custom-plugin-command` is available alongside Composer commands.
|
|||
Plugins for an event can be run manually by the `run-script` command. This works the same way as
|
||||
[running scripts manually](scripts.md#running-scripts-manually).
|
||||
|
||||
If it is another type of plugin the best way to test it is probably using a [path repository](../05-repositories.md#path)
|
||||
to require the plugin in a test project, and then `rm -rf vendor && composer update`
|
||||
every time you want to install/run it again.
|
||||
|
||||
## Using Plugins
|
||||
|
||||
Plugin packages are automatically loaded as soon as they are installed and will
|
||||
|
|
|
@ -85,11 +85,6 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Downloader/GzipDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function rawurldecode expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#"
|
||||
count: 1
|
||||
|
|
|
@ -645,26 +645,11 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getId\\(\\) on Composer\\\\Package\\\\BasePackage\\|int\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getInstallationManager\\(\\) on Composer\\\\Composer\\|null\\.$#"
|
||||
count: 2
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getPrettyVersion\\(\\) on Composer\\\\Package\\\\BasePackage\\|int\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getVersion\\(\\) on Composer\\\\Package\\\\BasePackage\\|int\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Foreach overwrites \\$packages with its value variable\\.$#"
|
||||
count: 1
|
||||
|
@ -675,11 +660,6 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Method Composer\\\\Command\\\\ShowCommand\\:\\:getPackage\\(\\) should return array\\{Composer\\\\Package\\\\CompletePackageInterface\\|null, array\\<string, string\\>\\} but returns array\\{Composer\\\\Package\\\\BasePackage\\|int\\|null, array\\<string, string\\>\\}\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in &&, Composer\\\\Composer\\|null given on the right side\\.$#"
|
||||
count: 1
|
||||
|
@ -720,11 +700,6 @@ parameters:
|
|||
count: 2
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in a negated boolean, Composer\\\\Package\\\\BasePackage\\|int\\|null given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in a negated boolean, Composer\\\\Repository\\\\RepositorySet\\|null given\\.$#"
|
||||
count: 1
|
||||
|
@ -805,11 +780,6 @@ parameters:
|
|||
count: 2
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$package of method Composer\\\\Repository\\\\CompositeRepository\\:\\:hasPackage\\(\\) expects Composer\\\\Package\\\\PackageInterface, Composer\\\\Package\\\\BasePackage\\|int given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/ShowCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$str of function strtok expects string, array\\|string given\\.$#"
|
||||
count: 1
|
||||
|
@ -1930,36 +1900,11 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#"
|
||||
count: 2
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$package of method Composer\\\\Downloader\\\\VcsDownloader\\:\\:cleanChanges\\(\\) expects Composer\\\\Package\\\\PackageInterface, Composer\\\\Package\\\\PackageInterface\\|null given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$path of function realpath expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$path of static method Composer\\\\Util\\\\Filesystem\\:\\:isLocalPath\\(\\) expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$str of function rawurldecode expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Downloader/VcsDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$toReference of method Composer\\\\Downloader\\\\VcsDownloader\\:\\:getCommitLogs\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
|
@ -2500,11 +2445,6 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Installer/SuggestedPackagesReporter.php
|
||||
|
||||
-
|
||||
message: "#^Method Composer\\\\Json\\\\JsonFile\\:\\:encode\\(\\) should return string but returns string\\|false\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Json/JsonFile.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in &&, Composer\\\\IO\\\\IOInterface\\|null given on the left side\\.$#"
|
||||
count: 1
|
||||
|
|
|
@ -1,247 +0,0 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
use Composer\Pcre\Preg;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @internal
|
||||
*/
|
||||
class PhpFileCleaner
|
||||
{
|
||||
/** @var array<array{name: string, length: int, pattern: non-empty-string}> */
|
||||
private static $typeConfig;
|
||||
|
||||
/** @var non-empty-string */
|
||||
private static $restPattern;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @var string
|
||||
*/
|
||||
private $contents;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @var int
|
||||
*/
|
||||
private $len;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @var int
|
||||
*/
|
||||
private $maxMatches;
|
||||
|
||||
/** @var int */
|
||||
private $index = 0;
|
||||
|
||||
/**
|
||||
* @param string[] $types
|
||||
*/
|
||||
public static function setTypeConfig(array $types): void
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
self::$typeConfig[$type[0]] = [
|
||||
'name' => $type,
|
||||
'length' => \strlen($type),
|
||||
'pattern' => '{.\b(?<![\$:>])'.$type.'\s++[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+}Ais',
|
||||
];
|
||||
}
|
||||
|
||||
self::$restPattern = '{[^?"\'</'.implode('', array_keys(self::$typeConfig)).']+}A';
|
||||
}
|
||||
|
||||
public function __construct(string $contents, int $maxMatches)
|
||||
{
|
||||
$this->contents = $contents;
|
||||
$this->len = \strlen($this->contents);
|
||||
$this->maxMatches = $maxMatches;
|
||||
}
|
||||
|
||||
public function clean(): string
|
||||
{
|
||||
$clean = '';
|
||||
|
||||
while ($this->index < $this->len) {
|
||||
$this->skipToPhp();
|
||||
$clean .= '<?';
|
||||
|
||||
while ($this->index < $this->len) {
|
||||
$char = $this->contents[$this->index];
|
||||
if ($char === '?' && $this->peek('>')) {
|
||||
$clean .= '?>';
|
||||
$this->index += 2;
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if ($char === '"') {
|
||||
$this->skipString('"');
|
||||
$clean .= 'null';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($char === "'") {
|
||||
$this->skipString("'");
|
||||
$clean .= 'null';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($char === "<" && $this->peek('<') && $this->match('{<<<[ \t]*+([\'"]?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*+)\\1(?:\r\n|\n|\r)}A', $match)) {
|
||||
$this->index += \strlen($match[0]);
|
||||
$this->skipHeredoc($match[2]);
|
||||
$clean .= 'null';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($char === '/') {
|
||||
if ($this->peek('/')) {
|
||||
$this->skipToNewline();
|
||||
continue;
|
||||
}
|
||||
if ($this->peek('*')) {
|
||||
$this->skipComment();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->maxMatches === 1 && isset(self::$typeConfig[$char])) {
|
||||
$type = self::$typeConfig[$char];
|
||||
if (
|
||||
\substr($this->contents, $this->index, $type['length']) === $type['name']
|
||||
&& Preg::isMatch($type['pattern'], $this->contents, $match, 0, $this->index - 1)
|
||||
) {
|
||||
$clean .= $match[0];
|
||||
|
||||
return $clean;
|
||||
}
|
||||
}
|
||||
|
||||
$this->index += 1;
|
||||
if ($this->match(self::$restPattern, $match)) {
|
||||
$clean .= $char . $match[0];
|
||||
$this->index += \strlen($match[0]);
|
||||
} else {
|
||||
$clean .= $char;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $clean;
|
||||
}
|
||||
|
||||
private function skipToPhp(): void
|
||||
{
|
||||
while ($this->index < $this->len) {
|
||||
if ($this->contents[$this->index] === '<' && $this->peek('?')) {
|
||||
$this->index += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private function skipString(string $delimiter): void
|
||||
{
|
||||
$this->index += 1;
|
||||
while ($this->index < $this->len) {
|
||||
if ($this->contents[$this->index] === '\\' && ($this->peek('\\') || $this->peek($delimiter))) {
|
||||
$this->index += 2;
|
||||
continue;
|
||||
}
|
||||
if ($this->contents[$this->index] === $delimiter) {
|
||||
$this->index += 1;
|
||||
break;
|
||||
}
|
||||
$this->index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private function skipComment(): void
|
||||
{
|
||||
$this->index += 2;
|
||||
while ($this->index < $this->len) {
|
||||
if ($this->contents[$this->index] === '*' && $this->peek('/')) {
|
||||
$this->index += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private function skipToNewline(): void
|
||||
{
|
||||
while ($this->index < $this->len) {
|
||||
if ($this->contents[$this->index] === "\r" || $this->contents[$this->index] === "\n") {
|
||||
return;
|
||||
}
|
||||
$this->index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private function skipHeredoc(string $delimiter): void
|
||||
{
|
||||
$firstDelimiterChar = $delimiter[0];
|
||||
$delimiterLength = \strlen($delimiter);
|
||||
$delimiterPattern = '{'.preg_quote($delimiter).'(?![a-zA-Z0-9_\x80-\xff])}A';
|
||||
|
||||
while ($this->index < $this->len) {
|
||||
// check if we find the delimiter after some spaces/tabs
|
||||
switch ($this->contents[$this->index]) {
|
||||
case "\t":
|
||||
case " ":
|
||||
$this->index += 1;
|
||||
continue 2;
|
||||
case $firstDelimiterChar:
|
||||
if (
|
||||
\substr($this->contents, $this->index, $delimiterLength) === $delimiter
|
||||
&& $this->match($delimiterPattern)
|
||||
) {
|
||||
$this->index += $delimiterLength;
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// skip the rest of the line
|
||||
while ($this->index < $this->len) {
|
||||
$this->skipToNewline();
|
||||
|
||||
// skip newlines
|
||||
while ($this->index < $this->len && ($this->contents[$this->index] === "\r" || $this->contents[$this->index] === "\n")) {
|
||||
$this->index += 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function peek(string $char): bool
|
||||
{
|
||||
return $this->index + 1 < $this->len && $this->contents[$this->index + 1] === $char;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $regex
|
||||
* @param null|array<int, string> $match
|
||||
*/
|
||||
private function match($regex, ?array &$match = null): bool
|
||||
{
|
||||
return Preg::isMatch($regex, $this->contents, $match, 0, $this->index);
|
||||
}
|
||||
}
|
|
@ -24,10 +24,12 @@ use Composer\Repository\PlatformRepository;
|
|||
use Composer\Repository\RepositoryFactory;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Composer\Util\PackageInfo;
|
||||
|
||||
/**
|
||||
* Base implementation for commands mapping dependency relationships.
|
||||
|
@ -180,7 +182,9 @@ abstract class BaseDependencyCommand extends BaseCommand
|
|||
}
|
||||
$doubles[$unique] = true;
|
||||
$version = $package->getPrettyVersion() === RootPackage::DEFAULT_PRETTY_VERSION ? '-' : $package->getPrettyVersion();
|
||||
$rows[] = [$package->getPrettyName(), $version, $link->getDescription(), sprintf('%s (%s)', $link->getTarget(), $link->getPrettyConstraint())];
|
||||
$packageUrl = PackageInfo::getViewSourceOrHomepageUrl($package);
|
||||
$nameWithLink = $packageUrl !== null ? '<href=' . OutputFormatter::escape($packageUrl) . '>' . $package->getPrettyName() . '</>' : $package->getPrettyName();
|
||||
$rows[] = [$nameWithLink, $version, $link->getDescription(), sprintf('%s (%s)', $link->getTarget(), $link->getPrettyConstraint())];
|
||||
if ($children) {
|
||||
$queue = array_merge($queue, $children);
|
||||
}
|
||||
|
@ -229,7 +233,9 @@ abstract class BaseDependencyCommand extends BaseCommand
|
|||
$prevColor = $this->colors[($level - 1) % count($this->colors)];
|
||||
$isLast = (++$idx === $count);
|
||||
$versionText = $package->getPrettyVersion() === RootPackage::DEFAULT_PRETTY_VERSION ? '' : $package->getPrettyVersion();
|
||||
$packageText = rtrim(sprintf('<%s>%s</%1$s> %s', $color, $package->getPrettyName(), $versionText));
|
||||
$packageUrl = PackageInfo::getViewSourceOrHomepageUrl($package);
|
||||
$nameWithLink = $packageUrl !== null ? '<href=' . OutputFormatter::escape($packageUrl) . '>' . $package->getPrettyName() . '</>' : $package->getPrettyName();
|
||||
$packageText = rtrim(sprintf('<%s>%s</%1$s> %s', $color, $nameWithLink, $versionText));
|
||||
$linkText = sprintf('%s <%s>%s</%2$s> %s', $link->getDescription(), $prevColor, $link->getTarget(), $link->getPrettyConstraint());
|
||||
$circularWarn = $children === false ? '(circular dependency aborted here)' : '';
|
||||
$this->writeTreeLine(rtrim(sprintf("%s%s%s (%s) %s", $prefix, $isLast ? '└──' : '├──', $packageText, $linkText, $circularWarn)));
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Composer\Command;
|
|||
use Composer\Factory;
|
||||
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\CompletePackageInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
|
@ -100,7 +101,7 @@ trait PackageDiscoveryTrait
|
|||
|
||||
if (!isset($requirement['version'])) {
|
||||
// determine the best version automatically
|
||||
[$name, $version] = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, $fixed);
|
||||
[$name, $version] = $this->findBestVersionAndNameForPackage($this->getIO(), $input, $requirement['name'], $platformRepo, $preferredStability, $fixed);
|
||||
|
||||
// replace package name from packagist.org
|
||||
$requirement['name'] = $name;
|
||||
|
@ -243,7 +244,7 @@ trait PackageDiscoveryTrait
|
|||
);
|
||||
|
||||
if (false === $constraint) {
|
||||
[, $constraint] = $this->findBestVersionAndNameForPackage($input, $package, $platformRepo, $preferredStability);
|
||||
[, $constraint] = $this->findBestVersionAndNameForPackage($this->getIO(), $input, $package, $platformRepo, $preferredStability);
|
||||
|
||||
$io->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
|
@ -273,7 +274,7 @@ trait PackageDiscoveryTrait
|
|||
* @throws \InvalidArgumentException
|
||||
* @return array{string, string} name version
|
||||
*/
|
||||
private function findBestVersionAndNameForPackage(InputInterface $input, string $name, ?PlatformRepository $platformRepo = null, string $preferredStability = 'stable', bool $fixed = false): array
|
||||
private function findBestVersionAndNameForPackage(IOInterface $io, InputInterface $input, string $name, ?PlatformRepository $platformRepo = null, string $preferredStability = 'stable', bool $fixed = false): array
|
||||
{
|
||||
// handle ignore-platform-reqs flag if present
|
||||
if ($input->hasOption('ignore-platform-reqs') && $input->hasOption('ignore-platform-req')) {
|
||||
|
@ -358,6 +359,13 @@ trait PackageDiscoveryTrait
|
|||
));
|
||||
}
|
||||
|
||||
if ($input->isInteractive()) {
|
||||
$result = $io->select("<error>Could not find package $name.</error>\nPick one of these or leave empty to abort:", $similar, false, 1);
|
||||
if ($result !== false) {
|
||||
return $this->findBestVersionAndNameForPackage($io, $input, $similar[$result], $platformRepo, $preferredStability, $fixed);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Could not find package %s.\n\nDid you mean " . (count($similar) > 1 ? 'one of these' : 'this') . "?\n %s",
|
||||
$name,
|
||||
|
|
|
@ -756,10 +756,14 @@ EOT
|
|||
}
|
||||
|
||||
// select preferred package according to policy rules
|
||||
if (!$matchedPackage && $matches && $preferred = $policy->selectPreferredPackages($pool, $matches)) {
|
||||
if (null === $matchedPackage && $matches && $preferred = $policy->selectPreferredPackages($pool, $matches)) {
|
||||
$matchedPackage = $pool->literalToPackage($preferred[0]);
|
||||
}
|
||||
|
||||
if ($matchedPackage !== null && !$matchedPackage instanceof CompletePackageInterface) {
|
||||
throw new \LogicException('ShowCommand::getPackage can only work with CompletePackageInterface, but got '.get_class($matchedPackage));
|
||||
}
|
||||
|
||||
return [$matchedPackage, $versions];
|
||||
}
|
||||
|
||||
|
@ -1251,6 +1255,9 @@ EOT
|
|||
$colorIdent = $level % count($this->colors);
|
||||
$color = $this->colors[$colorIdent];
|
||||
|
||||
assert(is_string($require['name']));
|
||||
assert(is_string($require['version']));
|
||||
|
||||
$circularWarn = in_array(
|
||||
$require['name'],
|
||||
$currentTree,
|
||||
|
|
|
@ -557,6 +557,19 @@ class Problem
|
|||
*/
|
||||
protected static function constraintToText(?ConstraintInterface $constraint = null): string
|
||||
{
|
||||
if ($constraint instanceof Constraint && $constraint->getOperator() === Constraint::STR_OP_EQ && !str_starts_with($constraint->getVersion(), 'dev-')) {
|
||||
if (!Preg::isMatch('{^\d+(?:\.\d+)*$}', $constraint->getPrettyString())) {
|
||||
return ' '.$constraint->getPrettyString() .' (exact version match)';
|
||||
}
|
||||
|
||||
$versions = [$constraint->getPrettyString()];
|
||||
for ($i = 3 - substr_count($versions[0], '.'); $i > 0; $i--) {
|
||||
$versions[] = end($versions) . '.0';
|
||||
}
|
||||
|
||||
return ' ' . $constraint->getPrettyString() . ' (exact version match: ' . (count($versions) > 1 ? implode(', ', array_slice($versions, 0, -1)) . ' or ' . end($versions) : $versions[0]) . ')';
|
||||
}
|
||||
|
||||
return $constraint ? ' '.$constraint->getPrettyString() : '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -436,7 +436,12 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
|
|||
*/
|
||||
protected function getFileName(PackageInterface $package, string $path): string
|
||||
{
|
||||
return rtrim($this->config->get('vendor-dir') . '/composer/tmp-' . md5($package . spl_object_hash($package)) . '.' . $this->getDistPath($package, PATHINFO_EXTENSION), '.');
|
||||
$extension = $this->getDistPath($package, PATHINFO_EXTENSION);
|
||||
if ($extension === '') {
|
||||
$extension = $package->getDistType();
|
||||
}
|
||||
|
||||
return rtrim($this->config->get('vendor-dir') . '/composer/tmp-' . md5($package . spl_object_hash($package)) . '.' . $extension, '.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,12 +42,16 @@ class JsonFile
|
|||
|
||||
public const COMPOSER_SCHEMA_PATH = __DIR__ . '/../../../res/composer-schema.json';
|
||||
|
||||
public const INDENT_DEFAULT = ' ';
|
||||
|
||||
/** @var string */
|
||||
private $path;
|
||||
/** @var ?HttpDownloader */
|
||||
private $httpDownloader;
|
||||
/** @var ?IOInterface */
|
||||
private $io;
|
||||
/** @var string */
|
||||
private $indent = self::INDENT_DEFAULT;
|
||||
|
||||
/**
|
||||
* Initializes json file reader/parser.
|
||||
|
@ -117,6 +121,8 @@ class JsonFile
|
|||
throw new \RuntimeException('Could not read '.$this->path);
|
||||
}
|
||||
|
||||
$this->indent = self::detectIndenting($json);
|
||||
|
||||
return static::parseJson($json, $this->path);
|
||||
}
|
||||
|
||||
|
@ -131,7 +137,7 @@ class JsonFile
|
|||
public function write(array $hash, int $options = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
{
|
||||
if ($this->path === 'php://memory') {
|
||||
file_put_contents($this->path, static::encode($hash, $options));
|
||||
file_put_contents($this->path, static::encode($hash, $options, $this->indent));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -153,7 +159,7 @@ class JsonFile
|
|||
$retries = 3;
|
||||
while ($retries--) {
|
||||
try {
|
||||
$this->filePutContentsIfModified($this->path, static::encode($hash, $options). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
|
||||
$this->filePutContentsIfModified($this->path, static::encode($hash, $options, $this->indent). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
|
||||
break;
|
||||
} catch (\Exception $e) {
|
||||
if ($retries > 0) {
|
||||
|
@ -262,15 +268,28 @@ class JsonFile
|
|||
*
|
||||
* @param mixed $data Data to encode into a formatted JSON string
|
||||
* @param int $options json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
* @param string $indent Indentation string
|
||||
* @return string Encoded json
|
||||
*/
|
||||
public static function encode($data, int $options = 448)
|
||||
public static function encode($data, int $options = 448, string $indent = self::INDENT_DEFAULT): string
|
||||
{
|
||||
$json = json_encode($data, $options);
|
||||
|
||||
if (false === $json) {
|
||||
self::throwEncodeError(json_last_error());
|
||||
}
|
||||
|
||||
if (($options & JSON_PRETTY_PRINT) > 0 && $indent !== self::INDENT_DEFAULT ) {
|
||||
// Pretty printing and not using default indentation
|
||||
return Preg::replaceCallback(
|
||||
'#^ {4,}#m',
|
||||
static function ($match) use ($indent): string {
|
||||
return str_repeat($indent, (int)(strlen($match[0] ?? '') / 4));
|
||||
},
|
||||
$json
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
@ -279,6 +298,7 @@ class JsonFile
|
|||
*
|
||||
* @param int $code return code of json_last_error function
|
||||
* @throws \RuntimeException
|
||||
* @return never
|
||||
*/
|
||||
private static function throwEncodeError(int $code): void
|
||||
{
|
||||
|
@ -364,4 +384,12 @@ class JsonFile
|
|||
$result->getDetails());
|
||||
}
|
||||
}
|
||||
|
||||
public static function detectIndenting(?string $json): string
|
||||
{
|
||||
if (Preg::isMatchStrictGroups('#^([ \t]+)"#m', $json ?? '', $match)) {
|
||||
return $match[1];
|
||||
}
|
||||
return self::INDENT_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -561,10 +561,6 @@ class JsonManipulator
|
|||
|
||||
protected function detectIndenting(): void
|
||||
{
|
||||
if (Preg::isMatchStrictGroups('{^([ \t]+)"}m', $this->contents, $match)) {
|
||||
$this->indent = $match[1];
|
||||
} else {
|
||||
$this->indent = ' ';
|
||||
}
|
||||
$this->indent = JsonFile::detectIndenting($this->contents);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,8 +139,13 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
{
|
||||
parent::__construct();
|
||||
if (!Preg::isMatch('{^[\w.]+\??://}', $repoConfig['url'])) {
|
||||
// assume http as the default protocol
|
||||
$repoConfig['url'] = 'http://'.$repoConfig['url'];
|
||||
if (($localFilePath = realpath($repoConfig['url'])) !== false) {
|
||||
// it is a local path, add file scheme
|
||||
$repoConfig['url'] = 'file://'.$localFilePath;
|
||||
} else {
|
||||
// otherwise, assume http as the default protocol
|
||||
$repoConfig['url'] = 'http://'.$repoConfig['url'];
|
||||
}
|
||||
}
|
||||
$repoConfig['url'] = rtrim($repoConfig['url'], '/');
|
||||
if ($repoConfig['url'] === '') {
|
||||
|
|
|
@ -19,7 +19,7 @@ class PackageInfo
|
|||
{
|
||||
public static function getViewSourceUrl(PackageInterface $package): ?string
|
||||
{
|
||||
if ($package instanceof CompletePackageInterface && isset($package->getSupport()['source'])) {
|
||||
if ($package instanceof CompletePackageInterface && isset($package->getSupport()['source']) && '' !== $package->getSupport()['source']) {
|
||||
return $package->getSupport()['source'];
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,12 @@ class PackageInfo
|
|||
|
||||
public static function getViewSourceOrHomepageUrl(PackageInterface $package): ?string
|
||||
{
|
||||
return self::getViewSourceUrl($package) ?? ($package instanceof CompletePackageInterface ? $package->getHomepage() : null);
|
||||
$url = self::getViewSourceUrl($package) ?? ($package instanceof CompletePackageInterface ? $package->getHomepage() : null);
|
||||
|
||||
if ($url === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Test\Command;
|
||||
|
||||
use Composer\Test\TestCase;
|
||||
use Generator;
|
||||
|
||||
class ReinstallCommandTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider caseProvider
|
||||
* @param array<string> $packages
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testReinstallCommand(array $packages, string $expected): void
|
||||
{
|
||||
$this->initTempComposer([
|
||||
'require' => [
|
||||
'root/req' => '1.*',
|
||||
'root/anotherreq' => '2.*'
|
||||
]
|
||||
]);
|
||||
|
||||
$rootReqPackage = self::getPackage('root/req');
|
||||
$anotherReqPackage = self::getPackage('root/anotherreq');
|
||||
$rootReqPackage->setType('metapackage');
|
||||
$anotherReqPackage->setType('metapackage');
|
||||
|
||||
$this->createComposerLock([$rootReqPackage], [$anotherReqPackage]);
|
||||
$this->createInstalledJson([$rootReqPackage], [$anotherReqPackage]);
|
||||
|
||||
$appTester = $this->getApplicationTester();
|
||||
$appTester->run([
|
||||
'command' => 'reinstall',
|
||||
'--no-progress' => true,
|
||||
'--no-plugins' => true,
|
||||
'packages' => $packages
|
||||
]);
|
||||
|
||||
$this->assertSame($expected, trim($appTester->getDisplay(true)));
|
||||
}
|
||||
|
||||
public function caseProvider(): Generator
|
||||
{
|
||||
yield 'reinstall a package' => [
|
||||
['root/req', 'root/anotherreq'],
|
||||
'- Removing root/req (1.0.0)
|
||||
- Removing root/anotherreq (1.0.0)
|
||||
- Installing root/anotherreq (1.0.0)
|
||||
- Installing root/req (1.0.0)'
|
||||
];
|
||||
|
||||
yield 'reinstall a package that is not installed' => [
|
||||
['root/unknownreq'],
|
||||
'<warning>Pattern "root/unknownreq" does not match any currently installed packages.</warning>
|
||||
<warning>Found no packages to reinstall, aborting.</warning>'
|
||||
];
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@ Updating dependencies
|
|||
Your requirements could not be resolved to an installable set of packages.
|
||||
|
||||
Problem 1
|
||||
- Root composer.json requires a/aliased 3.0.2 as 3.0.3, found a/aliased[1.2.3] but it does not match the constraint.
|
||||
- Root composer.json requires a/aliased 3.0.2 as 3.0.3 (exact version match), found a/aliased[1.2.3] but it does not match the constraint.
|
||||
|
||||
--EXPECT--
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ Your requirements could not be resolved to an installable set of packages.
|
|||
Problem 3
|
||||
- Root composer.json requires linked library lib-icu 1001.* but it has the wrong version installed, try upgrading the intl extension.
|
||||
Problem 4
|
||||
- Root composer.json requires PHP extension ext-foobar 1.0.0 but it is missing from your system. Install or enable PHP's foobar extension.
|
||||
- Root composer.json requires PHP extension ext-foobar 1.0.0 (exact version match: 1.0.0 or 1.0.0.0) but it is missing from your system. Install or enable PHP's foobar extension.
|
||||
Problem 5
|
||||
- Root composer.json requires PHP extension ext-pcre ^8 but the ext-pcre package is disabled by your platform config. Enable it again with "composer config platform.ext-pcre --unset".
|
||||
Problem 6
|
||||
|
|
|
@ -113,7 +113,7 @@ Your requirements could not be resolved to an installable set of packages.
|
|||
Problem 3
|
||||
- Root composer.json requires non-existent/pkg, it could not be found in any version, there may be a typo in the package name.
|
||||
Problem 4
|
||||
- Root composer.json requires stable-requiree-excluded/pkg 1.0.1, found stable-requiree-excluded/pkg[1.0.1] but the package is fixed to 1.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
|
||||
- Root composer.json requires stable-requiree-excluded/pkg 1.0.1 (exact version match: 1.0.1 or 1.0.1.0), found stable-requiree-excluded/pkg[1.0.1] but the package is fixed to 1.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
|
||||
Problem 5
|
||||
- Root composer.json requires linked library lib-xml 1002.* but it has the wrong version installed or is missing from your system, make sure to load the extension providing it.
|
||||
Problem 6
|
||||
|
@ -121,7 +121,7 @@ Your requirements could not be resolved to an installable set of packages.
|
|||
Problem 7
|
||||
- Root composer.json requires PHP extension ext-xml 1002.* but it has the wrong version installed (%s).
|
||||
Problem 8
|
||||
- Root composer.json requires php 1 but your php version (%s) does not satisfy that requirement.
|
||||
- Root composer.json requires php 1 (exact version match: 1, 1.0, 1.0.0 or 1.0.0.0) but your php version (%s) does not satisfy that requirement.
|
||||
Problem 9
|
||||
- Root composer.json requires package/found 2.* -> satisfiable by package/found[2.0.0].
|
||||
- package/found 2.0.0 requires unstable/package2 2.* -> found unstable/package2[2.0.0-alpha] but it does not match your minimum-stability.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"foo": "bar"
|
||||
}
|
|
@ -436,6 +436,29 @@ class JsonFileTest extends TestCase
|
|||
JsonFile::parseJson($data);
|
||||
}
|
||||
|
||||
public function testPreserveIndentationAfterRead(): void
|
||||
{
|
||||
copy(__DIR__.'/Fixtures/tabs.json', __DIR__.'/Fixtures/tabs2.json');
|
||||
$jsonFile = new JsonFile(__DIR__.'/Fixtures/tabs2.json');
|
||||
$data = $jsonFile->read();
|
||||
$jsonFile->write(['foo' => 'baz']);
|
||||
|
||||
self::assertSame("{\n\t\"foo\": \"baz\"\n}\n", file_get_contents(__DIR__.'/Fixtures/tabs2.json'));
|
||||
|
||||
unlink(__DIR__.'/Fixtures/tabs2.json');
|
||||
}
|
||||
|
||||
public function testOverwritesIndentationByDefault(): void
|
||||
{
|
||||
copy(__DIR__.'/Fixtures/tabs.json', __DIR__.'/Fixtures/tabs2.json');
|
||||
$jsonFile = new JsonFile(__DIR__.'/Fixtures/tabs2.json');
|
||||
$jsonFile->write(['foo' => 'baz']);
|
||||
|
||||
self::assertSame("{\n \"foo\": \"baz\"\n}\n", file_get_contents(__DIR__.'/Fixtures/tabs2.json'));
|
||||
|
||||
unlink(__DIR__.'/Fixtures/tabs2.json');
|
||||
}
|
||||
|
||||
private function expectParseException(string $text, string $json): void
|
||||
{
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue