update lock clucknut
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 14s
Build, Push and Deploy / build-and-push (push) Successful in 3m14s
Build, Push and Deploy / deploy-staging (push) Successful in 25s
Build, Push and Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-18 20:32:18 +07:00
parent 4554035227
commit dcaf267458
3359 changed files with 153185 additions and 205489 deletions

View File

@@ -761,6 +761,21 @@ public function find(string $name)
}));
}
// check whether all commands left are aliases to the same one
if (\count($commands) > 1) {
$uniqueCommands = array_unique(array_map(function ($nameOrAlias) use (&$commandList) {
if (!$commandList[$nameOrAlias] instanceof Command) {
$commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
}
return $commandList[$nameOrAlias]->getName();
}, $commands));
if (1 === \count($uniqueCommands)) {
$commands = [reset($uniqueCommands)];
}
}
if (\count($commands) > 1) {
$usableWidth = $this->terminal->getWidth() - 10;
$abbrevs = array_values($commands);

View File

@@ -115,24 +115,30 @@ protected function execute(InputInterface $input, OutputInterface $output): int
'<info>Messages:</>',
]);
$command = $this->findCommand($completionInput, $output);
if ($command = $this->findCommand($completionInput, $output)) {
$command->mergeApplicationDefinition();
$completionInput->bind($command->getDefinition());
}
if (null === $command) {
$this->log(' No command found, completing using the Application class.');
$this->getApplication()->complete($completionInput, $suggestions);
} elseif (
$completionInput->mustSuggestArgumentValuesFor('command')
&& $command->getName() !== $completionInput->getCompletionValue()
&& !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true)
) {
$this->log(' No command found, completing using the Application class.');
$this->log(' Command found, completing command name.');
// expand shortcut names ("cache:cl<TAB>") into their full name ("cache:clear")
$suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases())));
$commandNames = array_filter(array_merge([$command->getName()], $command->getAliases()));
foreach ($commandNames as $name) {
if (str_starts_with($name, $completionInput->getCompletionValue())) {
$commandNames = [$name];
break;
}
}
$suggestions->suggestValues($commandNames);
} else {
$command->mergeApplicationDefinition();
$completionInput->bind($command->getDefinition());
if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
$this->log(' Completing option names for the <comment>'.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.'</> command.');

View File

@@ -22,7 +22,7 @@ public function __construct(\Throwable|string $exception, public readonly RunCom
{
parent::__construct(
$exception instanceof \Throwable ? $exception->getMessage() : $exception,
$exception instanceof \Throwable ? $exception->getCode() : 0,
$exception instanceof \Throwable && \is_int($exception->getCode()) ? $exception->getCode() : 0,
$exception instanceof \Throwable ? $exception : null,
);
}

View File

@@ -133,6 +133,10 @@ public function formatAndWrap(?string $message, int $width)
return '';
}
// For ASCII-only strings, byte positions equal character positions,
// so we can use native strlen/substr which is much faster than Helper::length/substr.
$isAscii = !preg_match('/[\x80-\xFF]/', $message);
$offset = 0;
$output = '';
$openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
@@ -147,11 +151,17 @@ public function formatAndWrap(?string $message, int $width)
continue;
}
// convert byte position to character position.
$pos = Helper::length(substr($message, 0, $pos));
// add the text up to the next tag
$output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + Helper::length($text);
if ($isAscii) {
// For ASCII, byte position = character position, no conversion needed
$output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + \strlen($text);
} else {
// convert byte position to character position.
$pos = Helper::length(substr($message, 0, $pos));
// add the text up to the next tag
$output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
$offset = $pos + Helper::length($text);
}
// opening tag?
if ($open = '/' !== $text[1]) {
@@ -172,7 +182,7 @@ public function formatAndWrap(?string $message, int $width)
}
}
$output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength);
$output .= $this->applyCurrentStyle($isAscii ? substr($message, $offset) : Helper::substr($message, $offset), $output, $width, $currentLineLength);
return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
}

View File

@@ -13,6 +13,7 @@
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
/**
@@ -140,7 +141,9 @@ public function finish(string $message)
$this->message = $message;
$this->display();
$this->output->writeln('');
if (!$this->output instanceof ConsoleSectionOutput) {
$this->output->writeln('');
}
$this->started = false;
}
@@ -207,7 +210,9 @@ private function determineBestFormat(): string
*/
private function overwrite(string $message): void
{
if ($this->output->isDecorated()) {
if ($this->output instanceof ConsoleSectionOutput) {
$this->output->overwrite($message);
} elseif ($this->output->isDecorated()) {
$this->output->write("\x0D\x1B[2K");
$this->output->write($message);
} else {

View File

@@ -474,6 +474,8 @@ private function validateAttempts(callable $interviewer, OutputInterface $output
try {
return $question->getValidator()($interviewer());
} catch (MissingInputException $e) {
throw $error ?? $e;
} catch (RuntimeException $e) {
throw $e;
} catch (\Exception $error) {

View File

@@ -142,12 +142,27 @@ private function isRunningOS400(): bool
*/
private function openOutputStream()
{
static $stdout;
if ($stdout) {
return $stdout;
}
if (!$this->hasStdoutSupport()) {
return fopen('php://output', 'w');
return $stdout = fopen('php://output', 'w');
}
// Use STDOUT when possible to prevent from opening too many file descriptors
return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w'));
if (!\defined('STDOUT')) {
return $stdout = @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');
}
// On Windows, STDOUT is opened in text mode; reopen in binary mode to prevent \n to \r\n conversion
if ('\\' === \DIRECTORY_SEPARATOR) {
return $stdout = @fopen('php://stdout', 'w') ?: \STDOUT;
}
return $stdout = \STDOUT;
}
/**
@@ -155,11 +170,26 @@ private function openOutputStream()
*/
private function openErrorStream()
{
static $stderr;
if ($stderr) {
return $stderr;
}
if (!$this->hasStderrSupport()) {
return fopen('php://output', 'w');
return $stderr = fopen('php://output', 'w');
}
// Use STDERR when possible to prevent from opening too many file descriptors
return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w'));
if (!\defined('STDERR')) {
return $stderr = @fopen('php://stderr', 'w') ?: fopen('php://output', 'w');
}
// On Windows, STDERR is opened in text mode; reopen in binary mode to prevent \n → \r\n conversion
if ('\\' === \DIRECTORY_SEPARATOR) {
return $stderr = @fopen('php://stderr', 'w') ?: \STDERR;
}
return $stderr ??= \STDERR;
}
}

View File

@@ -104,7 +104,7 @@ public function section(string $message)
public function listing(array $elements)
{
$this->autoPrependText();
$elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements);
$elements = array_map(static fn ($element) => \sprintf(' * %s', $element), $elements);
$this->writeln($elements);
$this->newLine();
@@ -475,12 +475,14 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $
$message = OutputFormatter::escape($message);
}
$message = str_replace("\r\n", "\n", $message);
$lines = array_merge(
$lines,
explode(\PHP_EOL, $outputWrapper->wrap(
explode("\n", $outputWrapper->wrap(
$message,
$this->lineLength - $prefixLength - $indentLength,
\PHP_EOL
"\n"
))
);

View File

@@ -128,7 +128,7 @@ public static function hasSttyAvailable(): bool
return false;
}
return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
return self::$stty = (bool) @shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
}
private static function initDimensions(): void

View File

@@ -49,7 +49,7 @@ public function __construct(Application $application)
*/
public function run(array $input, array $options = []): int
{
$prevShellVerbosity = getenv('SHELL_VERBOSITY');
$prevShellVerbosity = [getenv('SHELL_VERBOSITY'), $_ENV['SHELL_VERBOSITY'] ?? false, $_SERVER['SHELL_VERBOSITY'] ?? false];
try {
$this->input = new ArrayInput($input);
@@ -63,22 +63,35 @@ public function run(array $input, array $options = []): int
$this->initOutput($options);
// Temporarily clear SHELL_VERBOSITY to prevent Application::configureIO
// from overriding the interactive and verbosity settings set above
if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY');
}
unset($_ENV['SHELL_VERBOSITY'], $_SERVER['SHELL_VERBOSITY']);
return $this->statusCode = $this->application->run($this->input, $this->output);
} finally {
// SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
// to its previous value to avoid one test's verbosity to spread to the following tests
if (false === $prevShellVerbosity) {
if (false === $prevShellVerbosity[0]) {
if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY');
}
unset($_ENV['SHELL_VERBOSITY']);
unset($_SERVER['SHELL_VERBOSITY']);
} else {
if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity[0]);
}
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
}
if (false === $prevShellVerbosity[1]) {
unset($_ENV['SHELL_VERBOSITY']);
} else {
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity[1];
}
if (false === $prevShellVerbosity[2]) {
unset($_SERVER['SHELL_VERBOSITY']);
} else {
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity[2];
}
}
}