Skip to content

Commit

Permalink
NEW Refactor CLI interaction with Silverstripe app
Browse files Browse the repository at this point in the history
- Turn sake into a symfony/console app
- Avoid using HTTPRequest for CLI interaction
- Implement abstract hybrid execution path
  • Loading branch information
GuySartorelli committed Aug 27, 2024
1 parent e3508d4 commit db57250
Show file tree
Hide file tree
Showing 19 changed files with 1,109 additions and 458 deletions.
7 changes: 3 additions & 4 deletions _config/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
Name: DevelopmentAdmin
---
SilverStripe\Dev\DevelopmentAdmin:
commands:
config: 'SilverStripe\Dev\HybridExecution\Command\DevConfig'
'config:audit': 'SilverStripe\Dev\HybridExecution\Command\DevConfigAudit'
registered_controllers:
build:
controller: SilverStripe\Dev\DevBuildController
Expand All @@ -13,10 +16,6 @@ SilverStripe\Dev\DevelopmentAdmin:
tasks: 'See a list of build tasks to run'
confirm:
controller: SilverStripe\Dev\DevConfirmationController
config:
controller: Silverstripe\Dev\DevConfigController
links:
config: 'View the current config, useful for debugging'

SilverStripe\Dev\CSSContentParser:
disable_xml_external_entities: true
21 changes: 21 additions & 0 deletions bin/sake
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php

use SilverStripe\Cli\Sake;

// Ensure that people can't access this from a web-server
if (!in_array(PHP_SAPI, ['cli', 'cgi', 'cgi-fcgi'])) {
echo 'sake cannot be run from a web request, you have to run it on the command-line.';
die();
}

require_once __DIR__ . '/../src/includes/autoload.php';

$sake = new Sake();
$sake->addCommands([
// probably do this inside the sake app itself though
// TODO:
// - flush
// - navigate (use HTTPRequest and spin off a "web" request from CLI)
]);
$sake->run();
35 changes: 0 additions & 35 deletions cli-script.php

This file was deleted.

5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
}
],
"bin": [
"sake"
"bin/sake"
],
"require": {
"php": "^8.3",
Expand All @@ -36,12 +36,14 @@
"psr/container": "^1.1 || ^2.0",
"psr/http-message": "^1",
"sebastian/diff": "^4.0",
"sensiolabs/ansi-to-html": "^1.2",
"silverstripe/config": "^3",
"silverstripe/assets": "^3",
"silverstripe/vendor-plugin": "^2",
"sminnee/callbacklist": "^0.1.1",
"symfony/cache": "^6.1",
"symfony/config": "^6.1",
"symfony/console": "^7.0",
"symfony/dom-crawler": "^6.1",
"symfony/filesystem": "^6.1",
"symfony/http-foundation": "^6.1",
Expand Down Expand Up @@ -85,6 +87,7 @@
},
"autoload": {
"psr-4": {
"SilverStripe\\Cli\\": "src/Cli/",
"SilverStripe\\Control\\": "src/Control/",
"SilverStripe\\Control\\Tests\\": "tests/php/Control/",
"SilverStripe\\Core\\": "src/Core/",
Expand Down
119 changes: 0 additions & 119 deletions sake

This file was deleted.

52 changes: 52 additions & 0 deletions src/Cli/ArrayCommandLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace SilverStripe\Cli;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Exception\CommandNotFoundException;

/**
* Command loader that holds more command loaders
*/
class ArrayCommandLoader implements CommandLoaderInterface
{
/**
* @var array<CommandLoaderInterface>
*/
private array $loaders = [];

public function __construct(array $loaders)
{
$this->loaders = $loaders;
}

public function get(string $name): Command
{
foreach ($this->loaders as $loader) {
if ($loader->has($name)) {
return $loader->get($name);
}
}
throw new CommandNotFoundException("Can't find command $name");
}

public function has(string $name): bool
{
foreach ($this->loaders as $loader) {
if ($loader->has($name)) {
return true;
}
}
return false;
}

public function getNames(): array
{
$names = [];
foreach ($this->loaders as $loader) {
$names = array_merge($names, $loader->getNames());
}
return array_unique($names);
}
}
91 changes: 91 additions & 0 deletions src/Cli/DevCommandLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace SilverStripe\Cli;

use SilverStripe\Dev\DevelopmentAdmin;
use SilverStripe\Dev\HybridExecution\Command\HybridCommand;
use SilverStripe\Dev\HybridExecution\HybridOutput;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Get commands for the controllers registered in DevelopmentAdmin
*/
class DevCommandLoader implements CommandLoaderInterface
{
private $commands = [];

public function get(string $name): Command
{
$this->init();
$name = $this->deAlias($name);
if (!$this->has($name)) {
throw new CommandNotFoundException("Can't find command $name");
}
/** @var HybridCommand $commandClass */
$commandClass = $this->commands[$name];
$hybridCommand = $commandClass::create();
// Use the name that was passed into the method instead of fetching from the hybrid command
// because it includes the full namespace.
// TODO move all this (plus getting $hybridCommand->getOptions()) into its own class to wrap hybridcommand with
// we'll be reusing it for dev/tasks after all.
$command = new Command($name);
$command->setAliases([$this->makeAlias($name)]);
$command->setDescription($hybridCommand->getDescription());
$command->setCode(function (InputInterface $input, OutputInterface $output) use ($hybridCommand) {
$hybridOutput = HybridOutput::create(
HybridOutput::CONTEXT_CONSOLE,
$output->getVerbosity(),
$output->isDecorated(),
$output
);
// TODO make the title look a lil nicer
$hybridOutput->writeln([$hybridCommand->getTitle(), '--------']);
return $hybridCommand->run($input, $hybridOutput);
});
return $command;
}

public function has(string $name): bool
{
$this->init();
if (array_key_exists($name, $this->commands)) {
return true;
}
var_dump($name);
return array_key_exists($this->deAlias($name), $this->commands);
}

public function getNames(): array
{
$this->init();
return array_keys($this->commands);
}

private function init(): void
{
if (!empty($this->commands)) {
return;
}
$commands = DevelopmentAdmin::singleton()->getCommands();
foreach ($commands as $name => $class) {
if (!$class::canRunInBrowser()) {
unset($commands[$name]);
}
}
$this->commands = $commands;
}

private function deAlias(string $name): string
{
return str_replace('/', ':', $name);
}

private function makeAlias(string $name): string
{
return str_replace(':', '/', $name);
}
}
Loading

0 comments on commit db57250

Please sign in to comment.