You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
spip-cli/src/Application.php

267 lines
7.4 KiB
PHP

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace Spip\Cli;
use Psr\Container\ContainerInterface;
use Spip\Cli\Console\Style\SpipCliStyle;
use Spip\Cli\Container\Container;
use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
class Application extends ConsoleApplication {
const NAME = "Spip Cli";
const VERSION = "1.0.2";
/** @var Container */
protected $container;
/**
* Application constructor.
*
* Charge automatiquement les commandes présentes
* dans le répertoire Command de ce projet.
*
* @param array $options
*/
public function __construct(array $options = []) {
parent::__construct(self::NAME, self::VERSION);
$this->container = new Container([], $options + [
'debug' => false,
'spip.directory' => null,
'spip.webmestre.email' => '',
'spip.webmestre.login' => '',
'spip.webmestre.nom' => '',
'spip.webmestre.login.prefixe' => 'SpipCli-',
'cwd' => getcwd()
]);
$this->setTimezone();
$this->registerServices();
$this->registerCommandsInProject(self::class);
$this->loadSpip(); // hum…
$this->registerCommandsInSpip();
}
protected function registerServices(): void {
$app = $this;
$container = $this->container;
$container->set('console.io', function() use ($app) {
return function(InputInterface $input = null, OutputInterface $output = null) use ($app) {
if (null === $input) {
$input = new ArgvInput();
}
if (null === $output) {
$output = new ConsoleOutput();
$app->configureIO($input, $output);
}
return new Console\Style\SpipCliStyle($input, $output);
};
});
$container->set('loader.spip', function (ContainerInterface $container) {
$spip = new Loader\Spip($container->get('spip.directory'));
$spip->setContainer($container);
return $spip;
});
$container->set('sql.query', function (ContainerInterface $container) {
$connect = $container->get('loader.spip')->getPathConnect();
if (!is_file($connect)) {
throw new \Exception('SPIP database is not configured');
}
$sql = new Loader\Sql($connect);
return new Sql\Query($sql);
});
}
/**
* @note
* Alors ça, il faudrait plutôt que ça soit les commandes
* qui demandent le chargement de SPIP si elles en ont besoin,
* afin de faire des commandes où SPIP nest pas chargé encore…
*/
public function loadSpip(): void {
try {
$spip = $this->container->get('loader.spip');
$spip->load();
} catch (\Exception $e) {
$io = $this->getIo();
if (!in_array($io->getVerbosity(), [
OutputInterface::VERBOSITY_QUIET,
OutputInterface::VERBOSITY_NORMAL
])) {
$io->note($e->getMessage());
}
}
}
/**
* Ajoute les commandes contenues dans le répertoire Command du même chemin que la classe transmise
*/
public function registerCommandsInProject($class): void {
foreach ($this->findCommandsInProject($class) as $command) {
if (class_exists($command)) {
$this->add(new $command());
}
}
}
/**
* Retourne la liste des commandes au même niveau que ce projet
* @return array
* @throws \ReflectionException
*/
public function findCommandsInProject($class): array {
$class = new \ReflectionClass($class);
$commandDir = dirname($class->getFilename()) . '/Command'; // .../spip-cli/src/Command
$list = [];
if (is_dir($commandDir)) {
$namespace = $class->getNamespaceName(); // Spip\Cli
$finder = new Finder();
$finder->files()->in($commandDir)->name('*.php');
foreach ($finder as $file) {
// Spip\Cli\Command\Name
$list[] = $namespace . '\\Command\\' . str_replace('/', '\\', substr($file->getRelativePathname(), 0, -4));
}
}
return $list;
}
/**
* Chargement automatique des commandes spip-cli/ présentes dans les répertoires spip-cli/
* des plugins SPIP
*/
public function registerCommandsInSpip(): bool {
// les commandes dans spip-cli/ des plugins SPIP actifs
$this->registerSpipCliPluginsCommands();
// charger les vilaines globales utilisées dans les commandes spip-cli
try {
global $spip_racine, $spip_loaded, $cwd;
$cwd = getcwd();
$spip = $this->container->get('loader.spip');
$spip_racine = $spip->getDirectory();
$spip_loaded = $spip->load();
} catch (\Exception $e) {
return false;
}
return false;
}
/**
* Chargement des commandes présentes dans 'spip-cli/' des plugins SPIP actifs.
*
* Nécessite de démarrer SPIP (et donc dêtre dans un SPIP)
*/
public function registerSpipCliPluginsCommands(): bool {
try {
$spip = $this->container->get('loader.spip');
if (!$spip->load()) {
return false;
}
} catch (\Exception $e) {
return false;
}
$cwd = getcwd();
$spip->chdir();
$commandes = find_all_in_path('spip-cli/', '.*[.]php$');
// pas le spip.php à la racine de ce plugin (lancien exécutable pour démarrer spip-cli);
$commandes = array_filter($commandes, function($commande) {
return strpos($commande, "spip-cli/spip.php") === false;
});
foreach ($commandes as $path) {
$this->registerSpipCliCommand($path);
}
chdir($cwd);
return true;
}
/**
* Déclare une commande "Spip Cli"
*/
public function registerSpipCliCommand($path): void {
include_once($path);
$command = '\\' . basename($path, '.php');
if ($namespace = Tools\Files::getNamespace($path)) {
$command = '\\' . $namespace . $command;
}
if (class_exists($command)) {
$this->add(new $command());
}
}
/**
* If the timezone is not set anywhere, set it to UTC.
*/
protected function setTimezone(): void {
if (false == ini_get('date.timezone')) {
// on se synchro sur la date system si possible
$date = trim(shell_exec("date -R"));
$date = explode(' ', $date);
if (
preg_match(",^[+-][0-9][0-9][0-9][0-9]$,", end($date))
and $offset_target = intval(end($date))/100
and $zone = timezone_name_from_abbr("", 3600 * $offset_target, 0)
) {
date_default_timezone_set($zone);
// se recaler en cas de daylight saving time
$offset_real = intval(date_offset_get(new \DateTime) / 3600);
if ($offset_real > $offset_target) {
$zone = timezone_name_from_abbr("", 3600 * $offset_target, 1);
date_default_timezone_set($zone);
}
} else {
date_default_timezone_set('UTC');
}
}
}
public function getContainer(): Container {
return $this->container;
}
/** @return mixed */
public function getService($name) {
return $this->container->get($name);
}
/** Replace sur le répertoire de démarrage de lapplication */
public function restoreCwd(): void {
$cwd = $this->container->get('cwd');
chdir($cwd);
}
/**
* Retourne un écriveur pour console (étend SymfonyStyle)
*/
public function getIo(InputInterface $input = null, OutputInterface $output = null): SpipCliStyle {
$io = $this->container->get('console.io');
return $io($input, $output);
}
/**
* Affiche laide dune commande donnée
* @param string $commandName
* @param OutputInterface|null $output
*/
public function showHelp($commandName, OutputInterface $output = null): void {
if (null === $output) {
$output = new ConsoleOutput();
}
$command = $this->find('help');
$arguments = array(
'command' => 'help',
'command_name' => $commandName,
);
$input = new ArrayInput($arguments);
$command->run($input, $output);
}
}