Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 9 additions & 15 deletions system/Boot.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,8 @@ public static function bootSpark(Paths $paths): int
static::autoloadHelpers();

static::initializeCodeIgniter();
$console = static::initializeConsole();

return static::runCommand($console);
return static::runCommand(static::initializeConsole());
}

/**
Expand Down Expand Up @@ -424,23 +423,18 @@ protected static function saveConfigCache(FactoriesCache $factoriesCache): void

protected static function initializeConsole(): Console
{
$console = new Console();

// Show basic information before we do anything else.
if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) {
unset($_SERVER['argv'][$suppress]);
$suppress = true;
}

$console->showHeader($suppress);

return $console;
return new Console();
}

protected static function runCommand(Console $console): int
{
$exit = $console->run();
$exitCode = $console->initialize()->run();

if (! is_int($exitCode)) {
@trigger_error(sprintf('Starting with CodeIgniter v4.8.0, commands must return an integer exit code. Last command exited with %s. Defaulting to EXIT_SUCCESS.', get_debug_type($exitCode)), E_USER_DEPRECATED);
$exitCode = EXIT_SUCCESS;
}

return is_int($exit) ? $exit : EXIT_SUCCESS;
return $exitCode;
}
}
78 changes: 49 additions & 29 deletions system/CLI/Console.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,61 @@
use CodeIgniter\CodeIgniter;
use Config\App;
use Config\Services;
use Exception;

/**
* Console
*
* @see \CodeIgniter\CLI\ConsoleTest
*/
class Console
{
private const DEFAULT_COMMAND = 'list';

/**
* @var array<string, string|null>
*/
private array $options = [];

/**
* Runs the current command discovered on the CLI.
*
* @return int|void Exit code
* @param list<string> $tokens
*
* @throws Exception
* @return int|null Exit code or null for legacy commands that don't return an exit code.
*/
public function run()
public function run(array $tokens = [])
{
// Create CLIRequest
$appConfig = config(App::class);
Services::createRequest($appConfig, true);
// Load Routes
service('routes')->loadRoutes();
if ($tokens === []) {
$tokens = service('superglobals')->server('argv', []);
}

$parser = new CommandLineParser($tokens);

$arguments = $parser->getArguments();
$this->options = $parser->getOptions();

$this->showHeader($this->hasParameterOption(['no-header']));
unset($this->options['no-header']);

$params = array_merge(CLI::getSegments(), CLI::getOptions());
$params = $this->parseParamsForHelpOption($params);
$command = array_shift($params) ?? 'list';
if ($this->hasParameterOption(['help'])) {
unset($this->options['help']);

return service('commands')->run($command, $params);
if ($arguments === []) {
$arguments = ['help', self::DEFAULT_COMMAND];
} elseif ($arguments[0] !== 'help') {
array_unshift($arguments, 'help');
}
}

$command = array_shift($arguments) ?? self::DEFAULT_COMMAND;

return service('commands')->run($command, array_merge($arguments, $this->options));
}

public function initialize(): static
{
Services::createRequest(config(App::class), true);
service('routes')->loadRoutes();

return $this;
}

/**
Expand All @@ -67,24 +93,18 @@ public function showHeader(bool $suppress = false)
}

/**
* Introspects the `$params` passed for presence of the
* `--help` option.
* Checks whether any of the options are present in the command line.
*
* If present, it will be found as `['help' => null]`.
* We'll remove that as an option from `$params` and
* unshift it as argument instead.
*
* @param array<int|string, string|null> $params
* @param list<string> $options
*/
private function parseParamsForHelpOption(array $params): array
private function hasParameterOption(array $options): bool
{
if (array_key_exists('help', $params)) {
unset($params['help']);

$params = $params === [] ? ['list'] : $params;
array_unshift($params, 'help');
foreach ($options as $option) {
if (array_key_exists($option, $this->options)) {
return true;
}
}

return $params;
return false;
}
}
47 changes: 15 additions & 32 deletions system/Common.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

use CodeIgniter\Cache\CacheInterface;
use CodeIgniter\CLI\Console;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Config\Factories;
use CodeIgniter\Context\Context;
Expand Down Expand Up @@ -127,7 +128,7 @@ function command(string $command)
$regexString = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
$regexQuoted = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';

$args = [];
$tokens = [];
$length = strlen($command);
$cursor = 0;

Expand All @@ -140,9 +141,9 @@ function command(string $command)
if (preg_match('/\s+/A', $command, $match, 0, $cursor)) {
// nothing to do
} elseif (preg_match('/' . $regexQuoted . '/A', $command, $match, 0, $cursor)) {
$args[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
$tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
} elseif (preg_match('/' . $regexString . '/A', $command, $match, 0, $cursor)) {
$args[] = stripcslashes($match[1]);
$tokens[] = stripcslashes($match[1]);
} else {
// @codeCoverageIgnoreStart
throw new InvalidArgumentException(sprintf(
Expand All @@ -155,39 +156,21 @@ function command(string $command)
$cursor += strlen($match[0]);
}

/** @var array<int|string, string|null> */
$params = [];
$command = array_shift($args);
$optionValue = false;

foreach ($args as $i => $arg) {
if (mb_strpos($arg, '-') !== 0) {
if ($optionValue) {
// if this was an option value, it was already
// included in the previous iteration
$optionValue = false;
} else {
// add to segments if not starting with '-'
// and not an option value
$params[] = $arg;
}

continue;
}

$arg = ltrim($arg, '-');
$value = null;

if (isset($args[$i + 1]) && mb_strpos($args[$i + 1], '-') !== 0) {
$value = $args[$i + 1];
$optionValue = true;
// Don't show the header as it is not needed when running commands from code.
if (! in_array('--no-header', $tokens, true)) {
if (! in_array('--', $tokens, true)) {
$tokens[] = '--no-header';
} else {
$index = (int) array_search('--', $tokens, true);
array_splice($tokens, $index, 0, '--no-header');
}

$params[$arg] = $value;
}

// Prepend an application name, as Console expects one.
array_unshift($tokens, 'spark');

ob_start();
service('commands')->run($command, $params);
(new Console())->run($tokens);

return ob_get_clean();
}
Expand Down
Loading
Loading