updated core to 1.7.15
This commit is contained in:
106
system/src/Grav/Console/Application/Application.php
Normal file
106
system/src/Grav/Console/Application/Application.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Application;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class GpmApplication
|
||||
* @package Grav\Console\Application
|
||||
*/
|
||||
class Application extends \Symfony\Component\Console\Application
|
||||
{
|
||||
/** @var string|null */
|
||||
protected $environment;
|
||||
/** @var string|null */
|
||||
protected $language;
|
||||
/** @var bool */
|
||||
protected $initialized = false;
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCommandName(InputInterface $input): ?string
|
||||
{
|
||||
$this->environment = $input->getOption('env');
|
||||
$this->language = $input->getOption('lang') ?? $this->language;
|
||||
$this->init();
|
||||
|
||||
return parent::getCommandName($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function init(): void
|
||||
{
|
||||
if ($this->initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->initialized = true;
|
||||
|
||||
$grav = Grav::instance();
|
||||
$grav->setup($this->environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add global a --env option.
|
||||
*
|
||||
* @return InputDefinition
|
||||
*/
|
||||
protected function getDefaultInputDefinition(): InputDefinition
|
||||
{
|
||||
$inputDefinition = parent::getDefaultInputDefinition();
|
||||
$inputDefinition->addOption(
|
||||
new InputOption(
|
||||
'env',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Use environment configuration (defaults to localhost)'
|
||||
)
|
||||
);
|
||||
$inputDefinition->addOption(
|
||||
new InputOption(
|
||||
'lang',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Language to be used (defaults to en)'
|
||||
)
|
||||
);
|
||||
|
||||
return $inputDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return void
|
||||
*/
|
||||
protected function configureIO(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$formatter = $output->getFormatter();
|
||||
$formatter->setStyle('normal', new OutputFormatterStyle('white'));
|
||||
$formatter->setStyle('yellow', new OutputFormatterStyle('yellow', null, ['bold']));
|
||||
$formatter->setStyle('red', new OutputFormatterStyle('red', null, ['bold']));
|
||||
$formatter->setStyle('cyan', new OutputFormatterStyle('cyan', null, ['bold']));
|
||||
$formatter->setStyle('green', new OutputFormatterStyle('green', null, ['bold']));
|
||||
$formatter->setStyle('magenta', new OutputFormatterStyle('magenta', null, ['bold']));
|
||||
$formatter->setStyle('white', new OutputFormatterStyle('white', null, ['bold']));
|
||||
|
||||
parent::configureIO($input, $output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Application\CommandLoader;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
|
||||
use Symfony\Component\Console\Exception\CommandNotFoundException;
|
||||
|
||||
/**
|
||||
* Class GpmApplication
|
||||
* @package Grav\Console\Application
|
||||
*/
|
||||
class PluginCommandLoader implements CommandLoaderInterface
|
||||
{
|
||||
/** @var array */
|
||||
private $commands;
|
||||
|
||||
/**
|
||||
* PluginCommandLoader constructor.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->commands = [];
|
||||
|
||||
try {
|
||||
$path = "plugins://{$name}/cli";
|
||||
$pattern = '([A-Z]\w+Command\.php)';
|
||||
|
||||
$commands = is_dir($path) ? Folder::all($path, ['compare' => 'Filename', 'pattern' => '/' . $pattern . '$/usm', 'levels' => 1]) : [];
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException("Failed to load console commands for plugin {$name}");
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
foreach ($commands as $command_path) {
|
||||
$full_path = $locator->findResource("plugins://{$name}/cli/{$command_path}");
|
||||
require_once $full_path;
|
||||
|
||||
$command_class = 'Grav\Plugin\Console\\' . preg_replace('/.php$/', '', $command_path);
|
||||
if (class_exists($command_class)) {
|
||||
$command = new $command_class();
|
||||
if ($command instanceof Command) {
|
||||
$this->commands[$command->getName()] = $command;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return Command
|
||||
*/
|
||||
public function get($name): Command
|
||||
{
|
||||
$command = $this->commands[$name] ?? null;
|
||||
if (null === $command) {
|
||||
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name): bool
|
||||
{
|
||||
return isset($this->commands[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNames(): array
|
||||
{
|
||||
return array_keys($this->commands);
|
||||
}
|
||||
}
|
||||
42
system/src/Grav/Console/Application/GpmApplication.php
Normal file
42
system/src/Grav/Console/Application/GpmApplication.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Application;
|
||||
|
||||
use Grav\Console\Gpm\DirectInstallCommand;
|
||||
use Grav\Console\Gpm\IndexCommand;
|
||||
use Grav\Console\Gpm\InfoCommand;
|
||||
use Grav\Console\Gpm\InstallCommand;
|
||||
use Grav\Console\Gpm\SelfupgradeCommand;
|
||||
use Grav\Console\Gpm\UninstallCommand;
|
||||
use Grav\Console\Gpm\UpdateCommand;
|
||||
use Grav\Console\Gpm\VersionCommand;
|
||||
|
||||
/**
|
||||
* Class GpmApplication
|
||||
* @package Grav\Console\Application
|
||||
*/
|
||||
class GpmApplication extends Application
|
||||
{
|
||||
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
|
||||
{
|
||||
parent::__construct($name, $version);
|
||||
|
||||
$this->addCommands([
|
||||
new IndexCommand(),
|
||||
new VersionCommand(),
|
||||
new InfoCommand(),
|
||||
new InstallCommand(),
|
||||
new UninstallCommand(),
|
||||
new UpdateCommand(),
|
||||
new SelfupgradeCommand(),
|
||||
new DirectInstallCommand(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
52
system/src/Grav/Console/Application/GravApplication.php
Normal file
52
system/src/Grav/Console/Application/GravApplication.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Application;
|
||||
|
||||
use Grav\Console\Cli\BackupCommand;
|
||||
use Grav\Console\Cli\CleanCommand;
|
||||
use Grav\Console\Cli\ClearCacheCommand;
|
||||
use Grav\Console\Cli\ComposerCommand;
|
||||
use Grav\Console\Cli\InstallCommand;
|
||||
use Grav\Console\Cli\LogViewerCommand;
|
||||
use Grav\Console\Cli\NewProjectCommand;
|
||||
use Grav\Console\Cli\PageSystemValidatorCommand;
|
||||
use Grav\Console\Cli\SandboxCommand;
|
||||
use Grav\Console\Cli\SchedulerCommand;
|
||||
use Grav\Console\Cli\SecurityCommand;
|
||||
use Grav\Console\Cli\ServerCommand;
|
||||
use Grav\Console\Cli\YamlLinterCommand;
|
||||
|
||||
/**
|
||||
* Class GravApplication
|
||||
* @package Grav\Console\Application
|
||||
*/
|
||||
class GravApplication extends Application
|
||||
{
|
||||
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
|
||||
{
|
||||
parent::__construct($name, $version);
|
||||
|
||||
$this->addCommands([
|
||||
new InstallCommand(),
|
||||
new ComposerCommand(),
|
||||
new SandboxCommand(),
|
||||
new CleanCommand(),
|
||||
new ClearCacheCommand(),
|
||||
new BackupCommand(),
|
||||
new NewProjectCommand(),
|
||||
new SchedulerCommand(),
|
||||
new SecurityCommand(),
|
||||
new LogViewerCommand(),
|
||||
new YamlLinterCommand(),
|
||||
new ServerCommand(),
|
||||
new PageSystemValidatorCommand(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
116
system/src/Grav/Console/Application/PluginApplication.php
Normal file
116
system/src/Grav/Console/Application/PluginApplication.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Application;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Plugins;
|
||||
use Grav\Console\Application\CommandLoader\PluginCommandLoader;
|
||||
use Grav\Console\Plugin\PluginListCommand;
|
||||
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class PluginApplication
|
||||
* @package Grav\Console\Application
|
||||
*/
|
||||
class PluginApplication extends Application
|
||||
{
|
||||
/** @var string|null */
|
||||
protected $pluginName;
|
||||
|
||||
/**
|
||||
* PluginApplication constructor.
|
||||
* @param string $name
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
|
||||
{
|
||||
parent::__construct($name, $version);
|
||||
|
||||
$this->addCommands([
|
||||
new PluginListCommand(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pluginName
|
||||
* @return void
|
||||
*/
|
||||
public function setPluginName(string $pluginName): void
|
||||
{
|
||||
$this->pluginName = $pluginName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName(): string
|
||||
{
|
||||
return $this->pluginName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface|null $input
|
||||
* @param OutputInterface|null $output
|
||||
* @return int
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function run(InputInterface $input = null, OutputInterface $output = null): int
|
||||
{
|
||||
if (null === $input) {
|
||||
$argv = $_SERVER['argv'] ?? [];
|
||||
|
||||
$bin = array_shift($argv);
|
||||
$this->pluginName = array_shift($argv);
|
||||
$argv = array_merge([$bin], $argv);
|
||||
|
||||
$input = new ArgvInput($argv);
|
||||
}
|
||||
|
||||
return parent::run($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function init(): void
|
||||
{
|
||||
if ($this->initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::init();
|
||||
|
||||
if (null === $this->pluginName) {
|
||||
$this->setDefaultCommand('plugins:list');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
$grav->initializeCli();
|
||||
|
||||
/** @var Plugins $plugins */
|
||||
$plugins = $grav['plugins'];
|
||||
|
||||
$plugin = $this->pluginName ? $plugins::get($this->pluginName) : null;
|
||||
if (null === $plugin) {
|
||||
throw new NamespaceNotFoundException("Plugin \"{$this->pluginName}\" is not installed.");
|
||||
}
|
||||
if (!$plugin->enabled) {
|
||||
throw new NamespaceNotFoundException("Plugin \"{$this->pluginName}\" is not enabled.");
|
||||
}
|
||||
|
||||
$this->setCommandLoader(new PluginCommandLoader($this->pluginName));
|
||||
}
|
||||
}
|
||||
@@ -1,83 +1,133 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Backup\Backups;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Backup\ZipBackup;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use RocketTheme\Toolbox\File\JsonFile;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use ZipArchive;
|
||||
use function count;
|
||||
|
||||
class BackupCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class BackupCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class BackupCommand extends GravCommand
|
||||
{
|
||||
/** @var string $source */
|
||||
protected $source;
|
||||
|
||||
/** @var ProgressBar $progress */
|
||||
protected $progress;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("backup")
|
||||
->setName('backup')
|
||||
->addArgument(
|
||||
'destination',
|
||||
'id',
|
||||
InputArgument::OPTIONAL,
|
||||
'Where to store the backup (/backup is default)'
|
||||
|
||||
'The ID of the backup profile to perform without prompting'
|
||||
)
|
||||
->setDescription("Creates a backup of the Grav instance")
|
||||
->setHelp('The <info>backup</info> creates a zipped backup. Optionally can be saved in a different destination.');
|
||||
->setDescription('Creates a backup of the Grav instance')
|
||||
->setHelp('The <info>backup</info> creates a zipped backup.');
|
||||
|
||||
$this->source = getcwd();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->progress = new ProgressBar($this->output);
|
||||
$this->progress->setFormat('Archiving <cyan>%current%</cyan> files [<green>%bar%</green>] %elapsed:6s% %memory:6s%');
|
||||
$this->initializeGrav();
|
||||
|
||||
Grav::instance()['config']->init();
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$destination = ($this->input->getArgument('destination')) ? $this->input->getArgument('destination') : null;
|
||||
$log = JsonFile::instance(Grav::instance()['locator']->findResource("log://backup.log", true, true));
|
||||
$backup = ZipBackup::backup($destination, [$this, 'output']);
|
||||
$io->title('Grav Backup');
|
||||
|
||||
$log->content([
|
||||
'time' => time(),
|
||||
'location' => $backup
|
||||
]);
|
||||
$log->save();
|
||||
if (!class_exists(ZipArchive::class)) {
|
||||
$io->error('php-zip extension needs to be enabled!');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('');
|
||||
ProgressBar::setFormatDefinition('zip', 'Archiving <cyan>%current%</cyan> files [<green>%bar%</green>] <white>%percent:3s%%</white> %elapsed:6s% <yellow>%message%</yellow>');
|
||||
|
||||
$this->progress = new ProgressBar($this->output, 100);
|
||||
$this->progress->setFormat('zip');
|
||||
|
||||
|
||||
/** @var Backups $backups */
|
||||
$backups = Grav::instance()['backups'];
|
||||
$backups_list = $backups::getBackupProfiles();
|
||||
$backups_names = $backups->getBackupNames();
|
||||
|
||||
$id = null;
|
||||
|
||||
$inline_id = $input->getArgument('id');
|
||||
if (null !== $inline_id && is_numeric($inline_id)) {
|
||||
$id = $inline_id;
|
||||
}
|
||||
|
||||
if (null === $id) {
|
||||
if (count($backups_list) > 1) {
|
||||
$question = new ChoiceQuestion(
|
||||
'Choose a backup?',
|
||||
$backups_names,
|
||||
0
|
||||
);
|
||||
$question->setErrorMessage('Option %s is invalid.');
|
||||
$backup_name = $io->askQuestion($question);
|
||||
$id = array_search($backup_name, $backups_names, true);
|
||||
|
||||
$io->newLine();
|
||||
$io->note('Selected backup: ' . $backup_name);
|
||||
} else {
|
||||
$id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$backup = $backups::backup($id, function($args) { $this->outputProgress($args); });
|
||||
|
||||
$io->newline(2);
|
||||
$io->success('Backup Successfully Created: ' . $backup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @param array $args
|
||||
* @return void
|
||||
*/
|
||||
public function output($args)
|
||||
public function outputProgress(array $args): void
|
||||
{
|
||||
switch ($args['type']) {
|
||||
case 'count':
|
||||
$steps = $args['steps'];
|
||||
$freq = (int)($steps > 100 ? round($steps / 100) : $steps);
|
||||
$this->progress->setMaxSteps($steps);
|
||||
$this->progress->setRedrawFrequency($freq);
|
||||
$this->progress->setMessage('Adding files...');
|
||||
break;
|
||||
case 'message':
|
||||
$this->output->writeln($args['message']);
|
||||
$this->progress->setMessage($args['message']);
|
||||
$this->progress->display();
|
||||
break;
|
||||
case 'progress':
|
||||
if ($args['complete']) {
|
||||
if (isset($args['complete']) && $args['complete']) {
|
||||
$this->progress->finish();
|
||||
} else {
|
||||
$this->progress->advance();
|
||||
@@ -85,6 +135,4 @@ class BackupCommand extends ConsoleCommand
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
@@ -13,18 +14,20 @@ use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Class CleanCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class CleanCommand extends Command
|
||||
{
|
||||
/* @var InputInterface $output */
|
||||
/** @var InputInterface */
|
||||
protected $input;
|
||||
/** @var SymfonyStyle */
|
||||
protected $io;
|
||||
|
||||
/* @var OutputInterface $output */
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $paths_to_remove = [
|
||||
'codeception.yml',
|
||||
'tests/',
|
||||
@@ -61,6 +64,11 @@ class CleanCommand extends Command
|
||||
'user/plugins/email/vendor/swiftmailer/swiftmailer/doc',
|
||||
'user/themes/antimatter/.sass-cache',
|
||||
'vendor/antoligy/dom-string-iterators/composer.json',
|
||||
'vendor/composer/ca-bundle/composer.json',
|
||||
'vendor/composer/ca-bundle/phpstan.neon.dist',
|
||||
'vendor/composer/semver/CHANGELOG.md',
|
||||
'vendor/composer/semver/composer.json',
|
||||
'vendor/composer/semver/phpstan.neon.dist',
|
||||
'vendor/doctrine/cache/.travis.yml',
|
||||
'vendor/doctrine/cache/build.properties',
|
||||
'vendor/doctrine/cache/build.xml',
|
||||
@@ -70,16 +78,35 @@ class CleanCommand extends Command
|
||||
'vendor/doctrine/cache/.gitignore',
|
||||
'vendor/doctrine/cache/.git',
|
||||
'vendor/doctrine/cache/tests',
|
||||
'vendor/doctrine/cache/UPGRADE.md',
|
||||
'vendor/doctrine/collections/docs',
|
||||
'vendor/doctrine/collections/.doctrine-project.json',
|
||||
'vendor/doctrine/collections/CONTRIBUTING.md',
|
||||
'vendor/doctrine/collections/psalm.xml.dist',
|
||||
'vendor/doctrine/collections/composer.json',
|
||||
'vendor/doctrine/collections/phpunit.xml.dist',
|
||||
'vendor/doctrine/collections/tests',
|
||||
'vendor/donatj/phpuseragentparser/.git',
|
||||
'vendor/donatj/phpuseragentparser/.github',
|
||||
'vendor/donatj/phpuseragentparser/.gitignore',
|
||||
'vendor/donatj/phpuseragentparser/.editorconfig',
|
||||
'vendor/donatj/phpuseragentparser/.travis.yml',
|
||||
'vendor/donatj/phpuseragentparser/composer.json',
|
||||
'vendor/donatj/phpuseragentparser/phpunit.xml.dist',
|
||||
'vendor/donatj/phpuseragentparser/Tests',
|
||||
'vendor/donatj/phpuseragentparser/tests',
|
||||
'vendor/donatj/phpuseragentparser/Tools',
|
||||
'vendor/donatj/phpuseragentparser/CONTRIBUTING.md',
|
||||
'vendor/donatj/phpuseragentparser/Makefile',
|
||||
'vendor/donatj/phpuseragentparser/.mddoc.xml',
|
||||
'vendor/dragonmantank/cron-expression/.editorconfig',
|
||||
'vendor/dragonmantank/cron-expression/composer.json',
|
||||
'vendor/dragonmantank/cron-expression/tests',
|
||||
'vendor/dragonmantank/cron-expression/CHANGELOG.md',
|
||||
'vendor/enshrined/svg-sanitize/tests',
|
||||
'vendor/enshrined/svg-sanitize/.gitignore',
|
||||
'vendor/enshrined/svg-sanitize/.travis.yml',
|
||||
'vendor/enshrined/svg-sanitize/composer.json',
|
||||
'vendor/enshrined/svg-sanitize/phpunit.xml',
|
||||
'vendor/erusev/parsedown/composer.json',
|
||||
'vendor/erusev/parsedown/phpunit.xml.dist',
|
||||
'vendor/erusev/parsedown/.travis.yml',
|
||||
@@ -95,12 +122,20 @@ class CleanCommand extends Command
|
||||
'vendor/filp/whoops/examples',
|
||||
'vendor/filp/whoops/tests',
|
||||
'vendor/filp/whoops/.git',
|
||||
'vendor/filp/whoops/.github',
|
||||
'vendor/filp/whoops/.gitignore',
|
||||
'vendor/filp/whoops/.scrutinizer.yml',
|
||||
'vendor/filp/whoops/.travis.yml',
|
||||
'vendor/filp/whoops/phpunit.xml.dist',
|
||||
'vendor/filp/whoops/CHANGELOG.md',
|
||||
'vendor/gregwar/image/Gregwar/Image/composer.json',
|
||||
'vendor/gregwar/image/Gregwar/Image/phpunit.xml',
|
||||
'vendor/gregwar/image/Gregwar/Image/phpunit.xml.dist',
|
||||
'vendor/gregwar/image/Gregwar/Image/Makefile',
|
||||
'vendor/gregwar/image/Gregwar/Image/.editorconfig',
|
||||
'vendor/gregwar/image/Gregwar/Image/.php_cs',
|
||||
'vendor/gregwar/image/Gregwar/Image/.styleci.yml',
|
||||
'vendor/gregwar/image/Gregwar/Image/.travis.yml',
|
||||
'vendor/gregwar/image/Gregwar/Image/.gitignore',
|
||||
'vendor/gregwar/image/Gregwar/Image/.git',
|
||||
'vendor/gregwar/image/Gregwar/Image/doc',
|
||||
@@ -108,22 +143,30 @@ class CleanCommand extends Command
|
||||
'vendor/gregwar/image/Gregwar/Image/tests',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/composer.json',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/phpunit.xml',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/.travis.yml',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/.gitignore',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/.git',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/demo',
|
||||
'vendor/gregwar/cache/Gregwar/Cache/tests',
|
||||
'vendor/ircmaxell/password-compat/composer.json',
|
||||
'vendor/ircmaxell/password-compat/phpunit.xml.dist',
|
||||
'vendor/ircmaxell/password-compat/version-test.php',
|
||||
'vendor/ircmaxell/password-compat/.travis.yml',
|
||||
'vendor/ircmaxell/password-compat/test',
|
||||
'vendor/guzzlehttp/psr7/composer.json',
|
||||
'vendor/guzzlehttp/psr7/.editorconfig',
|
||||
'vendor/guzzlehttp/psr7/CHANGELOG.md',
|
||||
'vendor/itsgoingd/clockwork/.gitattributes',
|
||||
'vendor/itsgoingd/clockwork/CHANGELOG.md',
|
||||
'vendor/itsgoingd/clockwork/composer.json',
|
||||
'vendor/league/climate/composer.json',
|
||||
'vendor/league/climate/CHANGELOG.md',
|
||||
'vendor/league/climate/CONTRIBUTING.md',
|
||||
'vendor/league/climate/Dockerfile',
|
||||
'vendor/league/climate/CODE_OF_CONDUCT.md',
|
||||
'vendor/matthiasmullie/minify/.github',
|
||||
'vendor/matthiasmullie/minify/bin',
|
||||
'vendor/matthiasmullie/minify/composer.json',
|
||||
'vendor/matthiasmullie/minify/docker-composer.yml',
|
||||
'vendor/matthiasmullie/minify/docker-compose.yml',
|
||||
'vendor/matthiasmullie/minify/Dockerfile',
|
||||
'vendor/matthiasmullie/minify/CONTRIBUTING.md',
|
||||
'vendor/matthiasmullie/path-converter/composer.json',
|
||||
'vendor/maximebf/debugbar/.github',
|
||||
'vendor/maximebf/debugbar/bower.json',
|
||||
'vendor/maximebf/debugbar/composer.json',
|
||||
'vendor/maximebf/debugbar/.bowerrc',
|
||||
@@ -140,119 +183,210 @@ class CleanCommand extends Command
|
||||
'vendor/miljar/php-exif/phpunit.xml.dist',
|
||||
'vendor/miljar/php-exif/Resources',
|
||||
'vendor/miljar/php-exif/tests',
|
||||
'vendor/miljar/php-exif/CHANGELOG.rst',
|
||||
'vendor/monolog/monolog/composer.json',
|
||||
'vendor/monolog/monolog/doc',
|
||||
'vendor/monolog/monolog/phpunit.xml.dist',
|
||||
'vendor/monolog/monolog/.php_cs',
|
||||
'vendor/monolog/monolog/tests',
|
||||
'vendor/monolog/monolog/CHANGELOG.md',
|
||||
'vendor/monolog/monolog/phpstan.neon.dist',
|
||||
'vendor/nyholm/psr7/composer.json',
|
||||
'vendor/nyholm/psr7/phpstan.neon.dist',
|
||||
'vendor/nyholm/psr7/CHANGELOG.md',
|
||||
'vendor/nyholm/psr7/psalm.xml',
|
||||
'vendor/nyholm/psr7-server/.github',
|
||||
'vendor/nyholm/psr7-server/composer.json',
|
||||
'vendor/nyholm/psr7-server/CHANGELOG.md',
|
||||
'vendor/phive/twig-extensions-deferred/.gitignore',
|
||||
'vendor/phive/twig-extensions-deferred/.travis.yml',
|
||||
'vendor/phive/twig-extensions-deferred/composer.json',
|
||||
'vendor/phive/twig-extensions-deferred/phpunit.xml.dist',
|
||||
'vendor/phive/twig-extensions-deferred/tests',
|
||||
'vendor/php-http/message-factory/composer.json',
|
||||
'vendor/php-http/message-factory/puli.json',
|
||||
'vendor/php-http/message-factory/CHANGELOG.md',
|
||||
'vendor/pimple/pimple/.gitignore',
|
||||
'vendor/pimple/pimple/.travis.yml',
|
||||
'vendor/pimple/pimple/composer.json',
|
||||
'vendor/pimple/pimple/ext',
|
||||
'vendor/pimple/pimple/phpunit.xml.dist',
|
||||
'vendor/pimple/pimple/src/Pimple/Tests',
|
||||
'vendor/pimple/pimple/.php_cs.dist',
|
||||
'vendor/pimple/pimple/CHANGELOG',
|
||||
'vendor/psr/cache/CHANGELOG.md',
|
||||
'vendor/psr/cache/composer.json',
|
||||
'vendor/psr/container/composer.json',
|
||||
'vendor/psr/container/.gitignore',
|
||||
'vendor/psr/http-factory/.gitignore',
|
||||
'vendor/psr/http-factory/.pullapprove.yml',
|
||||
'vendor/psr/http-factory/composer.json',
|
||||
'vendor/psr/http-message/composer.json',
|
||||
'vendor/psr/http-message/CHANGELOG.md',
|
||||
'vendor/psr/http-server-handler/composer.json',
|
||||
'vendor/psr/http-server-middleware/composer.json',
|
||||
'vendor/psr/simple-cache/.editorconfig',
|
||||
'vendor/psr/simple-cache/composer.json',
|
||||
'vendor/psr/log/composer.json',
|
||||
'vendor/psr/log/.gitignore',
|
||||
'vendor/ralouphie/getallheaders/.gitignore',
|
||||
'vendor/ralouphie/getallheaders/.travis.yml',
|
||||
'vendor/ralouphie/getallheaders/composer.json',
|
||||
'vendor/ralouphie/getallheaders/phpunit.xml',
|
||||
'vendor/ralouphie/getallheaders/tests/',
|
||||
'vendor/rockettheme/toolbox/.git',
|
||||
'vendor/rockettheme/toolbox/.gitignore',
|
||||
'vendor/rockettheme/toolbox/.scrutinizer.yml',
|
||||
'vendor/rockettheme/toolbox/.travis.yml',
|
||||
'vendor/rockettheme/toolbox/composer.json',
|
||||
'vendor/rockettheme/toolbox/phpunit.xml',
|
||||
'vendor/rockettheme/toolbox/CHANGELOG.md',
|
||||
'vendor/rockettheme/toolbox/Blueprints/tests',
|
||||
'vendor/rockettheme/toolbox/ResourceLocator/tests',
|
||||
'vendor/rockettheme/toolbox/Session/tests',
|
||||
'vendor/rockettheme/toolbox/tests',
|
||||
'vendor/seld/cli-prompt/composer.json',
|
||||
'vendor/seld/cli-prompt/.gitignore',
|
||||
'vendor/seld/cli-prompt/.github',
|
||||
'vendor/seld/cli-prompt/phpstan.neon.dist',
|
||||
'vendor/symfony/console/composer.json',
|
||||
'vendor/symfony/console/phpunit.xml.dist',
|
||||
'vendor/symfony/console/.gitignore',
|
||||
'vendor/symfony/console/.git',
|
||||
'vendor/symfony/console/Tester',
|
||||
'vendor/symfony/console/Tests',
|
||||
'vendor/symfony/debug/.gitignore',
|
||||
'vendor/symfony/debug/.git',
|
||||
'vendor/symfony/debug/phpunit.xml.dist',
|
||||
'vendor/symfony/debug/composer.json',
|
||||
'vendor/symfony/debug/Tests',
|
||||
'vendor/symfony/debug/Resources',
|
||||
'vendor/symfony/console/CHANGELOG.md',
|
||||
'vendor/symfony/contracts/Cache/.gitignore',
|
||||
'vendor/symfony/contracts/Cache/composer.json',
|
||||
'vendor/symfony/contracts/EventDispatcher/.gitignore',
|
||||
'vendor/symfony/contracts/EventDispatcher/composer.json',
|
||||
'vendor/symfony/contracts/HttpClient/.gitignore',
|
||||
'vendor/symfony/contracts/HttpClient/composer.json',
|
||||
'vendor/symfony/contracts/HttpClient/Test',
|
||||
'vendor/symfony/contracts/Service/.gitignore',
|
||||
'vendor/symfony/contracts/Service/composer.json',
|
||||
'vendor/symfony/contracts/Service/Test',
|
||||
'vendor/symfony/contracts/Tests',
|
||||
'vendor/symfony/contracts/Translation/.gitignore',
|
||||
'vendor/symfony/contracts/Translation/composer.json',
|
||||
'vendor/symfony/contracts/Translation/Test',
|
||||
'vendor/symfony/contracts/.gitignore',
|
||||
'vendor/symfony/contracts/composer.json',
|
||||
'vendor/symfony/contracts/phpunit.xml.dist',
|
||||
'vendor/symfony/event-dispatcher/.git',
|
||||
'vendor/symfony/event-dispatcher/.gitignore',
|
||||
'vendor/symfony/event-dispatcher/composer.json',
|
||||
'vendor/symfony/event-dispatcher/phpunit.xml.dist',
|
||||
'vendor/symfony/event-dispatcher/Tests',
|
||||
'vendor/symfony/event-dispatcher/CHANGELOG.md',
|
||||
'vendor/symfony/http-client/CHANGELOG.md',
|
||||
'vendor/symfony/http-client/composer.json',
|
||||
'vendor/symfony/polyfill-ctype/composer.json',
|
||||
'vendor/symfony/polyfill-iconv/.git',
|
||||
'vendor/symfony/polyfill-iconv/.gitignore',
|
||||
'vendor/symfony/polyfill-iconv/composer.json',
|
||||
'vendor/symfony/polyfill-mbstring/.git',
|
||||
'vendor/symfony/polyfill-mbstring/.gitignore',
|
||||
'vendor/symfony/polyfill-mbstring/composer.json',
|
||||
'vendor/symfony/polyfill-php72/composer.json',
|
||||
'vendor/symfony/polyfill-php73/composer.json',
|
||||
'vendor/symfony/process/.gitignore',
|
||||
'vendor/symfony/process/composer.json',
|
||||
'vendor/symfony/process/phpunit.xml.dist',
|
||||
'vendor/symfony/process/Tests',
|
||||
'vendor/symfony/process/CHANGELOG.md',
|
||||
'vendor/symfony/var-dumper/.git',
|
||||
'vendor/symfony/var-dumper/.gitignore',
|
||||
'vendor/symfony/var-dumper/composer.json',
|
||||
'vendor/symfony/var-dumper/phpunit.xml.dist',
|
||||
'vendor/symfony/var-dumper/Test',
|
||||
'vendor/symfony/var-dumper/Tests',
|
||||
'vendor/symfony/var-dumper/CHANGELOG.md',
|
||||
'vendor/symfony/yaml/composer.json',
|
||||
'vendor/symfony/yaml/phpunit.xml.dist',
|
||||
'vendor/symfony/yaml/.gitignore',
|
||||
'vendor/symfony/yaml/.git',
|
||||
'vendor/symfony/yaml/Tests',
|
||||
'vendor/symfony/yaml/CHANGELOG.md',
|
||||
'vendor/twig/twig/.editorconfig',
|
||||
'vendor/twig/twig/.php_cs.dist',
|
||||
'vendor/twig/twig/.travis.yml',
|
||||
'vendor/twig/twig/.gitignore',
|
||||
'vendor/twig/twig/.git',
|
||||
'vendor/twig/twig/.github',
|
||||
'vendor/twig/twig/composer.json',
|
||||
'vendor/twig/twig/phpunit.xml.dist',
|
||||
'vendor/twig/twig/doc',
|
||||
'vendor/twig/twig/ext',
|
||||
'vendor/twig/twig/test',
|
||||
'vendor/twig/twig/.gitattributes',
|
||||
'vendor/twig/twig/CHANGELOG',
|
||||
'vendor/twig/twig/drupal_test.sh',
|
||||
'vendor/willdurand/negotiation/.gitignore',
|
||||
'vendor/willdurand/negotiation/.travis.yml',
|
||||
'vendor/willdurand/negotiation/appveyor.yml',
|
||||
'vendor/willdurand/negotiation/composer.json',
|
||||
'vendor/willdurand/negotiation/phpunit.xml.dist',
|
||||
'vendor/willdurand/negotiation/tests',
|
||||
'vendor/willdurand/negotiation/CONTRIBUTING.md',
|
||||
'user/config/security.yaml',
|
||||
'cache/compiled/',
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("clean")
|
||||
->setDescription("Handles cleaning chores for Grav distribution")
|
||||
->setName('clean')
|
||||
->setDescription('Handles cleaning chores for Grav distribution')
|
||||
->setHelp('The <info>clean</info> clean extraneous folders and data');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->setupConsole($input, $output);
|
||||
|
||||
$this->cleanPaths();
|
||||
return $this->cleanPaths() ? 0 : 1;
|
||||
}
|
||||
|
||||
private function cleanPaths()
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function cleanPaths(): bool
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<red>DELETING</red>');
|
||||
$success = true;
|
||||
|
||||
$this->io->writeln('');
|
||||
$this->io->writeln('<red>DELETING</red>');
|
||||
$anything = false;
|
||||
foreach ($this->paths_to_remove as $path) {
|
||||
$path = ROOT_DIR . $path;
|
||||
if (is_dir($path) && @Folder::delete($path)) {
|
||||
$anything = true;
|
||||
$this->output->writeln('<red>dir: </red>' . $path);
|
||||
} elseif (is_file($path) && @unlink($path)) {
|
||||
$anything = true;
|
||||
$this->output->writeln('<red>file: </red>' . $path);
|
||||
$path = GRAV_ROOT . DS . $path;
|
||||
try {
|
||||
if (is_dir($path) && Folder::delete($path)) {
|
||||
$anything = true;
|
||||
$this->io->writeln('<red>dir: </red>' . $path);
|
||||
} elseif (is_file($path) && @unlink($path)) {
|
||||
$anything = true;
|
||||
$this->io->writeln('<red>file: </red>' . $path);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$success = false;
|
||||
$this->io->error(sprintf('Failed to delete %s: %s', $path, $e->getMessage()));
|
||||
}
|
||||
}
|
||||
if (!$anything) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<green>Nothing to clean...</green>');
|
||||
$this->io->writeln('');
|
||||
$this->io->writeln('<green>Nothing to clean...</green>');
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,19 +394,19 @@ class CleanCommand extends Command
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return void
|
||||
*/
|
||||
public function setupConsole(InputInterface $input, OutputInterface $output)
|
||||
public function setupConsole(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
|
||||
$this->output->getFormatter()->setStyle('normal', new OutputFormatterStyle('white'));
|
||||
$this->output->getFormatter()->setStyle('yellow', new OutputFormatterStyle('yellow', null, ['bold']));
|
||||
$this->output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, ['bold']));
|
||||
$this->output->getFormatter()->setStyle('cyan', new OutputFormatterStyle('cyan', null, ['bold']));
|
||||
$this->output->getFormatter()->setStyle('green', new OutputFormatterStyle('green', null, ['bold']));
|
||||
$this->output->getFormatter()->setStyle('magenta', new OutputFormatterStyle('magenta', null, ['bold']));
|
||||
$this->output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, ['bold']));
|
||||
$this->io->getFormatter()->setStyle('normal', new OutputFormatterStyle('white'));
|
||||
$this->io->getFormatter()->setStyle('yellow', new OutputFormatterStyle('yellow', null, ['bold']));
|
||||
$this->io->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, ['bold']));
|
||||
$this->io->getFormatter()->setStyle('cyan', new OutputFormatterStyle('cyan', null, ['bold']));
|
||||
$this->io->getFormatter()->setStyle('green', new OutputFormatterStyle('green', null, ['bold']));
|
||||
$this->io->getFormatter()->setStyle('magenta', new OutputFormatterStyle('magenta', null, ['bold']));
|
||||
$this->io->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, ['bold']));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +1,104 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Cache;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class ClearCacheCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class ClearCacheCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class ClearCacheCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('clear-cache')
|
||||
->setAliases(['clearcache'])
|
||||
->setName('cache')
|
||||
->setAliases(['clearcache', 'cache-clear'])
|
||||
->setDescription('Clears Grav cache')
|
||||
->addOption('invalidate', null, InputOption::VALUE_NONE, 'Invalidate cache, but do not remove any files')
|
||||
->addOption('purge', null, InputOption::VALUE_NONE, 'If set purge old caches')
|
||||
->addOption('all', null, InputOption::VALUE_NONE, 'If set will remove all including compiled, twig, doctrine caches')
|
||||
->addOption('assets-only', null, InputOption::VALUE_NONE, 'If set will remove only assets/*')
|
||||
->addOption('images-only', null, InputOption::VALUE_NONE, 'If set will remove only images/*')
|
||||
->addOption('cache-only', null, InputOption::VALUE_NONE, 'If set will remove only cache/*')
|
||||
->addOption('tmp-only', null, InputOption::VALUE_NONE, 'If set will remove only tmp/*')
|
||||
->setHelp('The <info>clear-cache</info> deletes all cache files');
|
||||
|
||||
->setHelp('The <info>cache</info> command allows you to interact with Grav cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
// Old versions of Grav called this command after grav upgrade.
|
||||
// We need make this command to work with older GravCommand instance:
|
||||
if (!method_exists($this, 'initializePlugins')) {
|
||||
Cache::clearCache('all');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->initializePlugins();
|
||||
$this->cleanPaths();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* loops over the array of paths and deletes the files/folders
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function cleanPaths()
|
||||
private function cleanPaths(): void
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<magenta>Clearing cache</magenta>');
|
||||
$this->output->writeln('');
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
if ($this->input->getOption('all')) {
|
||||
$remove = 'all';
|
||||
} elseif ($this->input->getOption('assets-only')) {
|
||||
$remove = 'assets-only';
|
||||
} elseif ($this->input->getOption('images-only')) {
|
||||
$remove = 'images-only';
|
||||
} elseif ($this->input->getOption('cache-only')) {
|
||||
$remove = 'cache-only';
|
||||
} elseif ($this->input->getOption('tmp-only')) {
|
||||
$remove = 'tmp-only';
|
||||
$io->newLine();
|
||||
|
||||
if ($input->getOption('purge')) {
|
||||
$io->writeln('<magenta>Purging old cache</magenta>');
|
||||
$io->newLine();
|
||||
|
||||
$msg = Cache::purgeJob();
|
||||
$io->writeln($msg);
|
||||
} else {
|
||||
$remove = 'standard';
|
||||
}
|
||||
$io->writeln('<magenta>Clearing cache</magenta>');
|
||||
$io->newLine();
|
||||
|
||||
foreach (Cache::clearCache($remove) as $result) {
|
||||
$this->output->writeln($result);
|
||||
if ($input->getOption('all')) {
|
||||
$remove = 'all';
|
||||
} elseif ($input->getOption('assets-only')) {
|
||||
$remove = 'assets-only';
|
||||
} elseif ($input->getOption('images-only')) {
|
||||
$remove = 'images-only';
|
||||
} elseif ($input->getOption('cache-only')) {
|
||||
$remove = 'cache-only';
|
||||
} elseif ($input->getOption('tmp-only')) {
|
||||
$remove = 'tmp-only';
|
||||
} elseif ($input->getOption('invalidate')) {
|
||||
$remove = 'invalidate';
|
||||
} else {
|
||||
$remove = 'standard';
|
||||
}
|
||||
|
||||
foreach (Cache::clearCache($remove) as $result) {
|
||||
$io->writeln($result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class ComposerCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class ComposerCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class ComposerCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
* @return void
|
||||
*/
|
||||
protected $config;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $local_config;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $destination;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $user_path;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("composer")
|
||||
->setName('composer')
|
||||
->addOption(
|
||||
'install',
|
||||
'i',
|
||||
@@ -49,24 +37,28 @@ class ComposerCommand extends ConsoleCommand
|
||||
InputOption::VALUE_NONE,
|
||||
'update the dependencies'
|
||||
)
|
||||
->setDescription("Updates the composer vendor dependencies needed by Grav.")
|
||||
->setDescription('Updates the composer vendor dependencies needed by Grav.')
|
||||
->setHelp('The <info>composer</info> command updates the composer vendor dependencies needed by Grav');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$action = $this->input->getOption('install') ? 'install' : ($this->input->getOption('update') ? 'update' : 'install');
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
if ($this->input->getOption('install')) {
|
||||
$action = $input->getOption('install') ? 'install' : ($input->getOption('update') ? 'update' : 'install');
|
||||
|
||||
if ($input->getOption('install')) {
|
||||
$action = 'install';
|
||||
}
|
||||
|
||||
// Updates composer first
|
||||
$this->output->writeln("\nInstalling vendor dependencies");
|
||||
$this->output->writeln($this->composerUpdate(GRAV_ROOT, $action));
|
||||
}
|
||||
$io->writeln("\nInstalling vendor dependencies");
|
||||
$io->writeln($this->composerUpdate(GRAV_ROOT, $action));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,85 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GravCommand;
|
||||
use Grav\Framework\File\Formatter\JsonFormatter;
|
||||
use Grav\Framework\File\JsonFile;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use function is_array;
|
||||
|
||||
class InstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class InstallCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class InstallCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var array */
|
||||
protected $config;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $local_config;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $destination;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $user_path;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("install")
|
||||
->setName('install')
|
||||
->addOption(
|
||||
'symlink',
|
||||
's',
|
||||
InputOption::VALUE_NONE,
|
||||
'Symlink the required bits'
|
||||
)
|
||||
->addOption(
|
||||
'plugin',
|
||||
'p',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Install plugin (symlink)'
|
||||
)
|
||||
->addOption(
|
||||
'theme',
|
||||
't',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Install theme (symlink)'
|
||||
)
|
||||
->addArgument(
|
||||
'destination',
|
||||
InputArgument::OPTIONAL,
|
||||
'Where to install the required bits (default to current project)'
|
||||
)
|
||||
->setDescription("Installs the dependencies needed by Grav. Optionally can create symbolic links")
|
||||
->setDescription('Installs the dependencies needed by Grav. Optionally can create symbolic links')
|
||||
->setHelp('The <info>install</info> command installs the dependencies needed by Grav. Optionally can create symbolic links');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$dependencies_file = '.dependencies';
|
||||
$this->destination = ($this->input->getArgument('destination')) ? $this->input->getArgument('destination') : ROOT_DIR;
|
||||
$this->destination = $input->getArgument('destination') ?: GRAV_WEBROOT;
|
||||
|
||||
// fix trailing slash
|
||||
$this->destination = rtrim($this->destination, DS) . DS;
|
||||
$this->user_path = $this->destination . USER_PATH;
|
||||
$this->user_path = $this->destination . GRAV_USER_PATH . DS;
|
||||
if ($local_config_file = $this->loadLocalConfig()) {
|
||||
$this->output->writeln('Read local config from <cyan>' . $local_config_file . '</cyan>');
|
||||
$io->writeln('Read local config from <cyan>' . $local_config_file . '</cyan>');
|
||||
}
|
||||
|
||||
// Look for dependencies file in ROOT and USER dir
|
||||
@@ -75,112 +88,215 @@ class InstallCommand extends ConsoleCommand
|
||||
} elseif (file_exists($this->destination . $dependencies_file)) {
|
||||
$file = YamlFile::instance($this->destination . $dependencies_file);
|
||||
} else {
|
||||
$this->output->writeln('<red>ERROR</red> Missing .dependencies file in <cyan>user/</cyan> folder');
|
||||
if ($this->input->getArgument('destination')) {
|
||||
$this->output->writeln('<yellow>HINT</yellow> <info>Are you trying to install a plugin or a theme? Make sure you use <cyan>bin/gpm install <something></cyan>, not <cyan>bin/grav install</cyan>. This command is only used to install Grav skeletons.');
|
||||
$io->writeln('<red>ERROR</red> Missing .dependencies file in <cyan>user/</cyan> folder');
|
||||
if ($input->getArgument('destination')) {
|
||||
$io->writeln('<yellow>HINT</yellow> <info>Are you trying to install a plugin or a theme? Make sure you use <cyan>bin/gpm install <something></cyan>, not <cyan>bin/grav install</cyan>. This command is only used to install Grav skeletons.');
|
||||
} else {
|
||||
$this->output->writeln('<yellow>HINT</yellow> <info>Are you trying to install Grav? Grav is already installed. You need to run this command only if you download a skeleton from GitHub directly.');
|
||||
$io->writeln('<yellow>HINT</yellow> <info>Are you trying to install Grav? Grav is already installed. You need to run this command only if you download a skeleton from GitHub directly.');
|
||||
}
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->config = $file->content();
|
||||
$file->free();
|
||||
|
||||
// If yaml config, process
|
||||
if ($this->config) {
|
||||
if (!$this->input->getOption('symlink')) {
|
||||
// Updates composer first
|
||||
$this->output->writeln("\nInstalling vendor dependencies");
|
||||
$this->output->writeln($this->composerUpdate(GRAV_ROOT, 'install'));
|
||||
// If no config, fail.
|
||||
if (!$this->config) {
|
||||
$io->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
|
||||
|
||||
$this->gitclone();
|
||||
} else {
|
||||
$this->symlink();
|
||||
}
|
||||
} else {
|
||||
$this->output->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$plugin = $input->getOption('plugin');
|
||||
$theme = $input->getOption('theme');
|
||||
$name = $plugin ?? $theme;
|
||||
$symlink = $name || $input->getOption('symlink');
|
||||
|
||||
if (!$symlink) {
|
||||
// Updates composer first
|
||||
$io->writeln("\nInstalling vendor dependencies");
|
||||
$io->writeln($this->composerUpdate(GRAV_ROOT, 'install'));
|
||||
|
||||
$error = $this->gitclone();
|
||||
} else {
|
||||
$type = $name ? ($plugin ? 'plugin' : 'theme') : null;
|
||||
|
||||
$error = $this->symlink($name, $type);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones from Git
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function gitclone()
|
||||
private function gitclone(): int
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<green>Cloning Bits</green>');
|
||||
$this->output->writeln('============');
|
||||
$this->output->writeln('');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln('<green>Cloning Bits</green>');
|
||||
$io->writeln('============');
|
||||
$io->newLine();
|
||||
|
||||
$error = 0;
|
||||
$this->destination = rtrim($this->destination, DS);
|
||||
foreach ($this->config['git'] as $repo => $data) {
|
||||
$this->destination = rtrim($this->destination, DS);
|
||||
$path = $this->destination . DS . $data['path'];
|
||||
if (!file_exists($path)) {
|
||||
exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' --depth 1 ' . $data['url'] . ' ' . $data['path'], $output, $return);
|
||||
|
||||
if (!$return) {
|
||||
$this->output->writeln('<green>SUCCESS</green> cloned <magenta>' . $data['url'] . '</magenta> -> <cyan>' . $path . '</cyan>');
|
||||
$io->writeln('<green>SUCCESS</green> cloned <magenta>' . $data['url'] . '</magenta> -> <cyan>' . $path . '</cyan>');
|
||||
} else {
|
||||
$this->output->writeln('<red>ERROR</red> cloning <magenta>' . $data['url']);
|
||||
|
||||
$io->writeln('<red>ERROR</red> cloning <magenta>' . $data['url']);
|
||||
$error = 1;
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
} else {
|
||||
$this->output->writeln('<red>' . $path . ' already exists, skipping...</red>');
|
||||
$this->output->writeln('');
|
||||
$io->writeln('<yellow>' . $path . ' already exists, skipping...</yellow>');
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Symlinks
|
||||
*
|
||||
* @param string|null $name
|
||||
* @param string|null $type
|
||||
* @return int
|
||||
*/
|
||||
private function symlink()
|
||||
private function symlink(string $name = null, string $type = null): int
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<green>Symlinking Bits</green>');
|
||||
$this->output->writeln('===============');
|
||||
$this->output->writeln('');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln('<green>Symlinking Bits</green>');
|
||||
$io->writeln('===============');
|
||||
$io->newLine();
|
||||
|
||||
if (!$this->local_config) {
|
||||
$this->output->writeln('<red>No local configuration available, aborting...</red>');
|
||||
$this->output->writeln('');
|
||||
return;
|
||||
$io->writeln('<red>No local configuration available, aborting...</red>');
|
||||
$io->newLine();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
exec('cd ' . $this->destination);
|
||||
foreach ($this->config['links'] as $repo => $data) {
|
||||
$repos = (array) $this->local_config[$data['scm'] . '_repos'];
|
||||
$from = false;
|
||||
$to = $this->destination . $data['path'];
|
||||
$error = 0;
|
||||
$this->destination = rtrim($this->destination, DS);
|
||||
|
||||
foreach ($repos as $repo) {
|
||||
$path = $repo . $data['src'];
|
||||
if (file_exists($path)) {
|
||||
$from = $path;
|
||||
if ($name) {
|
||||
$src = "grav-{$type}-{$name}";
|
||||
$links = [
|
||||
$name => [
|
||||
'scm' => 'github', // TODO: make configurable
|
||||
'src' => $src,
|
||||
'path' => "user/{$type}s/{$name}"
|
||||
]
|
||||
];
|
||||
} else {
|
||||
$links = $this->config['links'];
|
||||
}
|
||||
|
||||
foreach ($links as $name => $data) {
|
||||
$scm = $data['scm'] ?? null;
|
||||
$src = $data['src'] ?? null;
|
||||
$path = $data['path'] ?? null;
|
||||
if (!isset($scm, $src, $path)) {
|
||||
$io->writeln("<red>Dependency '$name' has broken configuration, skipping...</red>");
|
||||
$io->newLine();
|
||||
$error = 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$locations = (array) $this->local_config["{$scm}_repos"];
|
||||
$to = $this->destination . DS . $path;
|
||||
|
||||
$from = null;
|
||||
foreach ($locations as $location) {
|
||||
$test = rtrim($location, '\\/') . DS . $src;
|
||||
if (file_exists($test)) {
|
||||
$from = $test;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$from) {
|
||||
$this->output->writeln('<red>source for ' . $data['src'] . ' does not exists, skipping...</red>');
|
||||
$this->output->writeln('');
|
||||
if (is_link($to) && !realpath($to)) {
|
||||
$io->writeln('<yellow>Removed broken symlink '. $path .'</yellow>');
|
||||
unlink($to);
|
||||
}
|
||||
if (null === $from) {
|
||||
$io->writeln('<red>source for ' . $src . ' does not exists, skipping...</red>');
|
||||
$io->newLine();
|
||||
$error = 1;
|
||||
} elseif (!file_exists($to)) {
|
||||
$error = $this->addSymlinks($from, $to, ['name' => $name, 'src' => $src, 'path' => $path]);
|
||||
$io->newLine();
|
||||
} else {
|
||||
if (!file_exists($to)) {
|
||||
symlink($from, $to);
|
||||
$this->output->writeln('<green>SUCCESS</green> symlinked <magenta>' . $data['src'] . '</magenta> -> <cyan>' . $data['path'] . '</cyan>');
|
||||
$this->output->writeln('');
|
||||
} else {
|
||||
$this->output->writeln('<red>destination: ' . $to . ' already exists, skipping...</red>');
|
||||
$this->output->writeln('');
|
||||
}
|
||||
$io->writeln('<yellow>destination: ' . $path . ' already exists, skipping...</yellow>');
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
private function addSymlinks(string $from, string $to, array $options): int
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$hebe = $this->readHebe($from);
|
||||
if (null === $hebe) {
|
||||
symlink($from, $to);
|
||||
|
||||
$io->writeln('<green>SUCCESS</green> symlinked <magenta>' . $options['src'] . '</magenta> -> <cyan>' . $options['path'] . '</cyan>');
|
||||
} else {
|
||||
$to = GRAV_ROOT;
|
||||
$name = $options['name'];
|
||||
$io->writeln("Processing <magenta>{$name}</magenta>");
|
||||
foreach ($hebe as $section => $symlinks) {
|
||||
foreach ($symlinks as $symlink) {
|
||||
$src = trim($symlink['source'], '/');
|
||||
$dst = trim($symlink['destination'], '/');
|
||||
$s = "{$from}/{$src}";
|
||||
$d = "{$to}/{$dst}";
|
||||
|
||||
if (is_link($d) && !realpath($d)) {
|
||||
unlink($d);
|
||||
$io->writeln(' <yellow>Removed broken symlink '. $dst .'</yellow>');
|
||||
}
|
||||
if (!file_exists($d)) {
|
||||
symlink($s, $d);
|
||||
$io->writeln(' symlinked <magenta>' . $src . '</magenta> -> <cyan>' . $dst . '</cyan>');
|
||||
}
|
||||
}
|
||||
}
|
||||
$io->writeln('<green>SUCCESS</green>');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function readHebe(string $folder): ?array
|
||||
{
|
||||
$filename = "{$folder}/hebe.json";
|
||||
if (!is_file($filename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$formatter = new JsonFormatter();
|
||||
$file = new JsonFile($filename, $formatter);
|
||||
$hebe = $file->load();
|
||||
$paths = $hebe['platforms']['grav']['nodes'] ?? null;
|
||||
|
||||
return is_array($paths) ? $paths : null;
|
||||
}
|
||||
}
|
||||
|
||||
96
system/src/Grav/Console/Cli/LogViewerCommand.php
Normal file
96
system/src/Grav/Console/Cli/LogViewerCommand.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use DateTime;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Helpers\LogViewer;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
/**
|
||||
* Class LogViewerCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class LogViewerCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('logviewer')
|
||||
->addOption(
|
||||
'file',
|
||||
'f',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'custom log file location (default = grav.log)'
|
||||
)
|
||||
->addOption(
|
||||
'lines',
|
||||
'l',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'number of lines (default = 10)'
|
||||
)
|
||||
->setDescription('Display the last few entries of Grav log')
|
||||
->setHelp('Display the last few entries of Grav log');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function serve(): int
|
||||
{
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$file = $input->getOption('file') ?? 'grav.log';
|
||||
$lines = $input->getOption('lines') ?? 20;
|
||||
$verbose = $input->getOption('verbose') ?? false;
|
||||
|
||||
$io->title('Log Viewer');
|
||||
|
||||
$io->writeln(sprintf('viewing last %s entries in <white>%s</white>', $lines, $file));
|
||||
$io->newLine();
|
||||
|
||||
$viewer = new LogViewer();
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
$logfile = $grav['locator']->findResource('log://' . $file);
|
||||
if (!$logfile) {
|
||||
$io->error('cannot find the log file: logs/' . $file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$rows = $viewer->objectTail($logfile, $lines, true);
|
||||
foreach ($rows as $log) {
|
||||
$date = $log['date'];
|
||||
$level_color = LogViewer::levelColor($log['level']);
|
||||
|
||||
if ($date instanceof DateTime) {
|
||||
$output = "<yellow>{$log['date']->format('Y-m-d h:i:s')}</yellow> [<{$level_color}>{$log['level']}</{$level_color}>]";
|
||||
if ($log['trace'] && $verbose) {
|
||||
$output .= " <white>{$log['message']}</white>\n";
|
||||
foreach ((array) $log['trace'] as $index => $tracerow) {
|
||||
$output .= "<white>{$index}</white>${tracerow}\n";
|
||||
}
|
||||
} else {
|
||||
$output .= " {$log['message']}";
|
||||
}
|
||||
$io->writeln($output);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class NewProjectCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class NewProjectCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class NewProjectCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('new-project')
|
||||
@@ -39,10 +44,12 @@ class NewProjectCommand extends ConsoleCommand
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$sandboxCommand = $this->getApplication()->find('sandbox');
|
||||
$installCommand = $this->getApplication()->find('install');
|
||||
|
||||
@@ -58,8 +65,11 @@ class NewProjectCommand extends ConsoleCommand
|
||||
'-s' => $this->input->getOption('symlink')
|
||||
]);
|
||||
|
||||
$sandboxCommand->run($sandboxArguments, $this->output);
|
||||
$installCommand->run($installArguments, $this->output);
|
||||
$error = $sandboxCommand->run($sandboxArguments, $io);
|
||||
if ($error === 0) {
|
||||
$error = $installCommand->run($installArguments, $io);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
|
||||
299
system/src/Grav/Console/Cli/PageSystemValidatorCommand.php
Normal file
299
system/src/Grav/Console/Cli/PageSystemValidatorCommand.php
Normal file
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Page\Pages;
|
||||
use Grav\Console\GravCommand;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use function in_array;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Class PageSystemValidatorCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class PageSystemValidatorCommand extends GravCommand
|
||||
{
|
||||
/** @var array */
|
||||
protected $tests = [
|
||||
// Content
|
||||
'header' => [[]],
|
||||
'summary' => [[], [200], [200, true]],
|
||||
'content' => [[]],
|
||||
'getRawContent' => [[]],
|
||||
'rawMarkdown' => [[]],
|
||||
'value' => [['content'], ['route'], ['order'], ['ordering'], ['folder'], ['slug'], ['name'], /*['frontmatter'],*/ ['header.menu'], ['header.slug']],
|
||||
'title' => [[]],
|
||||
'menu' => [[]],
|
||||
'visible' => [[]],
|
||||
'published' => [[]],
|
||||
'publishDate' => [[]],
|
||||
'unpublishDate' => [[]],
|
||||
'process' => [[]],
|
||||
'slug' => [[]],
|
||||
'order' => [[]],
|
||||
//'id' => [[]],
|
||||
'modified' => [[]],
|
||||
'lastModified' => [[]],
|
||||
'folder' => [[]],
|
||||
'date' => [[]],
|
||||
'dateformat' => [[]],
|
||||
'taxonomy' => [[]],
|
||||
'shouldProcess' => [['twig'], ['markdown']],
|
||||
'isPage' => [[]],
|
||||
'isDir' => [[]],
|
||||
'exists' => [[]],
|
||||
|
||||
// Forms
|
||||
'forms' => [[]],
|
||||
|
||||
// Routing
|
||||
'urlExtension' => [[]],
|
||||
'routable' => [[]],
|
||||
'link' => [[], [false], [true]],
|
||||
'permalink' => [[]],
|
||||
'canonical' => [[], [false], [true]],
|
||||
'url' => [[], [true], [true, true], [true, true, false], [false, false, true, false]],
|
||||
'route' => [[]],
|
||||
'rawRoute' => [[]],
|
||||
'routeAliases' => [[]],
|
||||
'routeCanonical' => [[]],
|
||||
'redirect' => [[]],
|
||||
'relativePagePath' => [[]],
|
||||
'path' => [[]],
|
||||
//'folder' => [[]],
|
||||
'parent' => [[]],
|
||||
'topParent' => [[]],
|
||||
'currentPosition' => [[]],
|
||||
'active' => [[]],
|
||||
'activeChild' => [[]],
|
||||
'home' => [[]],
|
||||
'root' => [[]],
|
||||
|
||||
// Translations
|
||||
'translatedLanguages' => [[], [false], [true]],
|
||||
'untranslatedLanguages' => [[], [false], [true]],
|
||||
'language' => [[]],
|
||||
|
||||
// Legacy
|
||||
'raw' => [[]],
|
||||
'frontmatter' => [[]],
|
||||
'httpResponseCode' => [[]],
|
||||
'httpHeaders' => [[]],
|
||||
'blueprintName' => [[]],
|
||||
'name' => [[]],
|
||||
'childType' => [[]],
|
||||
'template' => [[]],
|
||||
'templateFormat' => [[]],
|
||||
'extension' => [[]],
|
||||
'expires' => [[]],
|
||||
'cacheControl' => [[]],
|
||||
'ssl' => [[]],
|
||||
'metadata' => [[]],
|
||||
'eTag' => [[]],
|
||||
'filePath' => [[]],
|
||||
'filePathClean' => [[]],
|
||||
'orderDir' => [[]],
|
||||
'orderBy' => [[]],
|
||||
'orderManual' => [[]],
|
||||
'maxCount' => [[]],
|
||||
'modular' => [[]],
|
||||
'modularTwig' => [[]],
|
||||
//'children' => [[]],
|
||||
'isFirst' => [[]],
|
||||
'isLast' => [[]],
|
||||
'prevSibling' => [[]],
|
||||
'nextSibling' => [[]],
|
||||
'adjacentSibling' => [[]],
|
||||
'ancestor' => [[]],
|
||||
//'inherited' => [[]],
|
||||
//'inheritedField' => [[]],
|
||||
'find' => [['/']],
|
||||
//'collection' => [[]],
|
||||
//'evaluate' => [[]],
|
||||
'folderExists' => [[]],
|
||||
//'getOriginal' => [[]],
|
||||
//'getAction' => [[]],
|
||||
];
|
||||
|
||||
/** @var Grav */
|
||||
protected $grav;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('page-system-validator')
|
||||
->setDescription('Page validator can be used to compare site before/after update and when migrating to Flex Pages.')
|
||||
->addOption('record', 'r', InputOption::VALUE_NONE, 'Record results')
|
||||
->addOption('check', 'c', InputOption::VALUE_NONE, 'Compare site against previously recorded results')
|
||||
->setHelp('The <info>page-system-validator</info> command can be used to test the pages before and after upgrade');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function serve(): int
|
||||
{
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$this->setLanguage('en');
|
||||
$this->initializePages();
|
||||
|
||||
$io->newLine();
|
||||
|
||||
$this->grav = $grav = Grav::instance();
|
||||
|
||||
$grav->fireEvent('onPageInitialized', new Event(['page' => $grav['page']]));
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
|
||||
if ($input->getOption('record')) {
|
||||
$io->writeln('Pages: ' . $config->get('system.pages.type', 'page'));
|
||||
|
||||
$io->writeln('<magenta>Record tests</magenta>');
|
||||
$io->newLine();
|
||||
|
||||
$results = $this->record();
|
||||
$file = $this->getFile('pages-old');
|
||||
$file->save($results);
|
||||
|
||||
$io->writeln('Recorded tests to ' . $file->filename());
|
||||
} elseif ($input->getOption('check')) {
|
||||
$io->writeln('Pages: ' . $config->get('system.pages.type', 'page'));
|
||||
|
||||
$io->writeln('<magenta>Run tests</magenta>');
|
||||
$io->newLine();
|
||||
|
||||
$new = $this->record();
|
||||
$file = $this->getFile('pages-new');
|
||||
$file->save($new);
|
||||
$io->writeln('Recorded tests to ' . $file->filename());
|
||||
|
||||
$file = $this->getFile('pages-old');
|
||||
$old = $file->content();
|
||||
|
||||
$results = $this->check($old, $new);
|
||||
$file = $this->getFile('diff');
|
||||
$file->save($results);
|
||||
$io->writeln('Recorded results to ' . $file->filename());
|
||||
} else {
|
||||
$io->writeln('<green>page-system-validator [-r|--record] [-c|--check]</green>');
|
||||
}
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function record(): array
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
/** @var Pages $pages */
|
||||
$pages = $this->grav['pages'];
|
||||
$all = $pages->all();
|
||||
|
||||
$results = [];
|
||||
$results[''] = $this->recordRow($pages->root());
|
||||
foreach ($all as $path => $page) {
|
||||
if (null === $page) {
|
||||
$io->writeln('<red>Error on page ' . $path . '</red>');
|
||||
continue;
|
||||
}
|
||||
|
||||
$results[$page->rawRoute()] = $this->recordRow($page);
|
||||
}
|
||||
|
||||
return json_decode(json_encode($results), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PageInterface $page
|
||||
* @return array
|
||||
*/
|
||||
private function recordRow(PageInterface $page): array
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($this->tests as $method => $params) {
|
||||
$params = $params ?: [[]];
|
||||
foreach ($params as $p) {
|
||||
$result = $page->$method(...$p);
|
||||
if (in_array($method, ['summary', 'content', 'getRawContent'], true)) {
|
||||
$result = preg_replace('/name="(form-nonce|__unique_form_id__)" value="[^"]+"/',
|
||||
'name="\\1" value="DYNAMIC"', $result);
|
||||
$result = preg_replace('`src=("|\'|")/images/./././././[^"]+\\1`',
|
||||
'src="\\1images/GENERATED\\1', $result);
|
||||
$result = preg_replace('/\?\d{10}/', '?1234567890', $result);
|
||||
} elseif ($method === 'httpHeaders' && isset($result['Expires'])) {
|
||||
$result['Expires'] = 'Thu, 19 Sep 2019 13:10:24 GMT (REPLACED AS DYNAMIC)';
|
||||
} elseif ($result instanceof PageInterface) {
|
||||
$result = $result->rawRoute();
|
||||
} elseif (is_object($result)) {
|
||||
$result = json_decode(json_encode($result), true);
|
||||
}
|
||||
|
||||
$ps = [];
|
||||
foreach ($p as $val) {
|
||||
$ps[] = (string)var_export($val, true);
|
||||
}
|
||||
$pstr = implode(', ', $ps);
|
||||
$call = "->{$method}({$pstr})";
|
||||
$results[$call] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $old
|
||||
* @param array $new
|
||||
* @return array
|
||||
*/
|
||||
private function check(array $old, array $new): array
|
||||
{
|
||||
$errors = [];
|
||||
foreach ($old as $path => $page) {
|
||||
if (!isset($new[$path])) {
|
||||
$errors[$path] = 'PAGE REMOVED';
|
||||
continue;
|
||||
}
|
||||
foreach ($page as $method => $test) {
|
||||
if (($new[$path][$method] ?? null) !== $test) {
|
||||
$errors[$path][$method] = ['old' => $test, 'new' => $new[$path][$method]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return CompiledYamlFile
|
||||
*/
|
||||
private function getFile(string $name): CompiledYamlFile
|
||||
{
|
||||
return CompiledYamlFile::instance('cache://tests/' . $name . '.yaml');
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Console\GravCommand;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use function count;
|
||||
|
||||
class SandboxCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class SandboxCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class SandboxCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $directories = [
|
||||
'/assets',
|
||||
'/backup',
|
||||
@@ -33,9 +38,7 @@ class SandboxCommand extends ConsoleCommand
|
||||
'/user/themes',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $files = [
|
||||
'/.dependencies',
|
||||
'/.htaccess',
|
||||
@@ -43,11 +46,10 @@ class SandboxCommand extends ConsoleCommand
|
||||
'/user/config/system.yaml',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $mappings = [
|
||||
'/.gitignore' => '/.gitignore',
|
||||
'/.editorconfig' => '/.editorconfig',
|
||||
'/CHANGELOG.md' => '/CHANGELOG.md',
|
||||
'/LICENSE.txt' => '/LICENSE.txt',
|
||||
'/README.md' => '/README.md',
|
||||
@@ -60,19 +62,15 @@ class SandboxCommand extends ConsoleCommand
|
||||
'/webserver-configs' => '/webserver-configs',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
||||
protected $default_file = "---\ntitle: HomePage\n---\n# HomePage\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque porttitor eu felis sed ornare. Sed a mauris venenatis, pulvinar velit vel, dictum enim. Phasellus ac rutrum velit. Nunc lorem purus, hendrerit sit amet augue aliquet, iaculis ultricies nisl. Suspendisse tincidunt euismod risus, quis feugiat arcu tincidunt eget. Nulla eros mi, commodo vel ipsum vel, aliquet congue odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque velit orci, laoreet at adipiscing eu, interdum quis nibh. Nunc a accumsan purus.";
|
||||
|
||||
/** @var string */
|
||||
protected $source;
|
||||
/** @var string */
|
||||
protected $destination;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('sandbox')
|
||||
@@ -89,104 +87,129 @@ class SandboxCommand extends ConsoleCommand
|
||||
'Symlink the base grav system'
|
||||
)
|
||||
->setHelp("The <info>sandbox</info> command help create a development environment that can optionally use symbolic links to link the core of grav to the git cloned repository.\nGood for development, playing around or starting fresh");
|
||||
$this->source = getcwd();
|
||||
|
||||
$source = getcwd();
|
||||
if ($source === false) {
|
||||
throw new RuntimeException('Internal Error');
|
||||
}
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->destination = $this->input->getArgument('destination');
|
||||
$input = $this->getInput();
|
||||
|
||||
// Symlink the Core Stuff
|
||||
if ($this->input->getOption('symlink')) {
|
||||
// Create Some core stuff if it doesn't exist
|
||||
$this->createDirectories();
|
||||
$this->destination = $input->getArgument('destination');
|
||||
|
||||
// Loop through the symlink mappings and create the symlinks
|
||||
$this->symlink();
|
||||
|
||||
// Copy the Core STuff
|
||||
} else {
|
||||
// Create Some core stuff if it doesn't exist
|
||||
$this->createDirectories();
|
||||
|
||||
// Loop through the symlink mappings and copy what otherwise would be symlinks
|
||||
$this->copy();
|
||||
// Create Some core stuff if it doesn't exist
|
||||
$error = $this->createDirectories();
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->pages();
|
||||
$this->initFiles();
|
||||
$this->perms();
|
||||
// Copy files or create symlinks
|
||||
$error = $input->getOption('symlink') ? $this->symlink() : $this->copy();
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$error = $this->pages();
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$error = $this->initFiles();
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$error = $this->perms();
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function createDirectories()
|
||||
private function createDirectories(): int
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>Creating Directories</comment>');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>Creating Directories</comment>');
|
||||
$dirs_created = false;
|
||||
|
||||
if (!file_exists($this->destination)) {
|
||||
mkdir($this->destination, 0777, true);
|
||||
Folder::create($this->destination);
|
||||
}
|
||||
|
||||
foreach ($this->directories as $dir) {
|
||||
if (!file_exists($this->destination . $dir)) {
|
||||
$dirs_created = true;
|
||||
$this->output->writeln(' <cyan>' . $dir . '</cyan>');
|
||||
mkdir($this->destination . $dir, 0777, true);
|
||||
$io->writeln(' <cyan>' . $dir . '</cyan>');
|
||||
Folder::create($this->destination . $dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$dirs_created) {
|
||||
$this->output->writeln(' <red>Directories already exist</red>');
|
||||
$io->writeln(' <red>Directories already exist</red>');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function copy()
|
||||
private function copy(): int
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>Copying Files</comment>');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>Copying Files</comment>');
|
||||
|
||||
|
||||
foreach ($this->mappings as $source => $target) {
|
||||
if ((int)$source == $source) {
|
||||
if ((string)(int)$source === (string)$source) {
|
||||
$source = $target;
|
||||
}
|
||||
|
||||
$from = $this->source . $source;
|
||||
$to = $this->destination . $target;
|
||||
|
||||
$this->output->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
|
||||
$io->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
|
||||
@Folder::rcopy($from, $to);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function symlink()
|
||||
private function symlink(): int
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>Resetting Symbolic Links</comment>');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>Resetting Symbolic Links</comment>');
|
||||
|
||||
|
||||
foreach ($this->mappings as $source => $target) {
|
||||
if ((int)$source == $source) {
|
||||
if ((string)(int)$source === (string)$source) {
|
||||
$source = $target;
|
||||
}
|
||||
|
||||
$from = $this->source . $source;
|
||||
$to = $this->destination . $target;
|
||||
|
||||
$this->output->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
|
||||
$io->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
|
||||
|
||||
if (is_dir($to)) {
|
||||
@Folder::delete($to);
|
||||
@@ -195,22 +218,50 @@ class SandboxCommand extends ConsoleCommand
|
||||
}
|
||||
symlink($from, $to);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function initFiles()
|
||||
private function pages(): int
|
||||
{
|
||||
$this->check();
|
||||
$io = $this->getIO();
|
||||
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>File Initializing</comment>');
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>Pages Initializing</comment>');
|
||||
|
||||
// get pages files and initialize if no pages exist
|
||||
$pages_dir = $this->destination . '/user/pages';
|
||||
$pages_files = array_diff(scandir($pages_dir), ['..', '.']);
|
||||
|
||||
if (count($pages_files) === 0) {
|
||||
$destination = $this->source . '/user/pages';
|
||||
Folder::rcopy($destination, $pages_dir);
|
||||
$io->writeln(' <cyan>' . $destination . '</cyan> <comment>-></comment> Created');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function initFiles(): int
|
||||
{
|
||||
if (!$this->check()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io = $this->getIO();
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>File Initializing</comment>');
|
||||
$files_init = false;
|
||||
|
||||
// Copy files if they do not exist
|
||||
foreach ($this->files as $source => $target) {
|
||||
if ((int)$source == $source) {
|
||||
if ((string)(int)$source === (string)$source) {
|
||||
$source = $target;
|
||||
}
|
||||
|
||||
@@ -220,42 +271,25 @@ class SandboxCommand extends ConsoleCommand
|
||||
if (!file_exists($to)) {
|
||||
$files_init = true;
|
||||
copy($from, $to);
|
||||
$this->output->writeln(' <cyan>' . $target . '</cyan> <comment>-></comment> Created');
|
||||
$io->writeln(' <cyan>' . $target . '</cyan> <comment>-></comment> Created');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$files_init) {
|
||||
$this->output->writeln(' <red>Files already exist</red>');
|
||||
$io->writeln(' <red>Files already exist</red>');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function pages()
|
||||
private function perms(): int
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>Pages Initializing</comment>');
|
||||
|
||||
// get pages files and initialize if no pages exist
|
||||
$pages_dir = $this->destination . '/user/pages';
|
||||
$pages_files = array_diff(scandir($pages_dir), ['..', '.']);
|
||||
|
||||
if (count($pages_files) == 0) {
|
||||
$destination = $this->source . '/user/pages';
|
||||
Folder::rcopy($destination, $pages_dir);
|
||||
$this->output->writeln(' <cyan>' . $destination . '</cyan> <comment>-></comment> Created');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function perms()
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>Permissions Initializing</comment>');
|
||||
$io = $this->getIO();
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>Permissions Initializing</comment>');
|
||||
|
||||
$dir_perms = 0755;
|
||||
|
||||
@@ -263,42 +297,46 @@ class SandboxCommand extends ConsoleCommand
|
||||
|
||||
foreach ($binaries as $bin) {
|
||||
chmod($bin, $dir_perms);
|
||||
$this->output->writeln(' <cyan>bin/' . basename($bin) . '</cyan> permissions reset to ' . decoct($dir_perms));
|
||||
$io->writeln(' <cyan>bin/' . basename($bin) . '</cyan> permissions reset to ' . decoct($dir_perms));
|
||||
}
|
||||
|
||||
$this->output->writeln("");
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function check()
|
||||
private function check(): bool
|
||||
{
|
||||
$success = true;
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!file_exists($this->destination)) {
|
||||
$this->output->writeln(' file: <red>$this->destination</red> does not exist!');
|
||||
$io->writeln(' file: <red>' . $this->destination . '</red> does not exist!');
|
||||
$success = false;
|
||||
}
|
||||
|
||||
foreach ($this->directories as $dir) {
|
||||
if (!file_exists($this->destination . $dir)) {
|
||||
$this->output->writeln(' directory: <red>' . $dir . '</red> does not exist!');
|
||||
$io->writeln(' directory: <red>' . $dir . '</red> does not exist!');
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->mappings as $target => $link) {
|
||||
if (!file_exists($this->destination . $target)) {
|
||||
$this->output->writeln(' mappings: <red>' . $target . '</red> does not exist!');
|
||||
$io->writeln(' mappings: <red>' . $target . '</red> does not exist!');
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('<comment>install should be run with --symlink|--s to symlink first</comment>');
|
||||
exit;
|
||||
$io->newLine();
|
||||
$io->writeln('<comment>install should be run with --symlink|--s to symlink first</comment>');
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
||||
225
system/src/Grav/Console/Cli/SchedulerCommand.php
Normal file
225
system/src/Grav/Console/Cli/SchedulerCommand.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Common\Scheduler\Scheduler;
|
||||
use Grav\Console\GravCommand;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use function is_null;
|
||||
|
||||
/**
|
||||
* Class SchedulerCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class SchedulerCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('scheduler')
|
||||
->addOption(
|
||||
'install',
|
||||
'i',
|
||||
InputOption::VALUE_NONE,
|
||||
'Show Install Command'
|
||||
)
|
||||
->addOption(
|
||||
'jobs',
|
||||
'j',
|
||||
InputOption::VALUE_NONE,
|
||||
'Show Jobs Summary'
|
||||
)
|
||||
->addOption(
|
||||
'details',
|
||||
'd',
|
||||
InputOption::VALUE_NONE,
|
||||
'Show Job Details'
|
||||
)
|
||||
->addOption(
|
||||
'run',
|
||||
'r',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Force run all jobs or a specific job if you specify a specific Job ID',
|
||||
false
|
||||
)
|
||||
->setDescription('Run the Grav Scheduler. Best when integrated with system cron')
|
||||
->setHelp("Running without any options will force the Scheduler to run through it's jobs and process them");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->initializePlugins();
|
||||
|
||||
$grav = Grav::instance();
|
||||
$grav['backups']->init();
|
||||
$this->initializePages();
|
||||
$this->initializeThemes();
|
||||
|
||||
/** @var Scheduler $scheduler */
|
||||
$scheduler = $grav['scheduler'];
|
||||
$grav->fireEvent('onSchedulerInitialized', new Event(['scheduler' => $scheduler]));
|
||||
|
||||
$this->setHelp('foo');
|
||||
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
$error = 0;
|
||||
|
||||
$run = $input->getOption('run');
|
||||
|
||||
if ($input->getOption('jobs')) {
|
||||
// Show jobs list
|
||||
|
||||
$jobs = $scheduler->getAllJobs();
|
||||
$job_states = (array)$scheduler->getJobStates()->content();
|
||||
$rows = [];
|
||||
|
||||
$table = new Table($io);
|
||||
$table->setStyle('box');
|
||||
$headers = ['Job ID', 'Command', 'Run At', 'Status', 'Last Run', 'State'];
|
||||
|
||||
$io->title('Scheduler Jobs Listing');
|
||||
|
||||
foreach ($jobs as $job) {
|
||||
$job_status = ucfirst($job_states[$job->getId()]['state'] ?? 'ready');
|
||||
$last_run = $job_states[$job->getId()]['last-run'] ?? 0;
|
||||
$status = $job_status === 'Failure' ? "<red>{$job_status}</red>" : "<green>{$job_status}</green>";
|
||||
$state = $job->getEnabled() ? '<cyan>Enabled</cyan>' : '<red>Disabled</red>';
|
||||
$row = [
|
||||
$job->getId(),
|
||||
"<white>{$job->getCommand()}</white>",
|
||||
"<magenta>{$job->getAt()}</magenta>",
|
||||
$status,
|
||||
'<yellow>' . ($last_run === 0 ? 'Never' : date('Y-m-d H:i', $last_run)) . '</yellow>',
|
||||
$state,
|
||||
|
||||
];
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
if (!empty($rows)) {
|
||||
$table->setHeaders($headers);
|
||||
$table->setRows($rows);
|
||||
$table->render();
|
||||
} else {
|
||||
$io->text('no jobs found...');
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
$io->note('For error details run "bin/grav scheduler -d"');
|
||||
$io->newLine();
|
||||
} elseif ($input->getOption('details')) {
|
||||
$jobs = $scheduler->getAllJobs();
|
||||
$job_states = (array)$scheduler->getJobStates()->content();
|
||||
|
||||
$io->title('Job Details');
|
||||
|
||||
$table = new Table($io);
|
||||
$table->setStyle('box');
|
||||
$table->setHeaders(['Job ID', 'Last Run', 'Next Run', 'Errors']);
|
||||
$rows = [];
|
||||
|
||||
foreach ($jobs as $job) {
|
||||
$job_state = $job_states[$job->getId()];
|
||||
$error = isset($job_state['error']) ? trim($job_state['error']) : false;
|
||||
|
||||
/** @var CronExpression $expression */
|
||||
$expression = $job->getCronExpression();
|
||||
$next_run = $expression->getNextRunDate();
|
||||
|
||||
$row = [];
|
||||
$row[] = $job->getId();
|
||||
if (!is_null($job_state['last-run'])) {
|
||||
$row[] = '<yellow>' . date('Y-m-d H:i', $job_state['last-run']) . '</yellow>';
|
||||
} else {
|
||||
$row[] = '<yellow>Never</yellow>';
|
||||
}
|
||||
$row[] = '<yellow>' . $next_run->format('Y-m-d H:i') . '</yellow>';
|
||||
|
||||
if ($error) {
|
||||
$row[] = "<error>{$error}</error>";
|
||||
} else {
|
||||
$row[] = '<green>None</green>';
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$table->setRows($rows);
|
||||
$table->render();
|
||||
} elseif ($run !== false && $run !== null) {
|
||||
$io->title('Force Run Job: ' . $run);
|
||||
|
||||
$job = $scheduler->getJob($run);
|
||||
|
||||
if ($job) {
|
||||
$job->inForeground()->run();
|
||||
|
||||
if ($job->isSuccessful()) {
|
||||
$io->success('Job ran successfully...');
|
||||
} else {
|
||||
$error = 1;
|
||||
$io->error('Job failed to run successfully...');
|
||||
}
|
||||
|
||||
$output = $job->getOutput();
|
||||
|
||||
if ($output) {
|
||||
$io->write($output);
|
||||
}
|
||||
} else {
|
||||
$error = 1;
|
||||
$io->error('Could not find a job with id: ' . $run);
|
||||
}
|
||||
} elseif ($input->getOption('install')) {
|
||||
$io->title('Install Scheduler');
|
||||
|
||||
$verb = 'install';
|
||||
|
||||
if ($scheduler->isCrontabSetup()) {
|
||||
$io->success('All Ready! You have already set up Grav\'s Scheduler in your crontab. You can validate this by running "crontab -l" to list your current crontab entries.');
|
||||
$verb = 'reinstall';
|
||||
} else {
|
||||
$user = $scheduler->whoami();
|
||||
$error = 1;
|
||||
$io->error('Can\'t find a crontab for ' . $user . '. You need to set up Grav\'s Scheduler in your crontab');
|
||||
}
|
||||
if (!Utils::isWindows()) {
|
||||
$io->note("To $verb, run the following command from your terminal:");
|
||||
$io->newLine();
|
||||
$io->text(trim($scheduler->getCronCommand()));
|
||||
} else {
|
||||
$io->note("To $verb, create a scheduled task in Windows.");
|
||||
$io->text('Learn more at https://learn.getgrav.org/advanced/scheduler');
|
||||
}
|
||||
} else {
|
||||
// Run scheduler
|
||||
$force = $run === null;
|
||||
$scheduler->run(null, $force);
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$io->title('Running Scheduled Jobs');
|
||||
$io->text($scheduler->getVerboseOutput());
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
@@ -10,92 +11,82 @@ namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Security;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use function count;
|
||||
|
||||
class SecurityCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class SecurityCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class SecurityCommand extends GravCommand
|
||||
{
|
||||
/** @var ProgressBar $progress */
|
||||
protected $progress;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("security")
|
||||
->setDescription("Capable of running various Security checks")
|
||||
->setName('security')
|
||||
->setDescription('Capable of running various Security checks')
|
||||
->setHelp('The <info>security</info> runs various security checks on your Grav site');
|
||||
|
||||
$this->source = getcwd();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->initializePages();
|
||||
|
||||
$io = $this->getIO();
|
||||
|
||||
/** @var Grav $grav */
|
||||
$grav = Grav::instance();
|
||||
|
||||
$grav['uri']->init();
|
||||
$grav['config']->init();
|
||||
$grav['debugger']->enabled(false);
|
||||
$grav['streams'];
|
||||
$grav['plugins']->init();
|
||||
$grav['themes']->init();
|
||||
|
||||
|
||||
$grav['twig']->init();
|
||||
$grav['pages']->init();
|
||||
|
||||
$this->progress = new ProgressBar($this->output, (count($grav['pages']->routes()) - 1));
|
||||
$this->progress = new ProgressBar($this->output, count($grav['pages']->routes()) - 1);
|
||||
$this->progress->setFormat('Scanning <cyan>%current%</cyan> pages [<green>%bar%</green>] <white>%percent:3s%%</white> %elapsed:6s%');
|
||||
$this->progress->setBarWidth(100);
|
||||
|
||||
$io = new SymfonyStyle($this->input, $this->output);
|
||||
$io->title('Grav Security Check');
|
||||
|
||||
$output = Security::detectXssFromPages($grav['pages'], [$this, 'outputProgress']);
|
||||
|
||||
$io->newline(2);
|
||||
|
||||
if (!empty($output)) {
|
||||
$output = Security::detectXssFromPages($grav['pages'], false, [$this, 'outputProgress']);
|
||||
|
||||
$error = 0;
|
||||
if (!empty($output)) {
|
||||
$counter = 1;
|
||||
foreach ($output as $route => $results) {
|
||||
|
||||
$results_parts = array_map(function($value, $key) {
|
||||
$results_parts = array_map(static function ($value, $key) {
|
||||
return $key.': \''.$value . '\'';
|
||||
}, array_values($results), array_keys($results));
|
||||
|
||||
$io->writeln($counter++ .' - <cyan>' . $route . '</cyan> → <red>' . implode(', ', $results_parts) . '</red>');
|
||||
}
|
||||
|
||||
$error = 1;
|
||||
$io->error('Security Scan complete: ' . count($output) . ' potential XSS issues found...');
|
||||
|
||||
} else {
|
||||
$io->success('Security Scan complete: No issues found...');
|
||||
}
|
||||
|
||||
$io->newline(1);
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @param array $args
|
||||
* @return void
|
||||
*/
|
||||
public function outputProgress($args)
|
||||
public function outputProgress(array $args): void
|
||||
{
|
||||
switch ($args['type']) {
|
||||
case 'count':
|
||||
$steps = $args['steps'];
|
||||
$freq = intval($steps > 100 ? round($steps / 100) : $steps);
|
||||
$freq = (int)($steps > 100 ? round($steps / 100) : $steps);
|
||||
$this->progress->setMaxSteps($steps);
|
||||
$this->progress->setRedrawFrequency($freq);
|
||||
break;
|
||||
@@ -108,6 +99,4 @@ class SecurityCommand extends ConsoleCommand
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
154
system/src/Grav/Console/Cli/ServerCommand.php
Normal file
154
system/src/Grav/Console/Cli/ServerCommand.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Class ServerCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class ServerCommand extends GravCommand
|
||||
{
|
||||
const SYMFONY_SERVER = 'Symfony Server';
|
||||
const PHP_SERVER = 'Built-in PHP Server';
|
||||
|
||||
/** @var string */
|
||||
protected $ip;
|
||||
/** @var int */
|
||||
protected $port;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('server')
|
||||
->addOption('port', 'p', InputOption::VALUE_OPTIONAL, 'Preferred HTTP port rather than auto-find (default is 8000-9000')
|
||||
->addOption('symfony', null, InputOption::VALUE_NONE, 'Force using Symfony server')
|
||||
->addOption('php', null, InputOption::VALUE_NONE, 'Force using built-in PHP server')
|
||||
->setDescription("Runs built-in web-server, Symfony first, then tries PHP's")
|
||||
->setHelp("Runs built-in web-server, Symfony first, then tries PHP's");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function serve(): int
|
||||
{
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->title('Grav Web Server');
|
||||
|
||||
// Ensure CLI colors are on
|
||||
ini_set('cli_server.color', 'on');
|
||||
|
||||
// Options
|
||||
$force_symfony = $input->getOption('symfony');
|
||||
$force_php = $input->getOption('php');
|
||||
|
||||
// Find PHP
|
||||
$executableFinder = new PhpExecutableFinder();
|
||||
$php = $executableFinder->find(false);
|
||||
|
||||
$this->ip = '127.0.0.1';
|
||||
$this->port = (int)($input->getOption('port') ?? 8000);
|
||||
|
||||
// Get an open port
|
||||
while (!$this->portAvailable($this->ip, $this->port)) {
|
||||
$this->port++;
|
||||
}
|
||||
|
||||
// Setup the commands
|
||||
$symfony_cmd = ['symfony', 'server:start', '--ansi', '--port=' . $this->port];
|
||||
$php_cmd = [$php, '-S', $this->ip.':'.$this->port, 'system/router.php'];
|
||||
|
||||
$commands = [
|
||||
self::SYMFONY_SERVER => $symfony_cmd,
|
||||
self::PHP_SERVER => $php_cmd
|
||||
];
|
||||
|
||||
if ($force_symfony) {
|
||||
unset($commands[self::PHP_SERVER]);
|
||||
} elseif ($force_php) {
|
||||
unset($commands[self::SYMFONY_SERVER]);
|
||||
}
|
||||
|
||||
$error = 0;
|
||||
foreach ($commands as $name => $command) {
|
||||
$process = $this->runProcess($name, $command);
|
||||
if (!$process) {
|
||||
$io->note('Starting ' . $name . '...');
|
||||
}
|
||||
|
||||
// Should only get here if there's an error running
|
||||
if (!$process->isRunning() && (($name === self::SYMFONY_SERVER && $force_symfony) || ($name === self::PHP_SERVER))) {
|
||||
$error = 1;
|
||||
$io->error('Could not start ' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $cmd
|
||||
* @return Process
|
||||
*/
|
||||
protected function runProcess(string $name, array $cmd): Process
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$process = new Process($cmd);
|
||||
$process->setTimeout(0);
|
||||
$process->start();
|
||||
|
||||
if ($name === self::SYMFONY_SERVER && Utils::contains($process->getErrorOutput(), 'symfony: not found')) {
|
||||
$io->error('The symfony binary could not be found, please install the CLI tools: https://symfony.com/download');
|
||||
$io->warning('Falling back to PHP web server...');
|
||||
}
|
||||
|
||||
if ($name === self::PHP_SERVER) {
|
||||
$io->success('Built-in PHP web server listening on http://' . $this->ip . ':' . $this->port . ' (PHP v' . PHP_VERSION . ')');
|
||||
}
|
||||
|
||||
$process->wait(function ($type, $buffer) {
|
||||
$this->getIO()->write($buffer);
|
||||
});
|
||||
|
||||
return $process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function test the port
|
||||
*
|
||||
* @param string $ip
|
||||
* @param int $port
|
||||
* @return bool
|
||||
*/
|
||||
protected function portAvailable(string $ip, int $port): bool
|
||||
{
|
||||
$fp = @fsockopen($ip, $port, $errno, $errstr, 0.1);
|
||||
if (!$fp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
124
system/src/Grav/Console/Cli/YamlLinterCommand.php
Normal file
124
system/src/Grav/Console/Cli/YamlLinterCommand.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Helpers\YamlLinter;
|
||||
use Grav\Console\GravCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Class YamlLinterCommand
|
||||
* @package Grav\Console\Cli
|
||||
*/
|
||||
class YamlLinterCommand extends GravCommand
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName('yamllinter')
|
||||
->addOption(
|
||||
'all',
|
||||
'a',
|
||||
InputOption::VALUE_NONE,
|
||||
'Go through the whole Grav installation'
|
||||
)
|
||||
->addOption(
|
||||
'folder',
|
||||
'f',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Go through specific folder'
|
||||
)
|
||||
->setDescription('Checks various files for YAML errors')
|
||||
->setHelp('Checks various files for YAML errors');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function serve(): int
|
||||
{
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->title('Yaml Linter');
|
||||
|
||||
$error = 0;
|
||||
if ($input->getOption('all')) {
|
||||
$io->section('All');
|
||||
$errors = YamlLinter::lint('');
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues found');
|
||||
} else {
|
||||
$error = 1;
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
} elseif ($folder = $input->getOption('folder')) {
|
||||
$io->section($folder);
|
||||
$errors = YamlLinter::lint($folder);
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues found');
|
||||
} else {
|
||||
$error = 1;
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
} else {
|
||||
$io->section('User Configuration');
|
||||
$errors = YamlLinter::lintConfig();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with configuration');
|
||||
} else {
|
||||
$error = 1;
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
|
||||
$io->section('Pages Frontmatter');
|
||||
$errors = YamlLinter::lintPages();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with pages');
|
||||
} else {
|
||||
$error = 1;
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
|
||||
$io->section('Page Blueprints');
|
||||
$errors = YamlLinter::lintBlueprints();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with blueprints');
|
||||
} else {
|
||||
$error = 1;
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $errors
|
||||
* @param SymfonyStyle $io
|
||||
* @return void
|
||||
*/
|
||||
protected function displayErrors(array $errors, SymfonyStyle $io): void
|
||||
{
|
||||
$io->error('YAML Linting issues found...');
|
||||
foreach ($errors as $path => $error) {
|
||||
$io->writeln("<yellow>{$path}</yellow> - {$error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class ConsoleCommand
|
||||
* @package Grav\Console
|
||||
*/
|
||||
class ConsoleCommand extends Command
|
||||
{
|
||||
use ConsoleTrait;
|
||||
@@ -20,28 +24,23 @@ class ConsoleCommand extends Command
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->setupConsole($input, $output);
|
||||
$this->serve();
|
||||
|
||||
return $this->serve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override with your implementation.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
{
|
||||
|
||||
// Return error.
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected function displayGPMRelease()
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('GPM Releases Configuration: <yellow>' . ucfirst(Grav::instance()['config']->get('system.gpm.releases')) . '</yellow>');
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,93 +1,289 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console;
|
||||
|
||||
use Exception;
|
||||
use Grav\Common\Cache;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Composer;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Language\Language;
|
||||
use Grav\Common\Processors\InitializeProcessor;
|
||||
use Grav\Console\Cli\ClearCacheCommand;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Trait ConsoleTrait
|
||||
* @package Grav\Console
|
||||
*/
|
||||
trait ConsoleTrait
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $argv;
|
||||
|
||||
/* @var InputInterface $output */
|
||||
/** @var InputInterface */
|
||||
protected $input;
|
||||
|
||||
/* @var OutputInterface $output */
|
||||
/** @var SymfonyStyle */
|
||||
protected $output;
|
||||
/** @var array */
|
||||
protected $local_config;
|
||||
|
||||
/** @var bool */
|
||||
private $plugins_initialized = false;
|
||||
/** @var bool */
|
||||
private $themes_initialized = false;
|
||||
/** @var bool */
|
||||
private $pages_initialized = false;
|
||||
|
||||
/**
|
||||
* Set colors style definition for the formatter.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return void
|
||||
*/
|
||||
public function setupConsole(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// Initialize cache with CLI compatibility
|
||||
Grav::instance()['config']->set('system.cache.cli_compatibility', true);
|
||||
Grav::instance()['cache'];
|
||||
|
||||
$this->argv = $_SERVER['argv'][0];
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->input = $input;
|
||||
$this->output = new SymfonyStyle($input, $output);
|
||||
|
||||
$this->output->getFormatter()->setStyle('normal', new OutputFormatterStyle('white'));
|
||||
$this->output->getFormatter()->setStyle('yellow', new OutputFormatterStyle('yellow', null, array('bold')));
|
||||
$this->output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, array('bold')));
|
||||
$this->output->getFormatter()->setStyle('cyan', new OutputFormatterStyle('cyan', null, array('bold')));
|
||||
$this->output->getFormatter()->setStyle('green', new OutputFormatterStyle('green', null, array('bold')));
|
||||
$this->output->getFormatter()->setStyle('magenta', new OutputFormatterStyle('magenta', null, array('bold')));
|
||||
$this->output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, array('bold')));
|
||||
$this->setupGrav();
|
||||
}
|
||||
|
||||
public function getInput(): InputInterface
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return SymfonyStyle
|
||||
*/
|
||||
public function getIO(): SymfonyStyle
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an option.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
|
||||
* @param int|null $mode The option mode: One of the InputOption::VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param string|string[]|int|bool|null $default The default value (must be null for InputOption::VALUE_NONE)
|
||||
* @return $this
|
||||
* @throws InvalidArgumentException If option mode is invalid or incompatible
|
||||
*/
|
||||
public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
if ($name !== 'env' && $name !== 'lang') {
|
||||
parent::addOption($name, $shortcut, $mode, $description, $default);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
final protected function setupGrav(): void
|
||||
{
|
||||
try {
|
||||
$language = $this->input->getOption('lang');
|
||||
if ($language) {
|
||||
// Set used language.
|
||||
$this->setLanguage($language);
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {}
|
||||
|
||||
// Initialize cache with CLI compatibility
|
||||
$grav = Grav::instance();
|
||||
$grav['config']->set('system.cache.cli_compatibility', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Grav.
|
||||
*
|
||||
* - Load configuration
|
||||
* - Initialize logger
|
||||
* - Disable debugger
|
||||
* - Set timezone, locale
|
||||
* - Load plugins (call PluginsLoadedEvent)
|
||||
* - Set Pages and Users type to be used in the site
|
||||
*
|
||||
* Safe to be called multiple times.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final protected function initializeGrav()
|
||||
{
|
||||
InitializeProcessor::initializeCli(Grav::instance());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set language to be used in CLI.
|
||||
*
|
||||
* @param string|null $code
|
||||
* @return $this
|
||||
*/
|
||||
final protected function setLanguage(string $code = null)
|
||||
{
|
||||
$this->initializeGrav();
|
||||
|
||||
$grav = Grav::instance();
|
||||
/** @var Language $language */
|
||||
$language = $grav['language'];
|
||||
if ($language->enabled()) {
|
||||
if ($code && $language->validate($code)) {
|
||||
$language->setActive($code);
|
||||
} else {
|
||||
$language->setActive($language->getDefault());
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properly initialize plugins.
|
||||
*
|
||||
* - call $this->initializeGrav()
|
||||
* - call onPluginsInitialized event
|
||||
*
|
||||
* Safe to be called multiple times.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final protected function initializePlugins()
|
||||
{
|
||||
if (!$this->plugins_initialized) {
|
||||
$this->plugins_initialized = true;
|
||||
|
||||
$this->initializeGrav();
|
||||
|
||||
// Initialize plugins.
|
||||
$grav = Grav::instance();
|
||||
$grav['plugins']->init();
|
||||
$grav->fireEvent('onPluginsInitialized');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properly initialize themes.
|
||||
*
|
||||
* - call $this->initializePlugins()
|
||||
* - initialize theme (call onThemeInitialized event)
|
||||
*
|
||||
* Safe to be called multiple times.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final protected function initializeThemes()
|
||||
{
|
||||
if (!$this->themes_initialized) {
|
||||
$this->themes_initialized = true;
|
||||
|
||||
$this->initializePlugins();
|
||||
|
||||
// Initialize themes.
|
||||
$grav = Grav::instance();
|
||||
$grav['themes']->init();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properly initialize pages.
|
||||
*
|
||||
* - call $this->initializeThemes()
|
||||
* - initialize assets (call onAssetsInitialized event)
|
||||
* - initialize twig (calls the twig events)
|
||||
* - initialize pages (calls onPagesInitialized event)
|
||||
*
|
||||
* Safe to be called multiple times.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final protected function initializePages()
|
||||
{
|
||||
if (!$this->pages_initialized) {
|
||||
$this->pages_initialized = true;
|
||||
|
||||
$this->initializeThemes();
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
// Initialize assets.
|
||||
$grav['assets']->init();
|
||||
$grav->fireEvent('onAssetsInitialized');
|
||||
|
||||
// Initialize twig.
|
||||
$grav['twig']->init();
|
||||
|
||||
// Initialize pages.
|
||||
$pages = $grav['pages'];
|
||||
$pages->init();
|
||||
$grav->fireEvent('onPagesInitialized', new Event(['pages' => $pages]));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function isGravInstance($path)
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!file_exists($path)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("<red>ERROR</red>: Destination doesn't exist:");
|
||||
$this->output->writeln(" <white>$path</white>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln('');
|
||||
$io->writeln("<red>ERROR</red>: Destination doesn't exist:");
|
||||
$io->writeln(" <white>$path</white>");
|
||||
$io->writeln('');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!is_dir($path)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("<red>ERROR</red>: Destination chosen to install is not a directory:");
|
||||
$this->output->writeln(" <white>$path</white>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln('');
|
||||
$io->writeln("<red>ERROR</red>: Destination chosen to install is not a directory:");
|
||||
$io->writeln(" <white>$path</white>");
|
||||
$io->writeln('');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!file_exists($path . DS . 'index.php') || !file_exists($path . DS . '.dependencies') || !file_exists($path . DS . 'system' . DS . 'config' . DS . 'system.yaml')) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("<red>ERROR</red>: Destination chosen to install does not appear to be a Grav instance:");
|
||||
$this->output->writeln(" <white>$path</white>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln('');
|
||||
$io->writeln('<red>ERROR</red>: Destination chosen to install does not appear to be a Grav instance:');
|
||||
$io->writeln(" <white>$path</white>");
|
||||
$io->writeln('');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $action
|
||||
* @return string|false
|
||||
*/
|
||||
public function composerUpdate($path, $action = 'install')
|
||||
{
|
||||
$composer = Composer::getComposerExecutor();
|
||||
@@ -97,9 +293,8 @@ trait ConsoleTrait
|
||||
|
||||
/**
|
||||
* @param array $all
|
||||
*
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clearCache($all = [])
|
||||
{
|
||||
@@ -112,10 +307,18 @@ trait ConsoleTrait
|
||||
return $command->run($input, $this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function invalidateCache()
|
||||
{
|
||||
Cache::invalidateCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the local config file
|
||||
*
|
||||
* @return mixed string the local config file name. false if local config does not exist
|
||||
* @return string|false The local config file name. false if local config does not exist
|
||||
*/
|
||||
public function loadLocalConfig()
|
||||
{
|
||||
@@ -126,6 +329,7 @@ trait ConsoleTrait
|
||||
$file = YamlFile::instance($local_config_file);
|
||||
$this->local_config = $file->content();
|
||||
$file->free();
|
||||
|
||||
return $local_config_file;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Gpm;
|
||||
|
||||
use Exception;
|
||||
use Grav\Common\Cache;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Common\GPM\Response;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GpmCommand;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use ZipArchive;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
|
||||
class DirectInstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class DirectInstallCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class DirectInstallCommand extends GpmCommand
|
||||
{
|
||||
/** @var string */
|
||||
protected $all_yes;
|
||||
/** @var string */
|
||||
protected $destination;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("direct-install")
|
||||
->setName('direct-install')
|
||||
->setAliases(['directinstall'])
|
||||
->addArgument(
|
||||
'package-file',
|
||||
@@ -47,221 +62,261 @@ class DirectInstallCommand extends ConsoleCommand
|
||||
'The destination where the package should be installed at. By default this would be where the grav instance has been launched from',
|
||||
GRAV_ROOT
|
||||
)
|
||||
->setDescription("Installs Grav, plugin, or theme directly from a file or a URL")
|
||||
->setDescription('Installs Grav, plugin, or theme directly from a file or a URL')
|
||||
->setHelp('The <info>direct-install</info> command installs Grav, plugin, or theme directly from a file or a URL');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
// Making sure the destination is usable
|
||||
$this->destination = realpath($this->input->getOption('destination'));
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
if (
|
||||
!Installer::isGravInstance($this->destination) ||
|
||||
!Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK])
|
||||
) {
|
||||
$this->output->writeln("<red>ERROR</red>: " . Installer::lastErrorMsg());
|
||||
exit;
|
||||
if (!class_exists(ZipArchive::class)) {
|
||||
$io->title('Direct Install');
|
||||
$io->error('php-zip extension needs to be enabled!');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Making sure the destination is usable
|
||||
$this->destination = realpath($input->getOption('destination'));
|
||||
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
if (!Installer::isGravInstance($this->destination) ||
|
||||
!Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK])
|
||||
) {
|
||||
$io->writeln('<red>ERROR</red>: ' . Installer::lastErrorMsg());
|
||||
|
||||
$package_file = $this->input->getArgument('package-file');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$helper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion('Are you sure you want to direct-install <cyan>'.$package_file.'</cyan> [y|N] ', false);
|
||||
$this->all_yes = $input->getOption('all-yes');
|
||||
|
||||
$answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question);
|
||||
$package_file = $input->getArgument('package-file');
|
||||
|
||||
$question = new ConfirmationQuestion("Are you sure you want to direct-install <cyan>{$package_file}</cyan> [y|N] ", false);
|
||||
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln("exiting...");
|
||||
$this->output->writeln('');
|
||||
exit;
|
||||
$io->writeln('exiting...');
|
||||
$io->newLine();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
|
||||
$tmp_zip = $tmp_dir . '/Grav-' . uniqid();
|
||||
|
||||
$this->output->writeln("");
|
||||
$this->output->writeln("Preparing to install <cyan>" . $package_file . "</cyan>");
|
||||
$tmp_zip = $tmp_dir . uniqid('/Grav-', false);
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln("Preparing to install <cyan>{$package_file}</cyan>");
|
||||
|
||||
$zip = null;
|
||||
if (Response::isRemote($package_file)) {
|
||||
$this->output->write(" |- Downloading package... 0%");
|
||||
$io->write(' |- Downloading package... 0%');
|
||||
try {
|
||||
$zip = GPM::downloadPackage($package_file, $tmp_zip);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(" `- <red>ERROR: " . $e->getMessage() . "</red>");
|
||||
$this->output->writeln('');
|
||||
exit;
|
||||
} catch (RuntimeException $e) {
|
||||
$io->newLine();
|
||||
$io->writeln(" `- <red>ERROR: {$e->getMessage()}</red>");
|
||||
$io->newLine();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($zip) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->write(" |- Downloading package... 100%");
|
||||
$this->output->writeln('');
|
||||
$io->write("\x0D");
|
||||
$io->write(' |- Downloading package... 100%');
|
||||
$io->newLine();
|
||||
}
|
||||
} else {
|
||||
$this->output->write(" |- Copying package... 0%");
|
||||
} elseif (is_file($package_file)) {
|
||||
$io->write(' |- Copying package... 0%');
|
||||
$zip = GPM::copyPackage($package_file, $tmp_zip);
|
||||
if ($zip) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->write(" |- Copying package... 100%");
|
||||
$this->output->writeln('');
|
||||
$io->write("\x0D");
|
||||
$io->write(' |- Copying package... 100%');
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($zip)) {
|
||||
$tmp_source = $tmp_dir . '/Grav-' . uniqid();
|
||||
if ($zip && file_exists($zip)) {
|
||||
$tmp_source = $tmp_dir . uniqid('/Grav-', false);
|
||||
|
||||
$this->output->write(" |- Extracting package... ");
|
||||
$io->write(' |- Extracting package... ');
|
||||
$extracted = Installer::unZip($zip, $tmp_source);
|
||||
|
||||
if (!$extracted) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Extracting package... <red>failed</red>");
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Extracting package... <red>failed</red>');
|
||||
Folder::delete($tmp_source);
|
||||
Folder::delete($tmp_zip);
|
||||
exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Extracting package... <green>ok</green>");
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Extracting package... <green>ok</green>');
|
||||
|
||||
|
||||
$type = GPM::getPackageType($extracted);
|
||||
|
||||
if (!$type) {
|
||||
$this->output->writeln(" '- <red>ERROR: Not a valid Grav package</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>ERROR: Not a valid Grav package</red>");
|
||||
$io->newLine();
|
||||
Folder::delete($tmp_source);
|
||||
Folder::delete($tmp_zip);
|
||||
exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$blueprint = GPM::getBlueprints($extracted);
|
||||
if ($blueprint) {
|
||||
if (isset($blueprint['dependencies'])) {
|
||||
$depencencies = [];
|
||||
$dependencies = [];
|
||||
foreach ($blueprint['dependencies'] as $dependency) {
|
||||
if (is_array($dependency)){
|
||||
if (isset($dependency['name'])) {
|
||||
$depencencies[] = $dependency['name'];
|
||||
}
|
||||
if (isset($dependency['github'])) {
|
||||
$depencencies[] = $dependency['github'];
|
||||
}
|
||||
if (is_array($dependency)) {
|
||||
if (isset($dependency['name'])) {
|
||||
$dependencies[] = $dependency['name'];
|
||||
}
|
||||
if (isset($dependency['github'])) {
|
||||
$dependencies[] = $dependency['github'];
|
||||
}
|
||||
} else {
|
||||
$depencencies[] = $dependency;
|
||||
$dependencies[] = $dependency;
|
||||
}
|
||||
}
|
||||
$this->output->writeln(" |- Dependencies found... <cyan>[" . implode(',', $depencencies) . "]</cyan>");
|
||||
$io->writeln(' |- Dependencies found... <cyan>[' . implode(',', $dependencies) . ']</cyan>');
|
||||
|
||||
$question = new ConfirmationQuestion(" | '- Dependencies will not be satisfied. Continue ? [y|N] ", false);
|
||||
$answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question);
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln("exiting...");
|
||||
$this->output->writeln('');
|
||||
$io->writeln('exiting...');
|
||||
$io->newLine();
|
||||
Folder::delete($tmp_source);
|
||||
Folder::delete($tmp_zip);
|
||||
exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == 'grav') {
|
||||
|
||||
$this->output->write(" |- Checking destination... ");
|
||||
if ($type === 'grav') {
|
||||
$io->write(' |- Checking destination... ');
|
||||
Installer::isValidDestination(GRAV_ROOT . '/system');
|
||||
if (Installer::IS_LINK === Installer::lastErrorCode()) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <yellow>symbolic link</yellow>");
|
||||
$this->output->writeln(" '- <red>ERROR: symlinks found...</red> <yellow>" . GRAV_ROOT."</yellow>");
|
||||
$this->output->writeln('');
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <yellow>symbolic link</yellow>');
|
||||
$io->writeln(" '- <red>ERROR: symlinks found...</red> <yellow>" . GRAV_ROOT . '</yellow>');
|
||||
$io->newLine();
|
||||
Folder::delete($tmp_source);
|
||||
Folder::delete($tmp_zip);
|
||||
exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <green>ok</green>");
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <green>ok</green>');
|
||||
|
||||
$this->output->write(" |- Installing package... ");
|
||||
Installer::install($zip, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true], $extracted);
|
||||
$io->write(' |- Installing package... ');
|
||||
|
||||
$this->upgradeGrav($zip, $extracted);
|
||||
} else {
|
||||
$name = GPM::getPackageName($extracted);
|
||||
|
||||
if (!$name) {
|
||||
$this->output->writeln("<red>ERROR: Name could not be determined.</red> Please specify with --name|-n");
|
||||
$this->output->writeln('');
|
||||
$io->writeln('<red>ERROR: Name could not be determined.</red> Please specify with --name|-n');
|
||||
$io->newLine();
|
||||
Folder::delete($tmp_source);
|
||||
Folder::delete($tmp_zip);
|
||||
exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$install_path = GPM::getInstallPath($type, $name);
|
||||
$is_update = file_exists($install_path);
|
||||
|
||||
$this->output->write(" |- Checking destination... ");
|
||||
$io->write(' |- Checking destination... ');
|
||||
|
||||
Installer::isValidDestination(GRAV_ROOT . DS . $install_path);
|
||||
if (Installer::lastErrorCode() == Installer::IS_LINK) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <yellow>symbolic link</yellow>");
|
||||
$this->output->writeln(" '- <red>ERROR: symlink found...</red> <yellow>" . GRAV_ROOT . DS . $install_path . '</yellow>');
|
||||
$this->output->writeln('');
|
||||
if (Installer::lastErrorCode() === Installer::IS_LINK) {
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <yellow>symbolic link</yellow>');
|
||||
$io->writeln(" '- <red>ERROR: symlink found...</red> <yellow>" . GRAV_ROOT . DS . $install_path . '</yellow>');
|
||||
$io->newLine();
|
||||
Folder::delete($tmp_source);
|
||||
Folder::delete($tmp_zip);
|
||||
exit;
|
||||
|
||||
} else {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <green>ok</green>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->write(" |- Installing package... ");
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <green>ok</green>');
|
||||
|
||||
$io->write(' |- Installing package... ');
|
||||
|
||||
Installer::install(
|
||||
$zip,
|
||||
$this->destination,
|
||||
$options = [
|
||||
'install_path' => $install_path,
|
||||
'theme' => (($type == 'theme')),
|
||||
'theme' => (($type === 'theme')),
|
||||
'is_update' => $is_update
|
||||
],
|
||||
$extracted
|
||||
);
|
||||
|
||||
// clear cache after successful upgrade
|
||||
$this->clearCache();
|
||||
}
|
||||
|
||||
Folder::delete($tmp_source);
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$io->write("\x0D");
|
||||
|
||||
if(Installer::lastErrorCode()) {
|
||||
$this->output->writeln(" '- <red>" . Installer::lastErrorMsg() . "</red>");
|
||||
$this->output->writeln('');
|
||||
if (Installer::lastErrorCode()) {
|
||||
$io->writeln(" '- <red>" . Installer::lastErrorMsg() . '</red>');
|
||||
$io->newLine();
|
||||
} else {
|
||||
$this->output->writeln(" |- Installing package... <green>ok</green>");
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(' |- Installing package... <green>ok</green>');
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->output->writeln(" '- <red>ERROR: ZIP package could not be found</red>");
|
||||
$io->writeln(" '- <red>ERROR: ZIP package could not be found</red>");
|
||||
Folder::delete($tmp_zip);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Folder::delete($tmp_zip);
|
||||
|
||||
// clear cache after successful upgrade
|
||||
$this->clearCache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
/**
|
||||
* @param string $zip
|
||||
* @param string $folder
|
||||
* @return void
|
||||
*/
|
||||
private function upgradeGrav(string $zip, string $folder): void
|
||||
{
|
||||
if (!is_dir($folder)) {
|
||||
Installer::setError('Invalid source folder');
|
||||
}
|
||||
|
||||
try {
|
||||
$script = $folder . '/system/install.php';
|
||||
/** Install $installer */
|
||||
if ((file_exists($script) && $install = include $script) && is_callable($install)) {
|
||||
$install($zip);
|
||||
} else {
|
||||
throw new RuntimeException('Uploaded archive file is not a valid Grav update package');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Installer::setError($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Gpm;
|
||||
|
||||
use Grav\Common\GPM\Remote\AbstractPackageCollection;
|
||||
use Grav\Common\GPM\Remote\Package;
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Remote\Packages;
|
||||
use Grav\Common\GPM\Remote\Plugins;
|
||||
use Grav\Common\GPM\Remote\Themes;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use League\CLImate\CLImate;
|
||||
use Grav\Console\GpmCommand;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use function count;
|
||||
|
||||
class IndexCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class IndexCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class IndexCommand extends GpmCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var Packages */
|
||||
protected $data;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var GPM */
|
||||
protected $gpm;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var array */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @return void
|
||||
*/
|
||||
protected $sortKeys = ['name', 'slug', 'author', 'date'];
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("index")
|
||||
->setName('index')
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
@@ -81,9 +80,9 @@ class IndexCommand extends ConsoleCommand
|
||||
->addOption(
|
||||
'sort',
|
||||
's',
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Allows to sort (ASC) the results based on one or multiple keys. SORT can be either "name", "slug", "author", "date"',
|
||||
['date']
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Allows to sort (ASC) the results. SORT can be either "name", "slug", "author", "date"',
|
||||
'date'
|
||||
)
|
||||
->addOption(
|
||||
'desc',
|
||||
@@ -91,117 +90,154 @@ class IndexCommand extends ConsoleCommand
|
||||
InputOption::VALUE_NONE,
|
||||
'Reverses the order of the output.'
|
||||
)
|
||||
->setDescription("Lists the plugins and themes available for installation")
|
||||
->addOption(
|
||||
'enabled',
|
||||
'e',
|
||||
InputOption::VALUE_NONE,
|
||||
'Filters the results to only enabled Themes and Plugins.'
|
||||
)
|
||||
->addOption(
|
||||
'disabled',
|
||||
'd',
|
||||
InputOption::VALUE_NONE,
|
||||
'Filters the results to only disabled Themes and Plugins.'
|
||||
)
|
||||
->setDescription('Lists the plugins and themes available for installation')
|
||||
->setHelp('The <info>index</info> command lists the plugins and themes available for installation')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->options = $this->input->getOptions();
|
||||
$input = $this->getInput();
|
||||
$this->options = $input->getOptions();
|
||||
$this->gpm = new GPM($this->options['force']);
|
||||
$this->displayGPMRelease();
|
||||
$this->data = $this->gpm->getRepository();
|
||||
|
||||
$data = $this->filter($this->data);
|
||||
|
||||
$climate = new CLImate;
|
||||
$climate->extend('Grav\Console\TerminalObjects\Table');
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!$data) {
|
||||
$this->output->writeln('No data was found in the GPM repository stored locally.');
|
||||
$this->output->writeln('Please try clearing cache and running the <green>bin/gpm index -f</green> command again');
|
||||
$this->output->writeln('If this doesn\'t work try tweaking your GPM system settings.');
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('For more help go to:');
|
||||
$this->output->writeln(' -> <yellow>https://learn.getgrav.org/troubleshooting/common-problems#cannot-connect-to-the-gpm</yellow>');
|
||||
if (count($data) === 0) {
|
||||
$io->writeln('No data was found in the GPM repository stored locally.');
|
||||
$io->writeln('Please try clearing cache and running the <green>bin/gpm index -f</green> command again');
|
||||
$io->writeln('If this doesn\'t work try tweaking your GPM system settings.');
|
||||
$io->newLine();
|
||||
$io->writeln('For more help go to:');
|
||||
$io->writeln(' -> <yellow>https://learn.getgrav.org/troubleshooting/common-problems#cannot-connect-to-the-gpm</yellow>');
|
||||
|
||||
die;
|
||||
return 1;
|
||||
}
|
||||
|
||||
foreach ($data as $type => $packages) {
|
||||
$this->output->writeln("<green>" . strtoupper($type) . "</green> [ " . count($packages) . " ]");
|
||||
$io->writeln('<green>' . strtoupper($type) . '</green> [ ' . count($packages) . ' ]');
|
||||
|
||||
$packages = $this->sort($packages);
|
||||
|
||||
if (!empty($packages)) {
|
||||
$io->section('Packages table');
|
||||
$table = new Table($io);
|
||||
$table->setHeaders(['Count', 'Name', 'Slug', 'Version', 'Installed', 'Enabled']);
|
||||
|
||||
$table = [];
|
||||
$index = 0;
|
||||
|
||||
$index = 0;
|
||||
foreach ($packages as $slug => $package) {
|
||||
$row = [
|
||||
'Count' => $index++ + 1,
|
||||
'Name' => "<cyan>" . Utils::truncate($package->name, 20, false, ' ', '...') . "</cyan> ",
|
||||
'Name' => '<cyan>' . Utils::truncate($package->name, 20, false, ' ', '...') . '</cyan> ',
|
||||
'Slug' => $slug,
|
||||
'Version'=> $this->version($package),
|
||||
'Installed' => $this->installed($package)
|
||||
'Installed' => $this->installed($package),
|
||||
'Enabled' => $this->enabled($package),
|
||||
];
|
||||
$table[] = $row;
|
||||
|
||||
$table->addRow($row);
|
||||
}
|
||||
|
||||
$climate->table($table);
|
||||
$table->render();
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
$this->output->writeln('You can either get more informations about a package by typing:');
|
||||
$this->output->writeln(' <green>' . $this->argv . ' info <cyan><package></cyan></green>');
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('Or you can install a package by typing:');
|
||||
$this->output->writeln(' <green>' . $this->argv . ' install <cyan><package></cyan></green>');
|
||||
$this->output->writeln('');
|
||||
$io->writeln('You can either get more informations about a package by typing:');
|
||||
$io->writeln(" <green>{$this->argv} info <cyan><package></cyan></green>");
|
||||
$io->newLine();
|
||||
$io->writeln('Or you can install a package by typing:');
|
||||
$io->writeln(" <green>{$this->argv} install <cyan><package></cyan></green>");
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
*
|
||||
* @param Package $package
|
||||
* @return string
|
||||
*/
|
||||
private function version($package)
|
||||
private function version(Package $package): string
|
||||
{
|
||||
$list = $this->gpm->{'getUpdatable' . ucfirst($package->package_type)}();
|
||||
$package = isset($list[$package->slug]) ? $list[$package->slug] : $package;
|
||||
$type = ucfirst(preg_replace("/s$/", '', $package->package_type));
|
||||
$package = $list[$package->slug] ?? $package;
|
||||
$type = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
$updatable = $this->gpm->{'is' . $type . 'Updatable'}($package->slug);
|
||||
$installed = $this->gpm->{'is' . $type . 'Installed'}($package->slug);
|
||||
$local = $this->gpm->{'getInstalled' . $type}($package->slug);
|
||||
|
||||
if (!$installed || !$updatable) {
|
||||
$version = $installed ? $local->version : $package->version;
|
||||
return "v<green>" . $version . "</green>";
|
||||
return "v<green>{$version}</green>";
|
||||
}
|
||||
|
||||
if ($updatable) {
|
||||
return "v<red>" . $package->version . "</red> <cyan>-></cyan> v<green>" . $package->available . "</green>";
|
||||
}
|
||||
|
||||
return '';
|
||||
return "v<red>{$package->version}</red> <cyan>-></cyan> v<green>{$package->available}</green>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
*
|
||||
* @param Package $package
|
||||
* @return string
|
||||
*/
|
||||
private function installed($package)
|
||||
private function installed(Package $package): string
|
||||
{
|
||||
$package = isset($list[$package->slug]) ? $list[$package->slug] : $package;
|
||||
$type = ucfirst(preg_replace("/s$/", '', $package->package_type));
|
||||
$installed = $this->gpm->{'is' . $type . 'Installed'}($package->slug);
|
||||
$package = $list[$package->slug] ?? $package;
|
||||
$type = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
$method = 'is' . $type . 'Installed';
|
||||
$installed = $this->gpm->{$method}($package->slug);
|
||||
|
||||
return !$installed ? '<magenta>not installed</magenta>' : '<cyan>installed</cyan>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return mixed
|
||||
* @param Package $package
|
||||
* @return string
|
||||
*/
|
||||
public function filter($data)
|
||||
private function enabled(Package $package): string
|
||||
{
|
||||
$package = $list[$package->slug] ?? $package;
|
||||
$type = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
$method = 'is' . $type . 'Installed';
|
||||
$installed = $this->gpm->{$method}($package->slug);
|
||||
|
||||
$result = '';
|
||||
if ($installed) {
|
||||
$method = 'is' . $type . 'Enabled';
|
||||
$enabled = $this->gpm->{$method}($package->slug);
|
||||
if ($enabled === true) {
|
||||
$result = '<cyan>enabled</cyan>';
|
||||
} elseif ($enabled === false) {
|
||||
$result = '<red>disabled</red>';
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Packages $data
|
||||
* @return Packages
|
||||
*/
|
||||
public function filter(Packages $data): Packages
|
||||
{
|
||||
// filtering and sorting
|
||||
if ($this->options['plugins-only']) {
|
||||
@@ -212,10 +248,12 @@ class IndexCommand extends ConsoleCommand
|
||||
}
|
||||
|
||||
$filter = [
|
||||
$this->options['desc'],
|
||||
$this->options['disabled'],
|
||||
$this->options['enabled'],
|
||||
$this->options['filter'],
|
||||
$this->options['installed-only'],
|
||||
$this->options['updates-only'],
|
||||
$this->options['desc']
|
||||
];
|
||||
|
||||
if (count(array_filter($filter))) {
|
||||
@@ -225,19 +263,44 @@ class IndexCommand extends ConsoleCommand
|
||||
|
||||
// Filtering by string
|
||||
if ($this->options['filter']) {
|
||||
$filter = preg_grep('/(' . (implode('|', $this->options['filter'])) . ')/i', [$slug, $package->name]);
|
||||
$filter = preg_grep('/(' . implode('|', $this->options['filter']) . ')/i', [$slug, $package->name]);
|
||||
}
|
||||
|
||||
// Filtering updatables only
|
||||
if ($this->options['installed-only'] && $filter) {
|
||||
$method = ucfirst(preg_replace("/s$/", '', $package->package_type));
|
||||
$filter = $this->gpm->{'is' . $method . 'Installed'}($package->slug);
|
||||
if ($filter && ($this->options['installed-only'] || $this->options['enabled'] || $this->options['disabled'])) {
|
||||
$method = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
$function = 'is' . $method . 'Installed';
|
||||
$filter = $this->gpm->{$function}($package->slug);
|
||||
}
|
||||
|
||||
// Filtering updatables only
|
||||
if ($this->options['updates-only'] && $filter) {
|
||||
$method = ucfirst(preg_replace("/s$/", '', $package->package_type));
|
||||
$filter = $this->gpm->{'is' . $method . 'Updatable'}($package->slug);
|
||||
if ($filter && $this->options['updates-only']) {
|
||||
$method = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
$function = 'is' . $method . 'Updatable';
|
||||
$filter = $this->gpm->{$function}($package->slug);
|
||||
}
|
||||
|
||||
// Filtering enabled only
|
||||
if ($filter && $this->options['enabled']) {
|
||||
$method = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
|
||||
// Check if packaged is enabled.
|
||||
$function = 'is' . $method . 'Enabled';
|
||||
$filter = $this->gpm->{$function}($package->slug);
|
||||
}
|
||||
|
||||
// Filtering disabled only
|
||||
if ($filter && $this->options['disabled']) {
|
||||
$method = ucfirst(preg_replace('/s$/', '', $package->package_type));
|
||||
|
||||
// Check if package is disabled.
|
||||
$function = 'is' . $method . 'Enabled';
|
||||
$enabled_filter = $this->gpm->{$function}($package->slug);
|
||||
|
||||
// Apply filtering results.
|
||||
if (!( $enabled_filter === false)) {
|
||||
$filter = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$filter) {
|
||||
@@ -251,22 +314,24 @@ class IndexCommand extends ConsoleCommand
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $packages
|
||||
* @param AbstractPackageCollection|Plugins|Themes $packages
|
||||
* @return array
|
||||
*/
|
||||
public function sort($packages)
|
||||
public function sort(AbstractPackageCollection $packages): array
|
||||
{
|
||||
foreach ($this->options['sort'] as $key) {
|
||||
$packages = $packages->sort(function ($a, $b) use ($key) {
|
||||
$key = $this->options['sort'];
|
||||
|
||||
// Sorting only works once.
|
||||
return $packages->sort(
|
||||
function ($a, $b) use ($key) {
|
||||
switch ($key) {
|
||||
case 'author':
|
||||
return strcmp($a->{$key}['name'], $b->{$key}['name']);
|
||||
break;
|
||||
default:
|
||||
return strcmp($a->$key, $b->$key);
|
||||
}
|
||||
}, $this->options['desc'] ? true : false);
|
||||
}
|
||||
|
||||
return $packages;
|
||||
},
|
||||
$this->options['desc'] ? true : false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Gpm;
|
||||
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GpmCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use function strlen;
|
||||
|
||||
class InfoCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class InfoCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class InfoCommand extends GpmCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var array */
|
||||
protected $data;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var GPM */
|
||||
protected $gpm;
|
||||
|
||||
/** @var string */
|
||||
protected $all_yes;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("info")
|
||||
->setName('info')
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
@@ -51,46 +53,52 @@ class InfoCommand extends ConsoleCommand
|
||||
InputArgument::REQUIRED,
|
||||
'The package of which more informations are desired. Use the "index" command for a list of packages'
|
||||
)
|
||||
->setDescription("Shows more informations about a package")
|
||||
->setHelp('The <info>info</info> shows more informations about a package');
|
||||
->setDescription('Shows more informations about a package')
|
||||
->setHelp('The <info>info</info> shows more information about a package');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->gpm = new GPM($this->input->getOption('force'));
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
$this->gpm = new GPM($input->getOption('force'));
|
||||
|
||||
$this->all_yes = $input->getOption('all-yes');
|
||||
|
||||
$this->displayGPMRelease();
|
||||
|
||||
$foundPackage = $this->gpm->findPackage($this->input->getArgument('package'));
|
||||
$foundPackage = $this->gpm->findPackage($input->getArgument('package'));
|
||||
|
||||
if (!$foundPackage) {
|
||||
$this->output->writeln("The package <cyan>'" . $this->input->getArgument('package') . "'</cyan> was not found in the Grav repository.");
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("You can list all the available packages by typing:");
|
||||
$this->output->writeln(" <green>" . $this->argv . " index</green>");
|
||||
$this->output->writeln('');
|
||||
exit;
|
||||
$io->writeln("The package <cyan>'{$input->getArgument('package')}'</cyan> was not found in the Grav repository.");
|
||||
$io->newLine();
|
||||
$io->writeln('You can list all the available packages by typing:');
|
||||
$io->writeln(" <green>{$this->argv} index</green>");
|
||||
$io->newLine();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->writeln("Found package <cyan>'" . $this->input->getArgument('package') . "'</cyan> under the '<green>" . ucfirst($foundPackage->package_type) . "</green>' section");
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("<cyan>" . $foundPackage->name . "</cyan> [" . $foundPackage->slug . "]");
|
||||
$this->output->writeln(str_repeat('-', strlen($foundPackage->name) + strlen($foundPackage->slug) + 3));
|
||||
$this->output->writeln("<white>" . strip_tags($foundPackage->description_plain) . "</white>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln("Found package <cyan>'{$input->getArgument('package')}'</cyan> under the '<green>" . ucfirst($foundPackage->package_type) . "</green>' section");
|
||||
$io->newLine();
|
||||
$io->writeln("<cyan>{$foundPackage->name}</cyan> [{$foundPackage->slug}]");
|
||||
$io->writeln(str_repeat('-', strlen($foundPackage->name) + strlen($foundPackage->slug) + 3));
|
||||
$io->writeln('<white>' . strip_tags($foundPackage->description_plain) . '</white>');
|
||||
$io->newLine();
|
||||
|
||||
$packageURL = '';
|
||||
if (isset($foundPackage->author['url'])) {
|
||||
$packageURL = '<' . $foundPackage->author['url'] . '>';
|
||||
}
|
||||
|
||||
$this->output->writeln("<green>" . str_pad("Author",
|
||||
12) . ":</green> " . $foundPackage->author['name'] . ' <' . $foundPackage->author['email'] . '> ' . $packageURL);
|
||||
$io->writeln('<green>' . str_pad(
|
||||
'Author',
|
||||
12
|
||||
) . ':</green> ' . $foundPackage->author['name'] . ' <' . $foundPackage->author['email'] . '> ' . $packageURL);
|
||||
|
||||
foreach ([
|
||||
'version',
|
||||
@@ -105,21 +113,21 @@ class InfoCommand extends ConsoleCommand
|
||||
'zipball_url',
|
||||
'license'
|
||||
] as $info) {
|
||||
if (isset($foundPackage->$info)) {
|
||||
if (isset($foundPackage->{$info})) {
|
||||
$name = ucfirst($info);
|
||||
$data = $foundPackage->$info;
|
||||
$data = $foundPackage->{$info};
|
||||
|
||||
if ($info == 'zipball_url') {
|
||||
$name = "Download";
|
||||
if ($info === 'zipball_url') {
|
||||
$name = 'Download';
|
||||
}
|
||||
|
||||
if ($info == 'date') {
|
||||
$name = "Last Update";
|
||||
$data = date('D, j M Y, H:i:s, P ', strtotime('2014-09-16T00:07:16Z'));
|
||||
if ($info === 'date') {
|
||||
$name = 'Last Update';
|
||||
$data = date('D, j M Y, H:i:s, P ', strtotime($data));
|
||||
}
|
||||
|
||||
$name = str_pad($name, 12);
|
||||
$this->output->writeln("<green>" . $name . ":</green> " . $data);
|
||||
$io->writeln("<green>{$name}:</green> {$data}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,52 +138,54 @@ class InfoCommand extends ConsoleCommand
|
||||
// display current version if installed and different
|
||||
if ($installed && $updatable) {
|
||||
$local = $this->gpm->{'getInstalled'. $type}($foundPackage->slug);
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("Currently installed version: <magenta>" . $local->version . "</magenta>");
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
$io->writeln("Currently installed version: <magenta>{$local->version}</magenta>");
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
// display changelog information
|
||||
$questionHelper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion("Would you like to read the changelog? [y|N] ",
|
||||
false);
|
||||
$answer = $this->all_yes ? true : $questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion(
|
||||
'Would you like to read the changelog? [y|N] ',
|
||||
false
|
||||
);
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if ($answer) {
|
||||
$changelog = $foundPackage->changelog;
|
||||
|
||||
$this->output->writeln("");
|
||||
$io->newLine();
|
||||
foreach ($changelog as $version => $log) {
|
||||
$title = $version . ' [' . $log['date'] . ']';
|
||||
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', function ($match) {
|
||||
return "\n" . ucfirst($match[1]) . ":";
|
||||
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', static function ($match) {
|
||||
return "\n" . ucfirst($match[1]) . ':';
|
||||
}, $log['content']);
|
||||
|
||||
$this->output->writeln('<cyan>'.$title.'</cyan>');
|
||||
$this->output->writeln(str_repeat('-', strlen($title)));
|
||||
$this->output->writeln($content);
|
||||
$this->output->writeln("");
|
||||
$io->writeln("<cyan>{$title}</cyan>");
|
||||
$io->writeln(str_repeat('-', strlen($title)));
|
||||
$io->writeln($content);
|
||||
$io->newLine();
|
||||
|
||||
$question = new ConfirmationQuestion("Press [ENTER] to continue or [q] to quit ", true);
|
||||
$answer = $this->all_yes ? false : $questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion('Press [ENTER] to continue or [q] to quit ', true);
|
||||
$answer = $this->all_yes ? false : $io->askQuestion($question);
|
||||
if (!$answer) {
|
||||
break;
|
||||
}
|
||||
$this->output->writeln("");
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
|
||||
if ($installed && $updatable) {
|
||||
$this->output->writeln("You can update this package by typing:");
|
||||
$this->output->writeln(" <green>" . $this->argv . " update</green> <cyan>" . $foundPackage->slug . "</cyan>");
|
||||
$io->writeln('You can update this package by typing:');
|
||||
$io->writeln(" <green>{$this->argv} update</green> <cyan>{$foundPackage->slug}</cyan>");
|
||||
} else {
|
||||
$this->output->writeln("You can install this package by typing:");
|
||||
$this->output->writeln(" <green>" . $this->argv . " install</green> <cyan>" . $foundPackage->slug . "</cyan>");
|
||||
$io->writeln('You can install this package by typing:');
|
||||
$io->writeln(" <green>{$this->argv} install</green> <cyan>{$foundPackage->slug}</cyan>");
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +1,64 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Gpm;
|
||||
|
||||
use Exception;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Common\GPM\Licenses;
|
||||
use Grav\Common\GPM\Response;
|
||||
use Grav\Common\GPM\Remote\Package as Package;
|
||||
use Grav\Common\GPM\Remote\Package;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GpmCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use ZipArchive;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function define;
|
||||
|
||||
define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/(.*)/');
|
||||
|
||||
class InstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class InstallCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class InstallCommand extends GpmCommand
|
||||
{
|
||||
/** @var */
|
||||
/** @var array */
|
||||
protected $data;
|
||||
|
||||
/** @var GPM */
|
||||
protected $gpm;
|
||||
|
||||
/** @var */
|
||||
/** @var string */
|
||||
protected $destination;
|
||||
|
||||
/** @var */
|
||||
/** @var string */
|
||||
protected $file;
|
||||
|
||||
/** @var */
|
||||
/** @var string */
|
||||
protected $tmp;
|
||||
|
||||
/** @var */
|
||||
protected $local_config;
|
||||
|
||||
/** @var bool */
|
||||
protected $use_symlinks;
|
||||
|
||||
/** @var array */
|
||||
protected $demo_processing = [];
|
||||
|
||||
/** @var string */
|
||||
protected $all_yes;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("install")
|
||||
->setName('install')
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
@@ -82,100 +83,110 @@ class InstallCommand extends ConsoleCommand
|
||||
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
|
||||
'Package(s) to install. Use "bin/gpm index" to list packages. Use "bin/gpm direct-install" to install a specific version'
|
||||
)
|
||||
->setDescription("Performs the installation of plugins and themes")
|
||||
->setDescription('Performs the installation of plugins and themes')
|
||||
->setHelp('The <info>install</info> command allows to install plugins and themes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set the GPM object, used for testing the class
|
||||
*
|
||||
* @param $gpm
|
||||
* @param GPM $gpm
|
||||
*/
|
||||
public function setGpm($gpm)
|
||||
public function setGpm(GPM $gpm): void
|
||||
{
|
||||
$this->gpm = $gpm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->gpm = new GPM($this->input->getOption('force'));
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
if (!class_exists(ZipArchive::class)) {
|
||||
$io->title('GPM Install');
|
||||
$io->error('php-zip extension needs to be enabled!');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->gpm = new GPM($input->getOption('force'));
|
||||
|
||||
$this->all_yes = $input->getOption('all-yes');
|
||||
|
||||
$this->displayGPMRelease();
|
||||
|
||||
$this->destination = realpath($this->input->getOption('destination'));
|
||||
$this->destination = realpath($input->getOption('destination'));
|
||||
|
||||
$packages = array_map('strtolower', $this->input->getArgument('package'));
|
||||
$packages = array_map('strtolower', $input->getArgument('package'));
|
||||
$this->data = $this->gpm->findPackages($packages);
|
||||
$this->loadLocalConfig();
|
||||
|
||||
if (
|
||||
!Installer::isGravInstance($this->destination) ||
|
||||
if (!Installer::isGravInstance($this->destination) ||
|
||||
!Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK])
|
||||
) {
|
||||
$this->output->writeln("<red>ERROR</red>: " . Installer::lastErrorMsg());
|
||||
exit;
|
||||
$io->writeln('<red>ERROR</red>: ' . Installer::lastErrorMsg());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
|
||||
if (!$this->data['total']) {
|
||||
$this->output->writeln("Nothing to install.");
|
||||
$this->output->writeln('');
|
||||
exit;
|
||||
$io->writeln('Nothing to install.');
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->data['not_found'])) {
|
||||
$this->output->writeln("These packages were not found on Grav: <red>" . implode('</red>, <red>',
|
||||
array_keys($this->data['not_found'])) . "</red>");
|
||||
$io->writeln('These packages were not found on Grav: <red>' . implode(
|
||||
'</red>, <red>',
|
||||
array_keys($this->data['not_found'])
|
||||
) . '</red>');
|
||||
}
|
||||
|
||||
unset($this->data['not_found']);
|
||||
unset($this->data['total']);
|
||||
unset($this->data['not_found'], $this->data['total']);
|
||||
|
||||
|
||||
if (isset($this->local_config)) {
|
||||
if (null !== $this->local_config) {
|
||||
// Symlinks available, ask if Grav should use them
|
||||
$this->use_symlinks = false;
|
||||
$helper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion('Should Grav use the symlinks if available? [y|N] ', false);
|
||||
|
||||
$answer = $this->all_yes ? false : $helper->ask($this->input, $this->output, $question);
|
||||
$answer = $this->all_yes ? false : $io->askQuestion($question);
|
||||
|
||||
if ($answer) {
|
||||
$this->use_symlinks = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
|
||||
try {
|
||||
$dependencies = $this->gpm->getDependencies($packages);
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
//Error out if there are incompatible packages requirements and tell which ones, and what to do
|
||||
//Error out if there is any error in parsing the dependencies and their versions, and tell which one is broken
|
||||
$this->output->writeln("<red>" . $e->getMessage() . "</red>");
|
||||
return false;
|
||||
$io->writeln("<red>{$e->getMessage()}</red>");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($dependencies) {
|
||||
try {
|
||||
$this->installDependencies($dependencies, 'install', "The following dependencies need to be installed...");
|
||||
$this->installDependencies($dependencies, 'update', "The following dependencies need to be updated...");
|
||||
$this->installDependencies($dependencies, 'ignore', "The following dependencies can be updated as there is a newer version, but it's not mandatory...", false);
|
||||
} catch (\Exception $e) {
|
||||
$this->output->writeln("<red>Installation aborted</red>");
|
||||
return false;
|
||||
$this->installDependencies($dependencies, 'install', 'The following dependencies need to be installed...');
|
||||
$this->installDependencies($dependencies, 'update', 'The following dependencies need to be updated...');
|
||||
$this->installDependencies($dependencies, 'ignore', "The following dependencies can be updated as there is a newer version, but it's not mandatory...", false);
|
||||
} catch (Exception $e) {
|
||||
$io->writeln('<red>Installation aborted</red>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->output->writeln("<green>Dependencies are OK</green>");
|
||||
$this->output->writeln("");
|
||||
$io->writeln('<green>Dependencies are OK</green>');
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
|
||||
@@ -183,36 +194,35 @@ class InstallCommand extends ConsoleCommand
|
||||
foreach ($this->data as $data) {
|
||||
foreach ($data as $package_name => $package) {
|
||||
if (array_key_exists($package_name, $dependencies)) {
|
||||
$this->output->writeln("<green>Package " . $package_name . " already installed as dependency</green>");
|
||||
$io->writeln("<green>Package {$package_name} already installed as dependency</green>");
|
||||
} else {
|
||||
$is_valid_destination = Installer::isValidDestination($this->destination . DS . $package->install_path);
|
||||
if ($is_valid_destination || Installer::lastErrorCode() == Installer::NOT_FOUND) {
|
||||
$this->processPackage($package, false);
|
||||
} else {
|
||||
if (Installer::lastErrorCode() == Installer::EXISTS) {
|
||||
|
||||
try {
|
||||
$this->askConfirmationIfMajorVersionUpdated($package);
|
||||
$this->gpm->checkNoOtherPackageNeedsThisDependencyInALowerVersion($package->slug, $package->available, array_keys($data));
|
||||
} catch (\Exception $e) {
|
||||
$this->output->writeln("<red>" . $e->getMessage() . "</red>");
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
$io->writeln("<red>{$e->getMessage()}</red>");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$helper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion("The package <cyan>$package_name</cyan> is already installed, overwrite? [y|N] ", false);
|
||||
$answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion("The package <cyan>{$package_name}</cyan> is already installed, overwrite? [y|N] ", false);
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if ($answer) {
|
||||
$is_update = true;
|
||||
$this->processPackage($package, $is_update);
|
||||
} else {
|
||||
$this->output->writeln("<yellow>Package " . $package_name . " not overwritten</yellow>");
|
||||
$io->writeln("<yellow>Package {$package_name} not overwritten</yellow>");
|
||||
}
|
||||
} else {
|
||||
if (Installer::lastErrorCode() == Installer::IS_LINK) {
|
||||
$this->output->writeln("<red>Cannot overwrite existing symlink for </red><cyan>$package_name</cyan>");
|
||||
$this->output->writeln("");
|
||||
$io->writeln("<red>Cannot overwrite existing symlink for </red><cyan>{$package_name}</cyan>");
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,33 +239,34 @@ class InstallCommand extends ConsoleCommand
|
||||
// clear cache after successful upgrade
|
||||
$this->clearCache();
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the package is updated from an older major release, show warning and ask confirmation
|
||||
*
|
||||
* @param $package
|
||||
* @param Package $package
|
||||
* @return void
|
||||
*/
|
||||
public function askConfirmationIfMajorVersionUpdated($package)
|
||||
public function askConfirmationIfMajorVersionUpdated(Package $package): void
|
||||
{
|
||||
$helper = $this->getHelper('question');
|
||||
$io = $this->getIO();
|
||||
$package_name = $package->name;
|
||||
$new_version = $package->available ? $package->available : $this->gpm->getLatestVersionOfPackage($package->slug);
|
||||
$new_version = $package->available ?: $this->gpm->getLatestVersionOfPackage($package->slug);
|
||||
$old_version = $package->version;
|
||||
|
||||
$major_version_changed = explode('.', $new_version)[0] !== explode('.', $old_version)[0];
|
||||
|
||||
if ($major_version_changed) {
|
||||
if ($this->all_yes) {
|
||||
$this->output->writeln("The package <cyan>$package_name</cyan> will be updated to a new major version <green>$new_version</green>, from <magenta>$old_version</magenta>");
|
||||
$io->writeln("The package <cyan>{$package_name}</cyan> will be updated to a new major version <green>{$new_version}</green>, from <magenta>{$old_version}</magenta>");
|
||||
return;
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion("The package <cyan>$package_name</cyan> will be updated to a new major version <green>$new_version</green>, from <magenta>$old_version</magenta>. Be sure to read what changed with the new major release. Continue? [y|N] ", false);
|
||||
$question = new ConfirmationQuestion("The package <cyan>{$package_name}</cyan> will be updated to a new major version <green>{$new_version}</green>, from <magenta>{$old_version}</magenta>. Be sure to read what changed with the new major release. Continue? [y|N] ", false);
|
||||
|
||||
if (!$helper->ask($this->input, $this->output, $question)) {
|
||||
$this->output->writeln("<yellow>Package " . $package_name . " not updated</yellow>");
|
||||
if (!$io->askQuestion($question)) {
|
||||
$io->writeln("<yellow>Package {$package_name} not updated</yellow>");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -270,73 +281,75 @@ class InstallCommand extends ConsoleCommand
|
||||
* @param string $type The type of dependency to show: install, update, ignore
|
||||
* @param string $message A message to be shown prior to listing the dependencies
|
||||
* @param bool $required A flag that determines if the installation is required or optional
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function installDependencies($dependencies, $type, $message, $required = true)
|
||||
public function installDependencies(array $dependencies, string $type, string $message, bool $required = true): void
|
||||
{
|
||||
$packages = array_filter($dependencies, function ($action) use ($type) { return $action === $type; });
|
||||
$io = $this->getIO();
|
||||
$packages = array_filter($dependencies, static function ($action) use ($type) {
|
||||
return $action === $type;
|
||||
});
|
||||
if (count($packages) > 0) {
|
||||
$this->output->writeln($message);
|
||||
$io->writeln($message);
|
||||
|
||||
foreach ($packages as $dependencyName => $dependencyVersion) {
|
||||
$this->output->writeln(" |- Package <cyan>" . $dependencyName . "</cyan>");
|
||||
$io->writeln(" |- Package <cyan>{$dependencyName}</cyan>");
|
||||
}
|
||||
|
||||
$this->output->writeln("");
|
||||
$io->newLine();
|
||||
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
if ($type == 'install') {
|
||||
if ($type === 'install') {
|
||||
$questionAction = 'Install';
|
||||
} else {
|
||||
$questionAction = 'Update';
|
||||
}
|
||||
|
||||
if (count($packages) == 1) {
|
||||
if (count($packages) === 1) {
|
||||
$questionArticle = 'this';
|
||||
} else {
|
||||
$questionArticle = 'these';
|
||||
}
|
||||
|
||||
if (count($packages) == 1) {
|
||||
if (count($packages) === 1) {
|
||||
$questionNoun = 'package';
|
||||
} else {
|
||||
$questionNoun = 'packages';
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion("$questionAction $questionArticle $questionNoun? [Y|n] ", true);
|
||||
$answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion("${questionAction} {$questionArticle} {$questionNoun}? [Y|n] ", true);
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if ($answer) {
|
||||
foreach ($packages as $dependencyName => $dependencyVersion) {
|
||||
$package = $this->gpm->findPackage($dependencyName);
|
||||
$this->processPackage($package, ($type == 'update') ? true : false);
|
||||
}
|
||||
$this->output->writeln('');
|
||||
} else {
|
||||
if ($required) {
|
||||
throw new \Exception();
|
||||
$this->processPackage($package, $type === 'update');
|
||||
}
|
||||
$io->newLine();
|
||||
} elseif ($required) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
* @param bool $is_update True if the package is an update
|
||||
* @param Package|null $package
|
||||
* @param bool $is_update True if the package is an update
|
||||
* @return void
|
||||
*/
|
||||
private function processPackage($package, $is_update = false)
|
||||
private function processPackage(?Package $package, bool $is_update = false): void
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!$package) {
|
||||
$this->output->writeln("<red>Package not found on the GPM!</red> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln('<red>Package not found on the GPM!</red>');
|
||||
$io->newLine();
|
||||
return;
|
||||
}
|
||||
|
||||
$symlink = false;
|
||||
if ($this->use_symlinks) {
|
||||
if ($this->getSymlinkSource($package) || !isset($package->version)) {
|
||||
if (!isset($package->version) || $this->getSymlinkSource($package)) {
|
||||
$symlink = true;
|
||||
}
|
||||
}
|
||||
@@ -349,9 +362,10 @@ class InstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Add package to the queue to process the demo content, if demo content exists
|
||||
*
|
||||
* @param $package
|
||||
* @param Package $package
|
||||
* @return void
|
||||
*/
|
||||
private function processDemo($package)
|
||||
private function processDemo(Package $package): void
|
||||
{
|
||||
$demo_dir = $this->destination . DS . $package->install_path . DS . '_demo';
|
||||
if (file_exists($demo_dir)) {
|
||||
@@ -362,10 +376,12 @@ class InstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Prompt to install the demo content of a package
|
||||
*
|
||||
* @param $package
|
||||
* @param Package $package
|
||||
* @return void
|
||||
*/
|
||||
private function installDemoContent($package)
|
||||
private function installDemoContent(Package $package): void
|
||||
{
|
||||
$io = $this->getIO();
|
||||
$demo_dir = $this->destination . DS . $package->install_path . DS . '_demo';
|
||||
|
||||
if (file_exists($demo_dir)) {
|
||||
@@ -373,15 +389,15 @@ class InstallCommand extends ConsoleCommand
|
||||
$pages_dir = $dest_dir . DS . 'pages';
|
||||
|
||||
// Demo content exists, prompt to install it.
|
||||
$this->output->writeln("<white>Attention: </white><cyan>" . $package->name . "</cyan> contains demo content");
|
||||
$helper = $this->getHelper('question');
|
||||
$io->writeln("<white>Attention: </white><cyan>{$package->name}</cyan> contains demo content");
|
||||
|
||||
$question = new ConfirmationQuestion('Do you wish to install this demo content? [y|N] ', false);
|
||||
|
||||
$answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question);
|
||||
$answer = $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln(" '- <red>Skipped!</red> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Skipped!</red> ");
|
||||
$io->newLine();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -390,11 +406,11 @@ class InstallCommand extends ConsoleCommand
|
||||
if (file_exists($demo_dir . DS . 'pages')) {
|
||||
$pages_backup = 'pages.' . date('m-d-Y-H-i-s');
|
||||
$question = new ConfirmationQuestion('This will backup your current `user/pages` folder to `user/' . $pages_backup . '`, continue? [y|N]', false);
|
||||
$answer = $this->all_yes ? true : $helper->ask($this->input, $this->output, $question);
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln(" '- <red>Skipped!</red> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Skipped!</red> ");
|
||||
$io->newLine();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -402,27 +418,26 @@ class InstallCommand extends ConsoleCommand
|
||||
// backup current pages folder
|
||||
if (file_exists($dest_dir)) {
|
||||
if (rename($pages_dir, $dest_dir . DS . $pages_backup)) {
|
||||
$this->output->writeln(" |- Backing up pages... <green>ok</green>");
|
||||
$io->writeln(' |- Backing up pages... <green>ok</green>');
|
||||
} else {
|
||||
$this->output->writeln(" |- Backing up pages... <red>failed</red>");
|
||||
$io->writeln(' |- Backing up pages... <red>failed</red>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmation received, copy over the data
|
||||
$this->output->writeln(" |- Installing demo content... <green>ok</green> ");
|
||||
$io->writeln(' |- Installing demo content... <green>ok</green> ');
|
||||
Folder::rcopy($demo_dir, $dest_dir);
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
*
|
||||
* @return array|bool
|
||||
* @param Package $package
|
||||
* @return array|false
|
||||
*/
|
||||
private function getGitRegexMatches($package)
|
||||
private function getGitRegexMatches(Package $package)
|
||||
{
|
||||
if (isset($package->repository)) {
|
||||
$repository = $package->repository;
|
||||
@@ -436,11 +451,10 @@ class InstallCommand extends ConsoleCommand
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
*
|
||||
* @return bool|string
|
||||
* @param Package $package
|
||||
* @return string|false
|
||||
*/
|
||||
private function getSymlinkSource($package)
|
||||
private function getSymlinkSource(Package $package)
|
||||
{
|
||||
$matches = $this->getGitRegexMatches($package);
|
||||
|
||||
@@ -450,7 +464,7 @@ class InstallCommand extends ConsoleCommand
|
||||
} else {
|
||||
$repo_dir = $matches[2];
|
||||
}
|
||||
|
||||
|
||||
$paths = (array) $paths;
|
||||
foreach ($paths as $repo) {
|
||||
$path = rtrim($repo, '/') . '/' . $repo_dir;
|
||||
@@ -458,94 +472,94 @@ class InstallCommand extends ConsoleCommand
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
* @param Package $package
|
||||
* @return void
|
||||
*/
|
||||
private function processSymlink($package)
|
||||
private function processSymlink(Package $package): void
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
exec('cd ' . $this->destination);
|
||||
|
||||
$to = $this->destination . DS . $package->install_path;
|
||||
$from = $this->getSymlinkSource($package);
|
||||
|
||||
$this->output->writeln("Preparing to Symlink <cyan>" . $package->name . "</cyan>");
|
||||
$this->output->write(" |- Checking source... ");
|
||||
$io->writeln("Preparing to Symlink <cyan>{$package->name}</cyan>");
|
||||
$io->write(' |- Checking source... ');
|
||||
|
||||
if (file_exists($from)) {
|
||||
$this->output->writeln("<green>ok</green>");
|
||||
$io->writeln('<green>ok</green>');
|
||||
|
||||
$this->output->write(" |- Checking destination... ");
|
||||
$io->write(' |- Checking destination... ');
|
||||
$checks = $this->checkDestination($package);
|
||||
|
||||
if (!$checks) {
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->newLine();
|
||||
} elseif (file_exists($to)) {
|
||||
$io->writeln(" '- <red>Symlink cannot overwrite an existing package, please remove first</red>");
|
||||
$io->newLine();
|
||||
} else {
|
||||
if (file_exists($to)) {
|
||||
$this->output->writeln(" '- <red>Symlink cannot overwrite an existing package, please remove first</red>");
|
||||
$this->output->writeln('');
|
||||
} else {
|
||||
symlink($from, $to);
|
||||
symlink($from, $to);
|
||||
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- Symlinking package... <green>ok</green> ");
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
$this->output->writeln('');
|
||||
}
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$io->writeln(' |- Symlinking package... <green>ok</green> ');
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->output->writeln("<red>not found!</red>");
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->writeln('<red>not found!</red>');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
* @param Package $package
|
||||
* @param bool $is_update
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function processGpm($package, $is_update = false)
|
||||
private function processGpm(Package $package, bool $is_update = false)
|
||||
{
|
||||
$version = isset($package->available) ? $package->available : $package->version;
|
||||
$io = $this->getIO();
|
||||
|
||||
$version = $package->available ?? $package->version;
|
||||
$license = Licenses::get($package->slug);
|
||||
|
||||
$this->output->writeln("Preparing to install <cyan>" . $package->name . "</cyan> [v" . $version . "]");
|
||||
$io->writeln("Preparing to install <cyan>{$package->name}</cyan> [v{$version}]");
|
||||
|
||||
$this->output->write(" |- Downloading package... 0%");
|
||||
$io->write(' |- Downloading package... 0%');
|
||||
$this->file = $this->downloadPackage($package, $license);
|
||||
|
||||
if (!$this->file) {
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->newLine();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->output->write(" |- Checking destination... ");
|
||||
$io->write(' |- Checking destination... ');
|
||||
$checks = $this->checkDestination($package);
|
||||
|
||||
if (!$checks) {
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->newLine();
|
||||
} else {
|
||||
$this->output->write(" |- Installing package... ");
|
||||
$io->write(' |- Installing package... ');
|
||||
$installation = $this->installPackage($package, $is_update);
|
||||
if (!$installation) {
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->newLine();
|
||||
} else {
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
$io->newLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -556,26 +570,27 @@ class InstallCommand extends ConsoleCommand
|
||||
|
||||
/**
|
||||
* @param Package $package
|
||||
*
|
||||
* @param string $license
|
||||
*
|
||||
* @return string
|
||||
* @param string|null $license
|
||||
* @return string|null
|
||||
*/
|
||||
private function downloadPackage($package, $license = null)
|
||||
private function downloadPackage(Package $package, string $license = null)
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
|
||||
$this->tmp = $tmp_dir . '/Grav-' . uniqid();
|
||||
$filename = $package->slug . basename($package->zipball_url);
|
||||
$filename = preg_replace('/[\\\\\/:"*?&<>|]+/mi', '-', $filename);
|
||||
$filename = preg_replace('/[\\\\\/:"*?&<>|]+/m', '-', $filename);
|
||||
$query = '';
|
||||
|
||||
if ($package->premium) {
|
||||
$query = \json_encode(array_merge(
|
||||
if (!empty($package->premium)) {
|
||||
$query = json_encode(array_merge(
|
||||
$package->premium,
|
||||
[
|
||||
'slug' => $package->slug,
|
||||
'filename' => $package->premium['filename'],
|
||||
'license_key' => $license
|
||||
'license_key' => $license,
|
||||
'sid' => md5(GRAV_ROOT)
|
||||
]
|
||||
));
|
||||
|
||||
@@ -584,21 +599,27 @@ class InstallCommand extends ConsoleCommand
|
||||
|
||||
try {
|
||||
$output = Response::get($package->zipball_url . $query, [], [$this, 'progress']);
|
||||
} catch (\Exception $e) {
|
||||
$error = str_replace("\n", "\n | '- ", $e->getMessage());
|
||||
$this->output->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- Downloading package... <red>error</red> ");
|
||||
$this->output->writeln(" | '- " . $error);
|
||||
} catch (Exception $e) {
|
||||
if (!empty($package->premium) && $e->getCode() === 401) {
|
||||
$message = '<yellow>Unauthorized Premium License Key</yellow>';
|
||||
} else {
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
return false;
|
||||
$error = str_replace("\n", "\n | '- ", $message);
|
||||
$io->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$io->writeln(' |- Downloading package... <red>error</red> ');
|
||||
$io->writeln(" | '- " . $error);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Folder::mkdir($this->tmp);
|
||||
Folder::create($this->tmp);
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$this->output->write(" |- Downloading package... 100%");
|
||||
$this->output->writeln('');
|
||||
$io->write("\x0D");
|
||||
$io->write(' |- Downloading package... 100%');
|
||||
$io->newLine();
|
||||
|
||||
file_put_contents($this->tmp . DS . $filename, $output);
|
||||
|
||||
@@ -606,41 +627,42 @@ class InstallCommand extends ConsoleCommand
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
*
|
||||
* @param Package $package
|
||||
* @return bool
|
||||
*/
|
||||
private function checkDestination($package)
|
||||
private function checkDestination(Package $package): bool
|
||||
{
|
||||
$question_helper = $this->getHelper('question');
|
||||
$io = $this->getIO();
|
||||
|
||||
Installer::isValidDestination($this->destination . DS . $package->install_path);
|
||||
|
||||
if (Installer::lastErrorCode() == Installer::IS_LINK) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <yellow>symbolic link</yellow>");
|
||||
if (Installer::lastErrorCode() === Installer::IS_LINK) {
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <yellow>symbolic link</yellow>');
|
||||
|
||||
if ($this->all_yes) {
|
||||
$this->output->writeln(" | '- <yellow>Skipped automatically.</yellow>");
|
||||
$io->writeln(" | '- <yellow>Skipped automatically.</yellow>");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion(" | '- Destination has been detected as symlink, delete symbolic link first? [y|N] ",
|
||||
false);
|
||||
$answer = $question_helper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion(
|
||||
" | '- Destination has been detected as symlink, delete symbolic link first? [y|N] ",
|
||||
false
|
||||
);
|
||||
$answer = $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln(" | '- <red>You decided to not delete the symlink automatically.</red>");
|
||||
$io->writeln(" | '- <red>You decided to not delete the symlink automatically.</red>");
|
||||
|
||||
return false;
|
||||
} else {
|
||||
unlink($this->destination . DS . $package->install_path);
|
||||
}
|
||||
|
||||
unlink($this->destination . DS . $package->install_path);
|
||||
}
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <green>ok</green>");
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <green>ok</green>');
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -649,48 +671,56 @@ class InstallCommand extends ConsoleCommand
|
||||
* Install a package
|
||||
*
|
||||
* @param Package $package
|
||||
* @param bool $is_update True if it's an update. False if it's an install
|
||||
*
|
||||
* @param bool $is_update True if it's an update. False if it's an install
|
||||
* @return bool
|
||||
*/
|
||||
private function installPackage($package, $is_update = false)
|
||||
private function installPackage(Package $package, bool $is_update = false): bool
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$type = $package->package_type;
|
||||
|
||||
Installer::install($this->file, $this->destination, ['install_path' => $package->install_path, 'theme' => (($type == 'themes')), 'is_update' => $is_update]);
|
||||
Installer::install($this->file, $this->destination, ['install_path' => $package->install_path, 'theme' => $type === 'themes', 'is_update' => $is_update]);
|
||||
$error_code = Installer::lastErrorCode();
|
||||
Folder::delete($this->tmp);
|
||||
|
||||
if ($error_code) {
|
||||
$this->output->write("\x0D");
|
||||
$io->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- Installing package... <red>error</red> ");
|
||||
$this->output->writeln(" | '- " . Installer::lastErrorMsg());
|
||||
$io->writeln(' |- Installing package... <red>error</red> ');
|
||||
$io->writeln(" | '- " . Installer::lastErrorMsg());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$message = Installer::getMessage();
|
||||
if ($message) {
|
||||
$this->output->write("\x0D");
|
||||
$io->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- " . $message);
|
||||
$io->writeln(" |- {$message}");
|
||||
}
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$io->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- Installing package... <green>ok</green> ");
|
||||
$io->writeln(' |- Installing package... <green>ok</green> ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $progress
|
||||
* @param array $progress
|
||||
* @return void
|
||||
*/
|
||||
public function progress($progress)
|
||||
public function progress(array $progress): void
|
||||
{
|
||||
$this->output->write("\x0D");
|
||||
$this->output->write(" |- Downloading package... " . str_pad($progress['percent'], 5, " ",
|
||||
STR_PAD_LEFT) . '%');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->write("\x0D");
|
||||
$io->write(' |- Downloading package... ' . str_pad(
|
||||
$progress['percent'],
|
||||
5,
|
||||
' ',
|
||||
STR_PAD_LEFT
|
||||
) . '%');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Gpm;
|
||||
|
||||
use Exception;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Common\GPM\Response;
|
||||
use Grav\Common\GPM\Upgrader;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GpmCommand;
|
||||
use Grav\Installer\Install;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use ZipArchive;
|
||||
use function is_callable;
|
||||
use function strlen;
|
||||
|
||||
class SelfupgradeCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class SelfupgradeCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class SelfupgradeCommand extends GpmCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var array */
|
||||
protected $data;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $extensions;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $updatable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $file;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $types = ['plugins', 'themes'];
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string|null */
|
||||
private $tmp;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var Upgrader */
|
||||
private $upgrader;
|
||||
|
||||
/** @var string */
|
||||
protected $all_yes;
|
||||
/** @var string */
|
||||
protected $overwrite;
|
||||
/** @var int */
|
||||
protected $timeout;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("self-upgrade")
|
||||
->setName('self-upgrade')
|
||||
->setAliases(['selfupgrade', 'selfupdate'])
|
||||
->addOption(
|
||||
'force',
|
||||
@@ -78,18 +75,36 @@ class SelfupgradeCommand extends ConsoleCommand
|
||||
InputOption::VALUE_NONE,
|
||||
'Option to overwrite packages if they already exist'
|
||||
)
|
||||
->setDescription("Detects and performs an update of Grav itself when available")
|
||||
->addOption(
|
||||
'timeout',
|
||||
't',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Option to set the timeout in seconds when downloading the update (0 for no timeout)',
|
||||
30
|
||||
)
|
||||
->setDescription('Detects and performs an update of Grav itself when available')
|
||||
->setHelp('The <info>update</info> command updates Grav itself when a new version is available');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->upgrader = new Upgrader($this->input->getOption('force'));
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
$this->overwrite = $this->input->getOption('overwrite');
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!class_exists(ZipArchive::class)) {
|
||||
$io->title('GPM Self Upgrade');
|
||||
$io->error('php-zip extension needs to be enabled!');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->upgrader = new Upgrader($input->getOption('force'));
|
||||
$this->all_yes = $input->getOption('all-yes');
|
||||
$this->overwrite = $input->getOption('overwrite');
|
||||
$this->timeout = (int) $input->getOption('timeout');
|
||||
|
||||
$this->displayGPMRelease();
|
||||
|
||||
@@ -100,110 +115,148 @@ class SelfupgradeCommand extends ConsoleCommand
|
||||
$release = strftime('%c', strtotime($this->upgrader->getReleaseDate()));
|
||||
|
||||
if (!$this->upgrader->meetsRequirements()) {
|
||||
$this->output->writeln("<red>ATTENTION:</red>");
|
||||
$this->output->writeln(" Grav has increased the minimum PHP requirement.");
|
||||
$this->output->writeln(" You are currently running PHP <red>" . phpversion() . "</red>, but PHP <green>" . $this->upgrader->minPHPVersion() . "</green> is required.");
|
||||
$this->output->writeln(" Additional information: <white>http://getgrav.org/blog/changing-php-requirements</white>");
|
||||
$this->output->writeln("");
|
||||
$this->output->writeln("Selfupgrade aborted.");
|
||||
$this->output->writeln("");
|
||||
exit;
|
||||
$io->writeln('<red>ATTENTION:</red>');
|
||||
$io->writeln(' Grav has increased the minimum PHP requirement.');
|
||||
$io->writeln(' You are currently running PHP <red>' . phpversion() . '</red>, but PHP <green>' . $this->upgrader->minPHPVersion() . '</green> is required.');
|
||||
$io->writeln(' Additional information: <white>http://getgrav.org/blog/changing-php-requirements</white>');
|
||||
$io->newLine();
|
||||
$io->writeln('Selfupgrade aborted.');
|
||||
$io->newLine();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!$this->overwrite && !$this->upgrader->isUpgradable()) {
|
||||
$this->output->writeln("You are already running the latest version of Grav (v" . $local . ") released on " . $release);
|
||||
exit;
|
||||
$io->writeln("You are already running the latest version of <green>Grav v{$local}</green>");
|
||||
$io->writeln("which was released on {$release}");
|
||||
|
||||
$config = Grav::instance()['config'];
|
||||
$schema = $config->get('versions.core.grav.schema');
|
||||
if ($schema !== GRAV_SCHEMA && version_compare($schema, GRAV_SCHEMA, '<')) {
|
||||
$io->newLine();
|
||||
$io->writeln('However post-install scripts have not been run.');
|
||||
if (!$this->all_yes) {
|
||||
$question = new ConfirmationQuestion(
|
||||
'Would you like to run the scripts? [Y|n] ',
|
||||
true
|
||||
);
|
||||
$answer = $io->askQuestion($question);
|
||||
} else {
|
||||
$answer = true;
|
||||
}
|
||||
|
||||
if ($answer) {
|
||||
// Finalize installation.
|
||||
Install::instance()->finalize();
|
||||
|
||||
$io->write(' |- Running post-install scripts... ');
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Installer::isValidDestination(GRAV_ROOT . '/system');
|
||||
if (Installer::IS_LINK === Installer::lastErrorCode()) {
|
||||
$this->output->writeln("<red>ATTENTION:</red> Grav is symlinked, cannot upgrade, aborting...");
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("You are currently running a symbolically linked Grav v" . $local . ". Latest available is v". $remote . ".");
|
||||
exit;
|
||||
$io->writeln('<red>ATTENTION:</red> Grav is symlinked, cannot upgrade, aborting...');
|
||||
$io->newLine();
|
||||
$io->writeln("You are currently running a symbolically linked Grav v{$local}. Latest available is v{$remote}.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// not used but preloaded just in case!
|
||||
new ArrayInput([]);
|
||||
|
||||
$questionHelper = $this->getHelper('question');
|
||||
|
||||
|
||||
$this->output->writeln("Grav v<cyan>$remote</cyan> is now available [release date: $release].");
|
||||
$this->output->writeln("You are currently using v<cyan>" . GRAV_VERSION . "</cyan>.");
|
||||
$io->writeln("Grav v<cyan>{$remote}</cyan> is now available [release date: {$release}].");
|
||||
$io->writeln('You are currently using v<cyan>' . GRAV_VERSION . '</cyan>.');
|
||||
|
||||
if (!$this->all_yes) {
|
||||
$question = new ConfirmationQuestion("Would you like to read the changelog before proceeding? [y|N] ",
|
||||
false);
|
||||
$answer = $questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion(
|
||||
'Would you like to read the changelog before proceeding? [y|N] ',
|
||||
false
|
||||
);
|
||||
$answer = $io->askQuestion($question);
|
||||
|
||||
if ($answer) {
|
||||
$changelog = $this->upgrader->getChangelog(GRAV_VERSION);
|
||||
|
||||
$this->output->writeln("");
|
||||
$io->newLine();
|
||||
foreach ($changelog as $version => $log) {
|
||||
$title = $version . ' [' . $log['date'] . ']';
|
||||
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', function ($match) {
|
||||
return "\n" . ucfirst($match[1]) . ":";
|
||||
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', static function ($match) {
|
||||
return "\n" . ucfirst($match[1]) . ':';
|
||||
}, $log['content']);
|
||||
|
||||
$this->output->writeln($title);
|
||||
$this->output->writeln(str_repeat('-', strlen($title)));
|
||||
$this->output->writeln($content);
|
||||
$this->output->writeln("");
|
||||
$io->writeln($title);
|
||||
$io->writeln(str_repeat('-', strlen($title)));
|
||||
$io->writeln($content);
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion("Press [ENTER] to continue.", true);
|
||||
$questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion('Press [ENTER] to continue.', true);
|
||||
$io->askQuestion($question);
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion("Would you like to upgrade now? [y|N] ", false);
|
||||
$answer = $questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion('Would you like to upgrade now? [y|N] ', false);
|
||||
$answer = $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln("Aborting...");
|
||||
$io->writeln('Aborting...');
|
||||
|
||||
exit;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->writeln("");
|
||||
$this->output->writeln("Preparing to upgrade to v<cyan>$remote</cyan>..");
|
||||
$io->newLine();
|
||||
$io->writeln("Preparing to upgrade to v<cyan>{$remote}</cyan>..");
|
||||
|
||||
$this->output->write(" |- Downloading upgrade [" . $this->formatBytes($update['size']) . "]... 0%");
|
||||
$io->write(" |- Downloading upgrade [{$this->formatBytes($update['size'])}]... 0%");
|
||||
$this->file = $this->download($update);
|
||||
|
||||
$this->output->write(" |- Installing upgrade... ");
|
||||
$io->write(' |- Installing upgrade... ');
|
||||
$installation = $this->upgrade();
|
||||
|
||||
$error = 0;
|
||||
if (!$installation) {
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->newLine();
|
||||
$error = 1;
|
||||
} else {
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
// clear cache after successful upgrade
|
||||
$this->clearCache('all');
|
||||
if ($this->tmp && is_dir($this->tmp)) {
|
||||
Folder::delete($this->tmp);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $package
|
||||
*
|
||||
* @param array $package
|
||||
* @return string
|
||||
*/
|
||||
private function download($package)
|
||||
private function download(array $package): string
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
|
||||
$this->tmp = $tmp_dir . '/Grav-' . uniqid();
|
||||
$output = Response::get($package['download'], [], [$this, 'progress']);
|
||||
$this->tmp = $tmp_dir . '/grav-update-' . uniqid('', false);
|
||||
$options = [
|
||||
'timeout' => $this->timeout,
|
||||
];
|
||||
|
||||
Folder::mkdir($this->tmp);
|
||||
$output = Response::get($package['download'], $options, [$this, 'progress']);
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$this->output->write(" |- Downloading upgrade [" . $this->formatBytes($package['size']) . "]... 100%");
|
||||
$this->output->writeln('');
|
||||
Folder::create($this->tmp);
|
||||
|
||||
$io->write("\x0D");
|
||||
$io->write(" |- Downloading upgrade [{$this->formatBytes($package['size'])}]... 100%");
|
||||
$io->newLine();
|
||||
|
||||
file_put_contents($this->tmp . DS . $package['name'], $output);
|
||||
|
||||
@@ -213,50 +266,79 @@ class SelfupgradeCommand extends ConsoleCommand
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function upgrade()
|
||||
private function upgrade(): bool
|
||||
{
|
||||
Installer::install($this->file, GRAV_ROOT,
|
||||
['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true]);
|
||||
$errorCode = Installer::lastErrorCode();
|
||||
Folder::delete($this->tmp);
|
||||
$io = $this->getIO();
|
||||
|
||||
if ($errorCode & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR)) {
|
||||
$this->output->write("\x0D");
|
||||
$this->upgradeGrav($this->file);
|
||||
|
||||
$errorCode = Installer::lastErrorCode();
|
||||
if ($errorCode) {
|
||||
$io->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- Installing upgrade... <red>error</red> ");
|
||||
$this->output->writeln(" | '- " . Installer::lastErrorMsg());
|
||||
$io->writeln(' |- Installing upgrade... <red>error</red> ');
|
||||
$io->writeln(" | '- " . Installer::lastErrorMsg());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$io->write("\x0D");
|
||||
// extra white spaces to clear out the buffer properly
|
||||
$this->output->writeln(" |- Installing upgrade... <green>ok</green> ");
|
||||
$io->writeln(' |- Installing upgrade... <green>ok</green> ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $progress
|
||||
* @param array $progress
|
||||
* @return void
|
||||
*/
|
||||
public function progress($progress)
|
||||
public function progress(array $progress): void
|
||||
{
|
||||
$this->output->write("\x0D");
|
||||
$this->output->write(" |- Downloading upgrade [" . $this->formatBytes($progress["filesize"]) . "]... " . str_pad($progress['percent'],
|
||||
5, " ", STR_PAD_LEFT) . '%');
|
||||
$io = $this->getIO();
|
||||
|
||||
$io->write("\x0D");
|
||||
$io->write(" |- Downloading upgrade [{$this->formatBytes($progress['filesize']) }]... " . str_pad(
|
||||
$progress['percent'],
|
||||
5,
|
||||
' ',
|
||||
STR_PAD_LEFT
|
||||
) . '%');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $size
|
||||
* @param int|float $size
|
||||
* @param int $precision
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function formatBytes($size, $precision = 2)
|
||||
public function formatBytes($size, int $precision = 2): string
|
||||
{
|
||||
$base = log($size) / log(1024);
|
||||
$suffixes = array('', 'k', 'M', 'G', 'T');
|
||||
|
||||
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[(int)floor($base)];
|
||||
return round(1024 ** ($base - floor($base)), $precision) . $suffixes[(int)floor($base)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $zip
|
||||
* @return void
|
||||
*/
|
||||
private function upgradeGrav(string $zip): void
|
||||
{
|
||||
try {
|
||||
$folder = Installer::unZip($zip, $this->tmp . '/zip');
|
||||
if ($folder === false) {
|
||||
throw new RuntimeException(Installer::lastErrorMsg());
|
||||
}
|
||||
|
||||
$script = $folder . '/system/install.php';
|
||||
if ((file_exists($script) && $install = include $script) && is_callable($install)) {
|
||||
$install($zip);
|
||||
} else {
|
||||
throw new RuntimeException('Uploaded archive file is not a valid Grav update package');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Installer::setError($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
@@ -10,46 +11,46 @@ namespace Grav\Console\Gpm;
|
||||
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Common\GPM\Local;
|
||||
use Grav\Common\GPM\Remote;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Console\GpmCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Throwable;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
|
||||
class UninstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class UninstallCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class UninstallCommand extends GpmCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var array */
|
||||
protected $data;
|
||||
|
||||
/** @var GPM */
|
||||
protected $gpm;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $destination;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $file;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $tmp;
|
||||
|
||||
protected $dependencies= [];
|
||||
|
||||
/** @var array */
|
||||
protected $dependencies = [];
|
||||
/** @var string */
|
||||
protected $all_yes;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("uninstall")
|
||||
->setName('uninstall')
|
||||
->addOption(
|
||||
'all-yes',
|
||||
'y',
|
||||
@@ -61,83 +62,102 @@ class UninstallCommand extends ConsoleCommand
|
||||
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
|
||||
'The package(s) that are desired to be removed. Use the "index" command for a list of packages'
|
||||
)
|
||||
->setDescription("Performs the uninstallation of plugins and themes")
|
||||
->setDescription('Performs the uninstallation of plugins and themes')
|
||||
->setHelp('The <info>uninstall</info> command allows to uninstall plugins and themes');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$this->gpm = new GPM();
|
||||
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
$this->all_yes = $input->getOption('all-yes');
|
||||
|
||||
$packages = array_map('strtolower', $this->input->getArgument('package'));
|
||||
$packages = array_map('strtolower', $input->getArgument('package'));
|
||||
$this->data = ['total' => 0, 'not_found' => []];
|
||||
|
||||
$total = 0;
|
||||
foreach ($packages as $package) {
|
||||
$plugin = $this->gpm->getInstalledPlugin($package);
|
||||
$theme = $this->gpm->getInstalledTheme($package);
|
||||
if ($plugin || $theme) {
|
||||
$this->data[strtolower($package)] = $plugin ?: $theme;
|
||||
$this->data['total']++;
|
||||
$total++;
|
||||
} else {
|
||||
$this->data['not_found'][] = $package;
|
||||
}
|
||||
}
|
||||
$this->data['total'] = $total;
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
|
||||
if (!$this->data['total']) {
|
||||
$this->output->writeln("Nothing to uninstall.");
|
||||
$this->output->writeln('');
|
||||
exit;
|
||||
$io->writeln('Nothing to uninstall.');
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->data['not_found'])) {
|
||||
$this->output->writeln("These packages were not found installed: <red>" . implode('</red>, <red>',
|
||||
$this->data['not_found']) . "</red>");
|
||||
$io->writeln('These packages were not found installed: <red>' . implode(
|
||||
'</red>, <red>',
|
||||
$this->data['not_found']
|
||||
) . '</red>');
|
||||
}
|
||||
|
||||
unset($this->data['not_found']);
|
||||
unset($this->data['total']);
|
||||
unset($this->data['not_found'], $this->data['total']);
|
||||
|
||||
// Plugins need to be initialized in order to make clearcache to work.
|
||||
try {
|
||||
$this->initializePlugins();
|
||||
} catch (Throwable $e) {
|
||||
$io->writeln("<red>Some plugins failed to initialize: {$e->getMessage()}</red>");
|
||||
}
|
||||
|
||||
$error = 0;
|
||||
foreach ($this->data as $slug => $package) {
|
||||
$this->output->writeln("Preparing to uninstall <cyan>" . $package->name . "</cyan> [v" . $package->version . "]");
|
||||
$io->writeln("Preparing to uninstall <cyan>{$package->name}</cyan> [v{$package->version}]");
|
||||
|
||||
$this->output->write(" |- Checking destination... ");
|
||||
$io->write(' |- Checking destination... ');
|
||||
$checks = $this->checkDestination($slug, $package);
|
||||
|
||||
if (!$checks) {
|
||||
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <red>Installation failed or aborted.</red>");
|
||||
$io->newLine();
|
||||
$error = 1;
|
||||
} else {
|
||||
$uninstall = $this->uninstallPackage($slug, $package);
|
||||
|
||||
if (!$uninstall) {
|
||||
$this->output->writeln(" '- <red>Uninstallation failed or aborted.</red>");
|
||||
$io->writeln(" '- <red>Uninstallation failed or aborted.</red>");
|
||||
$error = 1;
|
||||
} else {
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// clear cache after successful upgrade
|
||||
$this->clearCache();
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $slug
|
||||
* @param $package
|
||||
*
|
||||
* @param string $slug
|
||||
* @param Local\Package|Remote\Package $package
|
||||
* @param bool $is_dependency
|
||||
* @return bool
|
||||
*/
|
||||
private function uninstallPackage($slug, $package, $is_dependency = false)
|
||||
private function uninstallPackage($slug, $package, $is_dependency = false): bool
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!$slug) {
|
||||
return false;
|
||||
}
|
||||
@@ -145,41 +165,34 @@ class UninstallCommand extends ConsoleCommand
|
||||
//check if there are packages that have this as a dependency. Abort and show list
|
||||
$dependent_packages = $this->gpm->getPackagesThatDependOnPackage($slug);
|
||||
if (count($dependent_packages) > ($is_dependency ? 1 : 0)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("<red>Uninstallation failed.</red>");
|
||||
$this->output->writeln('');
|
||||
$io->newLine(2);
|
||||
$io->writeln('<red>Uninstallation failed.</red>');
|
||||
$io->newLine();
|
||||
if (count($dependent_packages) > ($is_dependency ? 2 : 1)) {
|
||||
$this->output->writeln("The installed packages <cyan>" . implode('</cyan>, <cyan>', $dependent_packages) . "</cyan> depends on this package. Please remove those first.");
|
||||
$io->writeln('The installed packages <cyan>' . implode('</cyan>, <cyan>', $dependent_packages) . '</cyan> depends on this package. Please remove those first.');
|
||||
} else {
|
||||
$this->output->writeln("The installed package <cyan>" . implode('</cyan>, <cyan>', $dependent_packages) . "</cyan> depends on this package. Please remove it first.");
|
||||
$io->writeln('The installed package <cyan>' . implode('</cyan>, <cyan>', $dependent_packages) . '</cyan> depends on this package. Please remove it first.');
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($package->dependencies)) {
|
||||
|
||||
$dependencies = $package->dependencies;
|
||||
|
||||
if ($is_dependency) {
|
||||
foreach ($dependencies as $key => $dependency) {
|
||||
if (in_array($dependency['name'], $this->dependencies)) {
|
||||
if (in_array($dependency['name'], $this->dependencies, true)) {
|
||||
unset($dependencies[$key]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (count($dependencies) > 0) {
|
||||
$this->output->writeln(' `- Dependencies found...');
|
||||
$this->output->writeln('');
|
||||
}
|
||||
} elseif (count($dependencies) > 0) {
|
||||
$io->writeln(' `- Dependencies found...');
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
$questionHelper = $this->getHelper('question');
|
||||
|
||||
foreach ($dependencies as $dependency) {
|
||||
|
||||
$this->dependencies[] = $dependency['name'];
|
||||
|
||||
if (is_array($dependency)) {
|
||||
@@ -194,27 +207,25 @@ class UninstallCommand extends ConsoleCommand
|
||||
$dependency_exists = $this->packageExists($dependency, $dependencyPackage);
|
||||
|
||||
if ($dependency_exists == Installer::EXISTS) {
|
||||
$this->output->writeln("A dependency on <cyan>" . $dependencyPackage->name . "</cyan> [v" . $dependencyPackage->version . "] was found");
|
||||
$io->writeln("A dependency on <cyan>{$dependencyPackage->name}</cyan> [v{$dependencyPackage->version}] was found");
|
||||
|
||||
$question = new ConfirmationQuestion(" |- Uninstall <cyan>" . $dependencyPackage->name . "</cyan>? [y|N] ", false);
|
||||
$answer = $this->all_yes ? true : $questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion(" |- Uninstall <cyan>{$dependencyPackage->name}</cyan>? [y|N] ", false);
|
||||
$answer = $this->all_yes ? true : $io->askQuestion($question);
|
||||
|
||||
if ($answer) {
|
||||
$uninstall = $this->uninstallPackage($dependency, $dependencyPackage, true);
|
||||
|
||||
if (!$uninstall) {
|
||||
$this->output->writeln(" '- <red>Uninstallation failed or aborted.</red>");
|
||||
$io->writeln(" '- <red>Uninstallation failed or aborted.</red>");
|
||||
} else {
|
||||
$this->output->writeln(" '- <green>Success!</green> ");
|
||||
|
||||
$io->writeln(" '- <green>Success!</green> ");
|
||||
}
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
} else {
|
||||
$this->output->writeln(" '- <yellow>You decided not to uninstall " . $dependencyPackage->name . ".</yellow>");
|
||||
$this->output->writeln('');
|
||||
$io->writeln(" '- <yellow>You decided not to uninstall {$dependencyPackage->name}.</yellow>");
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,63 +236,61 @@ class UninstallCommand extends ConsoleCommand
|
||||
$errorCode = Installer::lastErrorCode();
|
||||
|
||||
if ($errorCode && $errorCode !== Installer::IS_LINK && $errorCode !== Installer::EXISTS) {
|
||||
$this->output->writeln(" |- Uninstalling " . $package->name . " package... <red>error</red> ");
|
||||
$this->output->writeln(" | '- <yellow>" . Installer::lastErrorMsg()."</yellow>");
|
||||
$io->writeln(" |- Uninstalling {$package->name} package... <red>error</red> ");
|
||||
$io->writeln(" | '- <yellow>" . Installer::lastErrorMsg() . '</yellow>');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$message = Installer::getMessage();
|
||||
if ($message) {
|
||||
$this->output->writeln(" |- " . $message);
|
||||
$io->writeln(" |- {$message}");
|
||||
}
|
||||
|
||||
if (!$is_dependency && $this->dependencies) {
|
||||
$this->output->writeln("Finishing up uninstalling <cyan>" . $package->name . "</cyan>");
|
||||
$io->writeln("Finishing up uninstalling <cyan>{$package->name}</cyan>");
|
||||
}
|
||||
$this->output->writeln(" |- Uninstalling " . $package->name . " package... <green>ok</green> ");
|
||||
|
||||
|
||||
$io->writeln(" |- Uninstalling {$package->name} package... <green>ok</green> ");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $slug
|
||||
* @param $package
|
||||
*
|
||||
* @param string $slug
|
||||
* @param Local\Package|Remote\Package $package
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
private function checkDestination($slug, $package)
|
||||
private function checkDestination(string $slug, $package): bool
|
||||
{
|
||||
$questionHelper = $this->getHelper('question');
|
||||
$io = $this->getIO();
|
||||
|
||||
$exists = $this->packageExists($slug, $package);
|
||||
|
||||
if ($exists == Installer::IS_LINK) {
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <yellow>symbolic link</yellow>");
|
||||
if ($exists === Installer::IS_LINK) {
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <yellow>symbolic link</yellow>');
|
||||
|
||||
if ($this->all_yes) {
|
||||
$this->output->writeln(" | '- <yellow>Skipped automatically.</yellow>");
|
||||
$io->writeln(" | '- <yellow>Skipped automatically.</yellow>");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion(" | '- Destination has been detected as symlink, delete symbolic link first? [y|N] ",
|
||||
false);
|
||||
$answer = $this->all_yes ? true : $questionHelper->ask($this->input, $this->output, $question);
|
||||
$question = new ConfirmationQuestion(
|
||||
" | '- Destination has been detected as symlink, delete symbolic link first? [y|N] ",
|
||||
false
|
||||
);
|
||||
|
||||
$answer = $io->askQuestion($question);
|
||||
if (!$answer) {
|
||||
$this->output->writeln(" | '- <red>You decided not to delete the symlink automatically.</red>");
|
||||
$io->writeln(" | '- <red>You decided not to delete the symlink automatically.</red>");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->write("\x0D");
|
||||
$this->output->writeln(" |- Checking destination... <green>ok</green>");
|
||||
$io->write("\x0D");
|
||||
$io->writeln(' |- Checking destination... <green>ok</green>');
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -289,14 +298,15 @@ class UninstallCommand extends ConsoleCommand
|
||||
/**
|
||||
* Check if package exists
|
||||
*
|
||||
* @param $slug
|
||||
* @param $package
|
||||
* @param string $slug
|
||||
* @param Local\Package|Remote\Package $package
|
||||
* @return int
|
||||
*/
|
||||
private function packageExists($slug, $package)
|
||||
private function packageExists(string $slug, $package): int
|
||||
{
|
||||
$path = Grav::instance()['locator']->findResource($package->package_type . '://' . $slug);
|
||||
Installer::isValidDestination($path);
|
||||
|
||||
return Installer::lastErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
@@ -10,60 +11,46 @@ namespace Grav\Console\Gpm;
|
||||
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Installer;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Common\GPM\Upgrader;
|
||||
use Grav\Console\GpmCommand;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use ZipArchive;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
|
||||
class UpdateCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class UpdateCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class UpdateCommand extends GpmCommand
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var array */
|
||||
protected $data;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $extensions;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $updatable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $destination;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
/** @var string */
|
||||
protected $file;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array */
|
||||
protected $types = ['plugins', 'themes'];
|
||||
/**
|
||||
* @var GPM $gpm
|
||||
*/
|
||||
/** @var GPM */
|
||||
protected $gpm;
|
||||
|
||||
/** @var string */
|
||||
protected $all_yes;
|
||||
|
||||
/** @var string */
|
||||
protected $overwrite;
|
||||
|
||||
/**
|
||||
* @var Upgrader
|
||||
*/
|
||||
/** @var Upgrader */
|
||||
protected $upgrader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("update")
|
||||
->setName('update')
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
@@ -106,83 +93,93 @@ class UpdateCommand extends ConsoleCommand
|
||||
InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
|
||||
'The package or packages that is desired to update. By default all available updates will be applied.'
|
||||
)
|
||||
->setDescription("Detects and performs an update of plugins and themes when available")
|
||||
->setDescription('Detects and performs an update of plugins and themes when available')
|
||||
->setHelp('The <info>update</info> command updates plugins and themes when a new version is available');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->upgrader = new Upgrader($this->input->getOption('force'));
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
if (!class_exists(ZipArchive::class)) {
|
||||
$io->title('GPM Update');
|
||||
$io->error('php-zip extension needs to be enabled!');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->upgrader = new Upgrader($input->getOption('force'));
|
||||
$local = $this->upgrader->getLocalVersion();
|
||||
$remote = $this->upgrader->getRemoteVersion();
|
||||
if ($local !== $remote) {
|
||||
$this->output->writeln("<yellow>WARNING</yellow>: A new version of Grav is available. You should update Grav before updating plugins and themes. If you continue without updating Grav, some plugins or themes may stop working.");
|
||||
$this->output->writeln("");
|
||||
$questionHelper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion("Continue with the update process? [Y|n] ", true);
|
||||
$answer = $questionHelper->ask($this->input, $this->output, $question);
|
||||
$io->writeln('<yellow>WARNING</yellow>: A new version of Grav is available. You should update Grav before updating plugins and themes. If you continue without updating Grav, some plugins or themes may stop working.');
|
||||
$io->newLine();
|
||||
$question = new ConfirmationQuestion('Continue with the update process? [Y|n] ', true);
|
||||
$answer = $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln("<red>Update aborted. Exiting...</red>");
|
||||
exit;
|
||||
$io->writeln('<red>Update aborted. Exiting...</red>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
$this->gpm = new GPM($this->input->getOption('force'));
|
||||
$this->gpm = new GPM($input->getOption('force'));
|
||||
|
||||
$this->all_yes = $this->input->getOption('all-yes');
|
||||
$this->overwrite = $this->input->getOption('overwrite');
|
||||
$this->all_yes = $input->getOption('all-yes');
|
||||
$this->overwrite = $input->getOption('overwrite');
|
||||
|
||||
$this->displayGPMRelease();
|
||||
|
||||
$this->destination = realpath($this->input->getOption('destination'));
|
||||
$this->destination = realpath($input->getOption('destination'));
|
||||
|
||||
if (!Installer::isGravInstance($this->destination)) {
|
||||
$this->output->writeln("<red>ERROR</red>: " . Installer::lastErrorMsg());
|
||||
$io->writeln('<red>ERROR</red>: ' . Installer::lastErrorMsg());
|
||||
exit;
|
||||
}
|
||||
if ($this->input->getOption('plugins') === false && $this->input->getOption('themes') === false) {
|
||||
if ($input->getOption('plugins') === false && $input->getOption('themes') === false) {
|
||||
$list_type = ['plugins' => true, 'themes' => true];
|
||||
} else {
|
||||
$list_type['plugins'] = $this->input->getOption('plugins');
|
||||
$list_type['themes'] = $this->input->getOption('themes');
|
||||
$list_type['plugins'] = $input->getOption('plugins');
|
||||
$list_type['themes'] = $input->getOption('themes');
|
||||
}
|
||||
|
||||
if ($this->overwrite) {
|
||||
$this->data = $this->gpm->getInstallable($list_type);
|
||||
$description = " can be overwritten";
|
||||
$description = ' can be overwritten';
|
||||
} else {
|
||||
$this->data = $this->gpm->getUpdatable($list_type);
|
||||
$description = " need updating";
|
||||
$description = ' need updating';
|
||||
}
|
||||
|
||||
$only_packages = array_map('strtolower', $this->input->getArgument('package'));
|
||||
$only_packages = array_map('strtolower', $input->getArgument('package'));
|
||||
|
||||
if (!$this->overwrite && !$this->data['total']) {
|
||||
$this->output->writeln("Nothing to update.");
|
||||
exit;
|
||||
$io->writeln('Nothing to update.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->output->write("Found <green>" . $this->gpm->countInstalled() . "</green> packages installed of which <magenta>" . $this->data['total'] . "</magenta>" . $description);
|
||||
$io->write("Found <green>{$this->gpm->countInstalled()}</green> packages installed of which <magenta>{$this->data['total']}</magenta>{$description}");
|
||||
|
||||
$limit_to = $this->userInputPackages($only_packages);
|
||||
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
|
||||
unset($this->data['total']);
|
||||
unset($limit_to['total']);
|
||||
unset($this->data['total'], $limit_to['total']);
|
||||
|
||||
|
||||
// updates review
|
||||
$slugs = [];
|
||||
|
||||
$index = 0;
|
||||
$index = 1;
|
||||
foreach ($this->data as $packages) {
|
||||
foreach ($packages as $slug => $package) {
|
||||
if (count($only_packages) && !array_key_exists($slug, $limit_to)) {
|
||||
if (!array_key_exists($slug, $limit_to) && count($only_packages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -190,13 +187,13 @@ class UpdateCommand extends ConsoleCommand
|
||||
$package->available = $package->version;
|
||||
}
|
||||
|
||||
$this->output->writeln(
|
||||
// index
|
||||
str_pad($index++ + 1, 2, '0', STR_PAD_LEFT) . ". " .
|
||||
$io->writeln(
|
||||
// index
|
||||
str_pad((string)$index++, 2, '0', STR_PAD_LEFT) . '. ' .
|
||||
// name
|
||||
"<cyan>" . str_pad($package->name, 15) . "</cyan> " .
|
||||
'<cyan>' . str_pad($package->name, 15) . '</cyan> ' .
|
||||
// version
|
||||
"[v<magenta>" . $package->version . "</magenta> -> v<green>" . $package->available . "</green>]"
|
||||
"[v<magenta>{$package->version}</magenta> -> v<green>{$package->available}</green>]"
|
||||
);
|
||||
$slugs[] = $slug;
|
||||
}
|
||||
@@ -204,14 +201,14 @@ class UpdateCommand extends ConsoleCommand
|
||||
|
||||
if (!$this->all_yes) {
|
||||
// prompt to continue
|
||||
$this->output->writeln("");
|
||||
$questionHelper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion("Continue with the update process? [Y|n] ", true);
|
||||
$answer = $questionHelper->ask($this->input, $this->output, $question);
|
||||
$io->newLine();
|
||||
$question = new ConfirmationQuestion('Continue with the update process? [Y|n] ', true);
|
||||
$answer = $io->askQuestion($question);
|
||||
|
||||
if (!$answer) {
|
||||
$this->output->writeln("<red>Update aborted. Exiting...</red>");
|
||||
exit;
|
||||
$io->writeln('<red>Update aborted. Exiting...</red>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,36 +218,40 @@ class UpdateCommand extends ConsoleCommand
|
||||
$args = new ArrayInput([
|
||||
'command' => 'install',
|
||||
'package' => $slugs,
|
||||
'-f' => $this->input->getOption('force'),
|
||||
'-f' => $input->getOption('force'),
|
||||
'-d' => $this->destination,
|
||||
'-y' => true
|
||||
]);
|
||||
$command_exec = $install_command->run($args, $this->output);
|
||||
$command_exec = $install_command->run($args, $io);
|
||||
|
||||
if ($command_exec != 0) {
|
||||
$this->output->writeln("<red>Error:</red> An error occurred while trying to install the packages");
|
||||
exit;
|
||||
$io->writeln('<red>Error:</red> An error occurred while trying to install the packages');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $only_packages
|
||||
*
|
||||
* @param array $only_packages
|
||||
* @return array
|
||||
*/
|
||||
private function userInputPackages($only_packages)
|
||||
private function userInputPackages(array $only_packages): array
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$found = ['total' => 0];
|
||||
$ignore = [];
|
||||
|
||||
if (!count($only_packages)) {
|
||||
$this->output->writeln('');
|
||||
$io->newLine();
|
||||
} else {
|
||||
foreach ($only_packages as $only_package) {
|
||||
$find = $this->gpm->findPackage($only_package);
|
||||
|
||||
if (!$find || (!$this->overwrite && !$this->gpm->isUpdatable($find->slug))) {
|
||||
$name = isset($find->slug) ? $find->slug : $only_package;
|
||||
$name = $find->slug ?? $only_package;
|
||||
$ignore[$name] = $name;
|
||||
} else {
|
||||
$found[$find->slug] = $find;
|
||||
@@ -264,19 +265,22 @@ class UpdateCommand extends ConsoleCommand
|
||||
$list = array_keys($list);
|
||||
|
||||
if ($found['total'] !== $this->data['total']) {
|
||||
$this->output->write(", only <magenta>" . $found['total'] . "</magenta> will be updated");
|
||||
$io->write(", only <magenta>{$found['total']}</magenta> will be updated");
|
||||
}
|
||||
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("Limiting updates for only <cyan>" . implode('</cyan>, <cyan>',
|
||||
$list) . "</cyan>");
|
||||
$io->newLine();
|
||||
$io->writeln('Limiting updates for only <cyan>' . implode(
|
||||
'</cyan>, <cyan>',
|
||||
$list
|
||||
) . '</cyan>');
|
||||
}
|
||||
|
||||
if (count($ignore)) {
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln("Packages not found or not requiring updates: <red>" . implode('</red>, <red>',
|
||||
$ignore) . "</red>");
|
||||
|
||||
$io->newLine();
|
||||
$io->writeln('Packages not found or not requiring updates: <red>' . implode(
|
||||
'</red>, <red>',
|
||||
$ignore
|
||||
) . '</red>');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\Gpm
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
@@ -10,25 +11,29 @@ namespace Grav\Console\Gpm;
|
||||
|
||||
use Grav\Common\GPM\GPM;
|
||||
use Grav\Common\GPM\Upgrader;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Console\GpmCommand;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use function count;
|
||||
|
||||
class VersionCommand extends ConsoleCommand
|
||||
/**
|
||||
* Class VersionCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class VersionCommand extends GpmCommand
|
||||
{
|
||||
/**
|
||||
* @var GPM
|
||||
*/
|
||||
/** @var GPM */
|
||||
protected $gpm;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName("version")
|
||||
->setName('version')
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
@@ -40,17 +45,20 @@ class VersionCommand extends ConsoleCommand
|
||||
InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
|
||||
'The package or packages that is desired to know the version of. By default and if not specified this would be grav'
|
||||
)
|
||||
->setDescription("Shows the version of an installed package. If available also shows pending updates.")
|
||||
->setDescription('Shows the version of an installed package. If available also shows pending updates.')
|
||||
->setHelp('The <info>version</info> command displays the current version of a package installed and, if available, the available version of pending updates');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
protected function serve(): int
|
||||
{
|
||||
$this->gpm = new GPM($this->input->getOption('force'));
|
||||
$packages = $this->input->getArgument('package');
|
||||
$input = $this->getInput();
|
||||
$io = $this->getIO();
|
||||
|
||||
$this->gpm = new GPM($input->getOption('force'));
|
||||
$packages = $input->getArgument('package');
|
||||
|
||||
$installed = false;
|
||||
|
||||
@@ -64,18 +72,17 @@ class VersionCommand extends ConsoleCommand
|
||||
$version = null;
|
||||
$updatable = false;
|
||||
|
||||
if ($package == 'grav') {
|
||||
if ($package === 'grav') {
|
||||
$name = 'Grav';
|
||||
$version = GRAV_VERSION;
|
||||
$upgrader = new Upgrader();
|
||||
|
||||
if ($upgrader->isUpgradable()) {
|
||||
$updatable = ' [upgradable: v<green>' . $upgrader->getRemoteVersion() . '</green>]';
|
||||
$updatable = " [upgradable: v<green>{$upgrader->getRemoteVersion()}</green>]";
|
||||
}
|
||||
|
||||
} else {
|
||||
// get currently installed version
|
||||
$locator = \Grav\Common\Grav::instance()['locator'];
|
||||
$locator = Grav::instance()['locator'];
|
||||
$blueprints_path = $locator->findResource('plugins://' . $package . DS . 'blueprints.yaml');
|
||||
if (!file_exists($blueprints_path)) { // theme?
|
||||
$blueprints_path = $locator->findResource('themes://' . $package . DS . 'blueprints.yaml');
|
||||
@@ -99,18 +106,20 @@ class VersionCommand extends ConsoleCommand
|
||||
$name = $installed->name;
|
||||
|
||||
if ($this->gpm->isUpdatable($package)) {
|
||||
$updatable = ' [updatable: v<green>' . $installed->available . '</green>]';
|
||||
$updatable = " [updatable: v<green>{$installed->available}</green>]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$updatable = $updatable ?: '';
|
||||
|
||||
if ($installed || $package == 'grav') {
|
||||
$this->output->writeln('You are running <white>' . $name . '</white> v<cyan>' . $version . '</cyan>' . $updatable);
|
||||
if ($installed || $package === 'grav') {
|
||||
$io->writeln("You are running <white>{$name}</white> v<cyan>{$version}</cyan>{$updatable}");
|
||||
} else {
|
||||
$this->output->writeln('Package <red>' . $package . '</red> not found');
|
||||
$io->writeln("Package <red>{$package}</red> not found");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
68
system/src/Grav/Console/GpmCommand.php
Normal file
68
system/src/Grav/Console/GpmCommand.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Grav;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class ConsoleCommand
|
||||
* @package Grav\Console
|
||||
*/
|
||||
class GpmCommand extends Command
|
||||
{
|
||||
use ConsoleTrait;
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->setupConsole($input, $output);
|
||||
|
||||
$grav = Grav::instance();
|
||||
$grav['config']->init();
|
||||
$grav['uri']->init();
|
||||
// @phpstan-ignore-next-line
|
||||
$grav['accounts'];
|
||||
|
||||
return $this->serve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override with your implementation.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
{
|
||||
// Return error.
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function displayGPMRelease()
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = Grav::instance()['config'];
|
||||
|
||||
$io = $this->getIO();
|
||||
$io->newLine();
|
||||
$io->writeln('GPM Releases Configuration: <yellow>' . ucfirst($config->get('system.gpm.releases')) . '</yellow>');
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
52
system/src/Grav/Console/GravCommand.php
Normal file
52
system/src/Grav/Console/GravCommand.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class ConsoleCommand
|
||||
* @package Grav\Console
|
||||
*/
|
||||
class GravCommand extends Command
|
||||
{
|
||||
use ConsoleTrait;
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->setupConsole($input, $output);
|
||||
|
||||
// Old versions of Grav called this command after grav upgrade.
|
||||
// We need make this command to work with older ConsoleTrait:
|
||||
if (method_exists($this, 'initializeGrav')) {
|
||||
$this->initializeGrav();
|
||||
}
|
||||
|
||||
return $this->serve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override with your implementation.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function serve()
|
||||
{
|
||||
// Return error.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
69
system/src/Grav/Console/Plugin/PluginListCommand.php
Normal file
69
system/src/Grav/Console/Plugin/PluginListCommand.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Plugin
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Plugin;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Plugins;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
|
||||
/**
|
||||
* Class InfoCommand
|
||||
* @package Grav\Console\Gpm
|
||||
*/
|
||||
class PluginListCommand extends ConsoleCommand
|
||||
{
|
||||
protected static $defaultName = 'plugins:list';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setHidden(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function serve(): int
|
||||
{
|
||||
$bin = $this->argv;
|
||||
$pattern = '([A-Z]\w+Command\.php)';
|
||||
|
||||
$io = $this->getIO();
|
||||
$io->newLine();
|
||||
$io->writeln('<red>Usage:</red>');
|
||||
$io->writeln(" {$bin} [slug] [command] [arguments]");
|
||||
$io->newLine();
|
||||
$io->writeln('<red>Example:</red>');
|
||||
$io->writeln(" {$bin} error log -l 1 --trace");
|
||||
$io->newLine();
|
||||
$io->writeln('<red>Plugins with CLI available:</red>');
|
||||
|
||||
$plugins = Plugins::all();
|
||||
$index = 0;
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if (!$plugin->enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$list = Folder::all("plugins://{$name}", ['compare' => 'Pathname', 'pattern' => '/\/cli\/' . $pattern . '$/usm', 'levels' => 1]);
|
||||
if (!$list) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$index++;
|
||||
$num = str_pad((string)$index, 2, '0', STR_PAD_LEFT);
|
||||
$io->writeln(' ' . $num . '. <red>' . str_pad($name, 15) . "</red> <white>{$bin} {$name} list</white>");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav.Console
|
||||
* @package Grav\Console\TerminalObjects
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\TerminalObjects;
|
||||
|
||||
/**
|
||||
* Class Table
|
||||
* @package Grav\Console\TerminalObjects
|
||||
* @deprecated 1.7 Use Symfony Console Table
|
||||
*/
|
||||
class Table extends \League\CLImate\TerminalObject\Basic\Table
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function result()
|
||||
{
|
||||
$this->column_widths = $this->getColumnWidths();
|
||||
|
||||
Reference in New Issue
Block a user