1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/guanguans-soar-php

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
composer-updater 13 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
guanguans Отправлено 16.08.2024 11:19 4bbecab
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
* This file is part of the guanguans/soar-php.
*
* (c) guanguans <ityaozm@gmail.com>
*
* This source file is subject to the MIT license that is bundled.
*/
use Composer\InstalledVersions;
use SebastianBergmann\Diff\Differ;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
require __DIR__.'/vendor/autoload.php';
/** @noinspection PhpUnhandledExceptionInspection */
$status = (new SingleCommandApplication())
->setName('Composer Updater')
->addOption('composer-json-path', null, InputOption::VALUE_OPTIONAL)
->addOption('highest-php-binary', null, InputOption::VALUE_REQUIRED)
->addOption('composer-binary', null, InputOption::VALUE_OPTIONAL)
->addOption('except-packages', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL)
->addOption('except-dependency-versions', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL)
->addOption('dry-run', null, InputOption::VALUE_NONE)
->setCode(function (InputInterface $input, OutputInterface $output): void {
assert_options(\ASSERT_BAIL, 1);
assert($this instanceof SingleCommandApplication);
assert((bool) $input->getOption('highest-php-binary'));
(new class(
$input->getOption('composer-json-path') ?: __DIR__.'/composer.json',
$input->getOption('highest-php-binary'),
$input->getOption('composer-binary'),
$input->getOption('except-packages'),
$input->getOption('except-dependency-versions'),
$input->getOption('dry-run'),
new SymfonyStyle($input, $output),
new Differ()
) {
private $composerJsonPath;
private $composerJsonContents;
private $highestComposerBinary;
private $composerBinary;
private $exceptPackages;
private $exceptDependencyVersions;
private $dryRun;
private $symfonyStyle;
private $differ;
/**
* @noinspection ParameterDefaultsNullInspection
*/
public function __construct(
string $composerJsonPath,
?string $highestPhpBinary = null,
?string $composerBinary = null,
array $exceptPackages = [],
array $exceptDependencyVersions = [],
bool $dryRun = false,
?SymfonyStyle $symfonyStyle = null,
?Differ $differ = null
) {
assert_options(\ASSERT_BAIL, 1);
assert((bool) $composerJsonPath);
$this->composerJsonPath = $composerJsonPath;
$this->composerJsonContents = file_get_contents($composerJsonPath);
$this->highestComposerBinary = $this->getComposerBinary($composerBinary, $highestPhpBinary);
$this->composerBinary = $this->getComposerBinary($composerBinary);
$this->exceptPackages = array_merge([
'php',
'ext-*',
], $exceptPackages);
$this->exceptDependencyVersions = array_merge([
'\*',
'*-*',
'*@*',
// '*|*',
], $exceptDependencyVersions);
$this->dryRun = $dryRun;
$this->symfonyStyle = $symfonyStyle ?? new SymfonyStyle(new ArgvInput(), new ConsoleOutput());
$this->differ = $differ ?? new Differ();
}
public function __invoke(): void
{
$this
->updateComposerPackages()
->updateOutdatedComposerPackages()
->updateComposerPackages()
->updateOutdatedComposerPackages()
->updateComposerPackages()
->normalizeComposerJson()
->success();
}
private function updateComposerPackages(): self
{
$this->mustRunCommand("$this->composerBinary update -W --ansi");
return $this;
}
/**
* @noinspection JsonEncodingApiUsageInspection
*
* @return $this|never-return
*/
private function updateOutdatedComposerPackages(): self
{
$outdatedComposerJsonContents = json_encode(
$this->getOutdatedDecodedComposerJson(),
\JSON_PRETTY_PRINT | \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES
).\PHP_EOL;
if ($this->dryRun) {
$this->symfonyStyle->writeln($this->formatDiff($this->differ->diff(
$this->composerJsonContents,
$outdatedComposerJsonContents
)));
exit(0);
}
file_put_contents($this->composerJsonPath, $outdatedComposerJsonContents);
return $this;
}
private function normalizeComposerJson(): self
{
$this->mustRunCommand("$this->composerBinary normalize --diff --ansi");
return $this;
}
private function success(): void
{
$this->symfonyStyle->success('Composer packages updated successfully!');
}
/**
* @noinspection JsonEncodingApiUsageInspection
*/
private function getOutdatedDecodedComposerJson(): array
{
$outdatedComposerPackages = $this->getOutdatedComposerPackages();
$decodedComposerJson = json_decode(file_get_contents($this->composerJsonPath), true);
(function () {
return self::reload(null);
})->call(new InstalledVersions());
foreach ($decodedComposerJson as $name => &$value) {
if (! in_array($name, ['require', 'require-dev'], true)) {
continue;
}
foreach ($value as $package => &$dependencyVersion) {
if (
$this->strIs($this->exceptPackages, $package)
|| $this->strIs($this->exceptDependencyVersions, $dependencyVersion)
) {
continue;
}
if ($version = InstalledVersions::getVersion($package)) {
$dependencyVersion = $this->toDependencyVersion($version);
}
if (isset($outdatedComposerPackages[$package])) {
$dependencyVersion = $outdatedComposerPackages[$package]['dependency_version'];
}
}
}
return $decodedComposerJson;
}
/**
* @noinspection JsonEncodingApiUsageInspection
*/
private function getOutdatedComposerPackages(): array
{
return array_reduce(
json_decode(
$this
->mustRunCommand("$this->highestComposerBinary outdated --format=json --direct --ansi")
->getOutput(),
true
)['installed'],
function (array $carry, array $package): array {
$lowestArrayVersion = $this->toArrayVersion($package['version']);
$highestArrayVersion = $this->toArrayVersion($package['latest']);
$dependencyVersions = [$this->toDependencyVersion($package['version'])];
if ($lowestArrayVersion[0] !== $highestArrayVersion[0]) {
$dependencyVersions = array_merge($dependencyVersions, array_map(
static function (string $major): string {
return "^$major.0";
},
range($lowestArrayVersion[0] + 1, $highestArrayVersion[0])
));
}
$package['dependency_version'] = implode(' || ', $dependencyVersions);
$carry[$package['name']] = $package;
return $carry;
},
[]
);
}
private function getComposerBinary(?string $composerBinary = null, ?string $phpBinary = null): string
{
return sprintf(
'%s %s',
$phpBinary ?? (new PhpExecutableFinder())->find(),
$composerBinary ?? (new ExecutableFinder())->find('composer')
);
}
/**
* @noinspection MissingParameterTypeDeclarationInspection
* @noinspection PhpSameParameterValueInspection
*
* @param array|string $command
* @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input
*/
private function mustRunCommand(
$command,
?string $cwd = null,
?array $env = null,
$input = null,
?float $timeout = 300
): Process {
$process = is_string($command)
? Process::fromShellCommandline($command, $cwd, $env, $input, $timeout)
: new Process($command, $cwd, $env, $input, $timeout);
$this->symfonyStyle->warning($process->getCommandLine());
return $process
->setWorkingDirectory(dirname($this->composerJsonPath))
->setEnv(['COMPOSER_MEMORY_LIMIT' => -1])
->mustRun(function (string $type, string $buffer): void {
$this->symfonyStyle->isVerbose() and $this->symfonyStyle->write($buffer);
});
}
private function toDependencyVersion(string $version): string
{
return '^'.implode('.', array_slice($this->toArrayVersion($version), 0, 2));
}
private function toArrayVersion(string $version): array
{
return explode('.', ltrim($version, 'v'));
}
/**
* @noinspection SuspiciousLoopInspection
* @noinspection ComparisonScalarOrderInspection
* @noinspection MissingParameterTypeDeclarationInspection
*
* @param array|string $pattern
*/
private function strIs($pattern, string $value): bool
{
$patterns = (array) $pattern;
if (empty($patterns)) {
return false;
}
foreach ($patterns as $pattern) {
$pattern = (string) $pattern;
if ($pattern === $value) {
return true;
}
$pattern = preg_quote($pattern, '#');
$pattern = str_replace('\*', '.*', $pattern);
if (1 === preg_match('#^'.$pattern.'\z#u', $value)) {
return true;
}
}
return false;
}
private function formatDiff(string $diff): string
{
$lines = explode(
"\n",
$diff,
);
$formatted = array_map(static function (string $line): string {
return preg_replace(
[
'/^(\+.*)$/',
'/^(-.*)$/',
],
[
'<fg=green>$1</>',
'<fg=red>$1</>',
],
$line,
);
}, $lines);
return implode(
"\n",
$formatted,
);
}
})();
})
->run();
exit($status);

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/guanguans-soar-php.git
git@api.gitlife.ru:oschina-mirror/guanguans-soar-php.git
oschina-mirror
guanguans-soar-php
guanguans-soar-php
master