Fixed broken list in bin/gpm index, CLI/GPM command failures returning success [#3092, #3017]

This commit is contained in:
Matias Griese
2020-12-07 12:56:47 +02:00
parent dd30b96210
commit c2a2ef212e
26 changed files with 1576 additions and 296 deletions

View File

@@ -1,10 +1,13 @@
# v1.7.0
## mm/dd/2020
1. [](#new)
* Auto-Escape enabled by default. Manually enable **Twig Compatibility** and disable **Auto-Escape** to use the old setting.
* Updated unit tests to use codeception 4.1
1. [](#bugfix)
* Fixed potential error when upgrading Grav
* Updated unit tests to use codeception 4.1
* Auto-Escape enabled by default. Manually enable **Twig Compatibility** to
* Fixed broken list in `bin/gpm index` [#3092](https://github.com/getgrav/grav/issues/3092)
* Fixed CLI/GPM command failures returning 0 (success) value [#3017](https://github.com/getgrav/grav/issues/3017)
# v1.7.0-rc.19
## 12/02/2020

849
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,12 @@ use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use function count;
/**
* Class BackupCommand
* @package Grav\Console\Cli
*/
class BackupCommand extends ConsoleCommand
{
/** @var string $source */
@@ -25,7 +30,10 @@ class BackupCommand extends ConsoleCommand
/** @var ProgressBar $progress */
protected $progress;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('backup')
@@ -40,7 +48,10 @@ class BackupCommand extends ConsoleCommand
$this->source = getcwd();
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->initializeGrav();
@@ -53,7 +64,7 @@ class BackupCommand extends ConsoleCommand
if (!class_exists(\ZipArchive::class)) {
$io->error('php-zip extension needs to be enabled!');
exit;
return 1;
}
/** @var Backups $backups */
@@ -69,7 +80,7 @@ class BackupCommand extends ConsoleCommand
}
if (null === $id) {
if (\count($backups_list) > 1) {
if (count($backups_list) > 1) {
$helper = $this->getHelper('question');
$question = new ChoiceQuestion(
'Choose a backup?',
@@ -91,12 +102,15 @@ class BackupCommand extends ConsoleCommand
$io->newline(2);
$io->success('Backup Successfully Created: ' . $backup);
return 0;
}
/**
* @param array $args
* @return void
*/
public function outputProgress($args)
public function outputProgress($args): void
{
switch ($args['type']) {
case 'count':

View File

@@ -15,6 +15,10 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
/**
* Class CleanCommand
* @package Grav\Console\Cli
*/
class CleanCommand extends Command
{
/* @var InputInterface $output */
@@ -260,7 +264,10 @@ class CleanCommand extends Command
'cache/compiled/',
];
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('clean')
@@ -271,15 +278,21 @@ class CleanCommand extends Command
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->setupConsole($input, $output);
$this->cleanPaths();
return 0;
}
private function cleanPaths()
/**
* @return void
*/
private function cleanPaths(): void
{
$this->output->writeln('');
$this->output->writeln('<red>DELETING</red>');
@@ -305,8 +318,9 @@ 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;

View File

@@ -13,9 +13,16 @@ use Grav\Common\Cache;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
/**
* Class ClearCacheCommand
* @package Grav\Console\Cli
*/
class ClearCacheCommand extends ConsoleCommand
{
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('cache')
@@ -32,16 +39,23 @@ class ClearCacheCommand extends ConsoleCommand
->setHelp('The <info>cache</info> command allows you to interact with Grav cache');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$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('');

View File

@@ -12,9 +12,16 @@ namespace Grav\Console\Cli;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
/**
* Class ComposerCommand
* @package Grav\Console\Cli
*/
class ComposerCommand extends ConsoleCommand
{
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('composer')
@@ -34,7 +41,10 @@ class ComposerCommand extends ConsoleCommand
->setHelp('The <info>composer</info> command updates the composer vendor dependencies needed by Grav');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$action = $this->input->getOption('install') ? 'install' : ($this->input->getOption('update') ? 'update' : 'install');
@@ -45,5 +55,7 @@ class ComposerCommand extends ConsoleCommand
// Updates composer first
$this->output->writeln("\nInstalling vendor dependencies");
$this->output->writeln($this->composerUpdate(GRAV_ROOT, $action));
return 0;
}
}

View File

@@ -14,6 +14,10 @@ use RocketTheme\Toolbox\File\YamlFile;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
/**
* Class InstallCommand
* @package Grav\Console\Cli
*/
class InstallCommand extends ConsoleCommand
{
/** @var array */
@@ -28,7 +32,10 @@ class InstallCommand extends ConsoleCommand
/** @var string */
protected $user_path;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('install')
@@ -47,7 +54,10 @@ class InstallCommand extends ConsoleCommand
->setHelp('The <info>install</info> command installs the dependencies needed by Grav. Optionally can create symbolic links');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$dependencies_file = '.dependencies';
$this->destination = $this->input->getArgument('destination') ?: ROOT_DIR;
@@ -72,38 +82,46 @@ class InstallCommand extends ConsoleCommand
$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.');
}
return;
return 1;
}
$this->config = $file->content();
$file->free();
// If yaml config, process
if ($this->config) {
// If no config, fail.
if (!$this->config) {
$this->output->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
return 1;
}
$error = 0;
if (!$this->input->getOption('symlink')) {
// Updates composer first
$this->output->writeln("\nInstalling vendor dependencies");
$this->output->writeln($this->composerUpdate(GRAV_ROOT, 'install'));
$this->gitclone();
$error = $this->gitclone();
} else {
$this->symlink();
}
} else {
$this->output->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
$error = $this->symlink();
}
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('');
$error = 0;
foreach ($this->config['git'] as $repo => $data) {
$this->destination = rtrim($this->destination, DS);
$path = $this->destination . DS . $data['path'];
@@ -114,6 +132,7 @@ class InstallCommand extends ConsoleCommand
$this->output->writeln('<green>SUCCESS</green> cloned <magenta>' . $data['url'] . '</magenta> -> <cyan>' . $path . '</cyan>');
} else {
$this->output->writeln('<red>ERROR</red> cloning <magenta>' . $data['url']);
$error = 1;
}
$this->output->writeln('');
@@ -122,12 +141,16 @@ class InstallCommand extends ConsoleCommand
$this->output->writeln('');
}
}
return $error;
}
/**
* Symlinks
*
* @return int
*/
private function symlink()
private function symlink(): int
{
$this->output->writeln('');
$this->output->writeln('<green>Symlinking Bits</green>');
@@ -137,9 +160,11 @@ class InstallCommand extends ConsoleCommand
if (!$this->local_config) {
$this->output->writeln('<red>No local configuration available, aborting...</red>');
$this->output->writeln('');
return;
return 1;
}
$error = 0;
exec('cd ' . $this->destination);
foreach ($this->config['links'] as $repo => $data) {
$repos = (array) $this->local_config[$data['scm'] . '_repos'];
@@ -157,8 +182,8 @@ class InstallCommand extends ConsoleCommand
if (!$from) {
$this->output->writeln('<red>source for ' . $data['src'] . ' does not exists, skipping...</red>');
$this->output->writeln('');
} else {
if (!file_exists($to)) {
$error = 1;
} elseif (!file_exists($to)) {
symlink($from, $to);
$this->output->writeln('<green>SUCCESS</green> symlinked <magenta>' . $data['src'] . '</magenta> -> <cyan>' . $data['path'] . '</cyan>');
$this->output->writeln('');
@@ -167,6 +192,7 @@ class InstallCommand extends ConsoleCommand
$this->output->writeln('');
}
}
}
return $error;
}
}

View File

@@ -9,15 +9,23 @@
namespace Grav\Console\Cli;
use DateTime;
use Grav\Common\Grav;
use Grav\Common\Helpers\LogViewer;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Class LogViewerCommand
* @package Grav\Console\Cli
*/
class LogViewerCommand extends ConsoleCommand
{
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('logviewer')
@@ -34,14 +42,17 @@ class LogViewerCommand extends ConsoleCommand
'number of lines (default = 10)'
)
->setDescription('Display the last few entries of Grav log')
->setHelp("Display the last few entries of Grav log");
->setHelp('Display the last few entries of Grav log');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$file = $this->input->getOption('file') ?? 'grav.log';
$lines = $this->input->getOption('lines') ?? 20;
$verbose = $this->input->getOption('verbose', false);
$verbose = $this->input->getOption('verbose') ?? false;
$io = new SymfonyStyle($this->input, $this->output);
@@ -53,15 +64,20 @@ class LogViewerCommand extends ConsoleCommand
$viewer = new LogViewer();
$grav = Grav::instance();
$logfile = $grav['locator']->findResource('log://' . $file);
if ($logfile) {
$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) {
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";
@@ -74,8 +90,7 @@ class LogViewerCommand extends ConsoleCommand
$io->writeln($output);
}
}
} else {
$io->error('cannot find the log file: logs/' . $file);
}
return 0;
}
}

View File

@@ -14,9 +14,16 @@ use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
/**
* Class NewProjectCommand
* @package Grav\Console\Cli
*/
class NewProjectCommand extends ConsoleCommand
{
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('new-project')
@@ -36,7 +43,10 @@ class NewProjectCommand extends ConsoleCommand
->setHelp("The <info>new-project</info> command is a combination of the `setup` and `install` commands.\nCreates a new Grav instance and performs the installation of all the required dependencies.");
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$sandboxCommand = $this->getApplication()->find('sandbox');
$installCommand = $this->getApplication()->find('install');
@@ -53,7 +63,11 @@ class NewProjectCommand extends ConsoleCommand
'-s' => $this->input->getOption('symlink')
]);
$sandboxCommand->run($sandboxArguments, $this->output);
$installCommand->run($installArguments, $this->output);
$error = $sandboxCommand->run($sandboxArguments, $this->output);
if ($error === 0) {
$error = $installCommand->run($installArguments, $this->output);
}
return $error;
}
}

View File

@@ -17,7 +17,13 @@ use Grav\Common\Page\Pages;
use Grav\Console\ConsoleCommand;
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 ConsoleCommand
{
/** @var array */
@@ -125,7 +131,10 @@ class PageSystemValidatorCommand extends ConsoleCommand
/** @var Grav */
protected $grav;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('page-system-validator')
@@ -135,7 +144,10 @@ class PageSystemValidatorCommand extends ConsoleCommand
->setHelp('The <info>page-system-validator</info> command can be used to test the pages before and after upgrade');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->setLanguage('en');
$this->initializePages();
@@ -182,8 +194,13 @@ class PageSystemValidatorCommand extends ConsoleCommand
$this->output->writeln('<green>page-system-validator [-r|--record] [-c|--check]</green>');
}
$this->output->writeln('');
return 0;
}
/**
* @return array
*/
private function record()
{
/** @var Pages $pages */
@@ -243,7 +260,12 @@ class PageSystemValidatorCommand extends ConsoleCommand
return $results;
}
private function check(array $old, array $new)
/**
* @param array $old
* @param array $new
* @return array
*/
private function check(array $old, array $new): array
{
$errors = [];
foreach ($old as $path => $page) {

View File

@@ -11,9 +11,15 @@ namespace Grav\Console\Cli;
use Grav\Console\ConsoleCommand;
use Grav\Common\Filesystem\Folder;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use function count;
/**
* Class SandboxCommand
* @package Grav\Console\Cli
*/
class SandboxCommand extends ConsoleCommand
{
/** @var array */
@@ -61,7 +67,10 @@ class SandboxCommand extends ConsoleCommand
/** @var string */
protected $destination;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('sandbox')
@@ -81,38 +90,52 @@ class SandboxCommand extends ConsoleCommand
$source = getcwd();
if ($source === false) {
throw new \RuntimeException('Internal Error');
throw new RuntimeException('Internal Error');
}
$this->source = $source;
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->destination = $this->input->getArgument('destination');
// Symlink the Core Stuff
if ($this->input->getOption('symlink')) {
// Create Some core stuff if it doesn't exist
$this->createDirectories();
// 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();
$error = $this->createDirectories();
if ($error) {
return $error;
}
$this->pages();
$this->initFiles();
$this->perms();
// Copy files or create symlinks
$error = $this->input->getOption('symlink') ? $this->symlink() : $this->copy();
if ($error) {
return $error;
}
private function createDirectories()
$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(): int
{
$this->output->writeln('');
$this->output->writeln('<comment>Creating Directories</comment>');
@@ -133,9 +156,14 @@ class SandboxCommand extends ConsoleCommand
if (!$dirs_created) {
$this->output->writeln(' <red>Directories already exist</red>');
}
return 0;
}
private function copy()
/**
* @return int
*/
private function copy(): int
{
$this->output->writeln('');
$this->output->writeln('<comment>Copying Files</comment>');
@@ -152,9 +180,14 @@ class SandboxCommand extends ConsoleCommand
$this->output->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
@Folder::rcopy($from, $to);
}
return 0;
}
private function symlink()
/**
* @return int
*/
private function symlink(): int
{
$this->output->writeln('');
$this->output->writeln('<comment>Resetting Symbolic Links</comment>');
@@ -177,11 +210,39 @@ class SandboxCommand extends ConsoleCommand
}
symlink($from, $to);
}
return 0;
}
private function initFiles()
/**
* @return int
*/
private function pages(): int
{
$this->check();
$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');
}
return 0;
}
/**
* @return int
*/
private function initFiles(): int
{
if (!$this->check()) {
return 1;
}
$this->output->writeln('');
$this->output->writeln('<comment>File Initializing</comment>');
@@ -206,25 +267,14 @@ class SandboxCommand extends ConsoleCommand
if (!$files_init) {
$this->output->writeln(' <red>Files already exist</red>');
}
return 0;
}
private function pages()
{
$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()
/**
* @return int
*/
private function perms(): int
{
$this->output->writeln('');
$this->output->writeln('<comment>Permissions Initializing</comment>');
@@ -239,14 +289,19 @@ class SandboxCommand extends ConsoleCommand
}
$this->output->writeln("");
return 0;
}
private function check()
/**
* @return bool
*/
private function check(): bool
{
$success = true;
if (!file_exists($this->destination)) {
$this->output->writeln(' file: <red>$this->destination</red> does not exist!');
$this->output->writeln(' file: <red>' . $this->destination . '</red> does not exist!');
$success = false;
}
@@ -267,7 +322,8 @@ class SandboxCommand extends ConsoleCommand
if (!$success) {
$this->output->writeln('');
$this->output->writeln('<comment>install should be run with --symlink|--s to symlink first</comment>');
exit;
}
}
return $success;
}
}

View File

@@ -18,10 +18,18 @@ use RocketTheme\Toolbox\Event\Event;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Style\SymfonyStyle;
use function is_null;
/**
* Class SchedulerCommand
* @package Grav\Console\Cli
*/
class SchedulerCommand extends ConsoleCommand
{
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('scheduler')
@@ -53,11 +61,13 @@ class SchedulerCommand extends ConsoleCommand
->setHelp("Running without any options will force the Scheduler to run through it's jobs and process them");
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->initializePlugins();
// error_reporting(1);
$grav = Grav::instance();
$grav['backups']->init();
@@ -68,6 +78,7 @@ class SchedulerCommand extends ConsoleCommand
$this->setHelp('foo');
$io = new SymfonyStyle($this->input, $this->output);
$error = 0;
if ($this->input->getOption('jobs')) {
// Show jobs list
@@ -159,6 +170,7 @@ class SchedulerCommand extends ConsoleCommand
if ($job->isSuccessful()) {
$io->success('Job ran successfully...');
} else {
$error = 1;
$io->error('Job failed to run successfully...');
}
@@ -168,6 +180,7 @@ class SchedulerCommand extends ConsoleCommand
$this->output->write($output);
}
} else {
$error = 1;
$io->error('Could not find a job with id: ' . $jobid);
}
} elseif ($this->input->getOption('install')) {
@@ -180,6 +193,7 @@ class SchedulerCommand extends ConsoleCommand
$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()) {
@@ -199,5 +213,7 @@ class SchedulerCommand extends ConsoleCommand
$io->text($scheduler->getVerboseOutput());
}
}
return $error;
}
}

View File

@@ -14,13 +14,21 @@ use Grav\Common\Security;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Style\SymfonyStyle;
use function count;
/**
* Class SecurityCommand
* @package Grav\Console\Cli
*/
class SecurityCommand extends ConsoleCommand
{
/** @var ProgressBar $progress */
protected $progress;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('security')
@@ -28,13 +36,16 @@ class SecurityCommand extends ConsoleCommand
->setHelp('The <info>security</info> runs various security checks on your Grav site');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->initializePages();
/** @var Grav $grav */
$grav = Grav::instance();
$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);
@@ -45,28 +56,33 @@ class SecurityCommand extends ConsoleCommand
$io->newline(2);
$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>');
}
$io->error('Security Scan complete: ' . \count($output) . ' potential XSS issues found...');
$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 array $args
* @return void
*/
public function outputProgress($args)
public function outputProgress($args): void
{
switch ($args['type']) {
case 'count':

View File

@@ -16,6 +16,10 @@ use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
/**
* Class ServerCommand
* @package Grav\Console\Cli
*/
class ServerCommand extends ConsoleCommand
{
const SYMFONY_SERVER = 'Symfony Server';
@@ -28,7 +32,10 @@ class ServerCommand extends ConsoleCommand
/** @var SymfonyStyle */
protected $io;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('server')
@@ -39,7 +46,10 @@ class ServerCommand extends ConsoleCommand
->setHelp("Runs built-in web-server, Symfony first, then tries PHP's");
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$io = $this->io = new SymfonyStyle($this->input, $this->output);
@@ -59,7 +69,6 @@ class ServerCommand extends ConsoleCommand
$this->ip = '127.0.0.1';
$this->port = (int)($this->input->getOption('port') ?? 8000);
// Get an open port
while (!$this->portAvailable($this->ip, $this->port)) {
$this->port++;
@@ -80,6 +89,7 @@ class ServerCommand extends ConsoleCommand
unset($commands[self::SYMFONY_SERVER]);
}
$error = 0;
foreach ($commands as $name => $command) {
$process = $this->runProcess($name, $command);
@@ -92,18 +102,26 @@ class ServerCommand extends ConsoleCommand
($name === self::SYMFONY_SERVER && $force_symfony) ||
($name === self::PHP_SERVER)
)) {
$error = 1;
$io->error('Could not start ' . $name);
}
}
return $error;
}
/**
* @param string $name
* @param string $cmd
* @return Process
*/
protected function runProcess($name, $cmd)
{
$process = new Process($cmd);
$process = new Process([$cmd]);
$process->setTimeout(0);
$process->start();
if ($name == self::SYMFONY_SERVER && Utils::contains($process->getErrorOutput(), 'symfony: not found')) {
if ($name === self::SYMFONY_SERVER && Utils::contains($process->getErrorOutput(), 'symfony: not found')) {
$this->io->error('The symfony binary could not be found, please install the CLI tools: https://symfony.com/download');
$this->io->warning('Falling back to PHP web server...');
}
@@ -126,7 +144,7 @@ class ServerCommand extends ConsoleCommand
* @param int $port
* @return bool
*/
protected function portAvailable($ip, $port)
protected function portAvailable($ip, $port): bool
{
$fp = @fsockopen($ip, $port, $errno, $errstr, 0.1);
if (!$fp) {
@@ -134,6 +152,7 @@ class ServerCommand extends ConsoleCommand
}
fclose($fp);
return false;
}
}

View File

@@ -14,9 +14,16 @@ use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Class YamlLinterCommand
* @package Grav\Console\Cli
*/
class YamlLinterCommand extends ConsoleCommand
{
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('yamllinter')
@@ -39,15 +46,19 @@ class YamlLinterCommand extends ConsoleCommand
'Go through specific folder'
)
->setDescription('Checks various files for YAML errors')
->setHelp("Checks various files for YAML errors");
->setHelp('Checks various files for YAML errors');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$io = new SymfonyStyle($this->input, $this->output);
$io->title('Yaml Linter');
$error = 0;
if ($this->input->getOption('all')) {
$io->section('All');
$errors = YamlLinter::lint('');
@@ -55,6 +66,7 @@ class YamlLinterCommand extends ConsoleCommand
if (empty($errors)) {
$io->success('No YAML Linting issues found');
} else {
$error = 1;
$this->displayErrors($errors, $io);
}
} elseif ($folder = $this->input->getOption('folder')) {
@@ -64,6 +76,7 @@ class YamlLinterCommand extends ConsoleCommand
if (empty($errors)) {
$io->success('No YAML Linting issues found');
} else {
$error = 1;
$this->displayErrors($errors, $io);
}
} else {
@@ -73,6 +86,7 @@ class YamlLinterCommand extends ConsoleCommand
if (empty($errors)) {
$io->success('No YAML Linting issues with configuration');
} else {
$error = 1;
$this->displayErrors($errors, $io);
}
@@ -82,6 +96,7 @@ class YamlLinterCommand extends ConsoleCommand
if (empty($errors)) {
$io->success('No YAML Linting issues with pages');
} else {
$error = 1;
$this->displayErrors($errors, $io);
}
@@ -91,12 +106,20 @@ class YamlLinterCommand extends ConsoleCommand
if (empty($errors)) {
$io->success('No YAML Linting issues with blueprints');
} else {
$error = 1;
$this->displayErrors($errors, $io);
}
}
return $error;
}
protected function displayErrors($errors, SymfonyStyle $io)
/**
* @param array $errors
* @param SymfonyStyle $io
* @return void
*/
protected function displayErrors($errors, SymfonyStyle $io): void
{
$io->error('YAML Linting issues found...');
foreach ($errors as $path => $error) {

View File

@@ -11,13 +11,16 @@ namespace Grav\Console;
use Grav\Common\Grav;
use Grav\Common\Language\Language;
use Grav\Common\Page\Page;
use Grav\Common\Processors\InitializeProcessor;
use RocketTheme\Toolbox\Event\Event;
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;
@@ -38,14 +41,19 @@ class ConsoleCommand extends Command
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;
}
/**
@@ -73,6 +81,7 @@ class ConsoleCommand extends Command
* Set language to be used in CLI.
*
* @param string|null $code
* @return $this
*/
final protected function setLanguage(string $code = null)
{
@@ -88,6 +97,8 @@ class ConsoleCommand extends Command
$language->setActive($language->getDefault());
}
}
return $this;
}
/**
@@ -178,6 +189,9 @@ class ConsoleCommand extends Command
return $this;
}
/**
* @return void
*/
protected function displayGPMRelease()
{
$this->output->writeln('');

View File

@@ -9,10 +9,10 @@
namespace Grav\Console;
use Exception;
use Grav\Common\Cache;
use Grav\Common\Grav;
use Grav\Common\Composer;
use Grav\Common\GravTrait;
use Grav\Console\Cli\ClearCacheCommand;
use RocketTheme\Toolbox\File\YamlFile;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
@@ -20,6 +20,10 @@ use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Trait ConsoleTrait
* @package Grav\Console
*/
trait ConsoleTrait
{
/** @var string */
@@ -39,6 +43,7 @@ trait ConsoleTrait
*
* @param InputInterface $input
* @param OutputInterface $output
* @return void
*/
public function setupConsole(InputInterface $input, OutputInterface $output)
{
@@ -61,6 +66,7 @@ trait ConsoleTrait
/**
* @param string $path
* @return void
*/
public function isGravInstance($path)
{
@@ -89,6 +95,11 @@ trait ConsoleTrait
}
}
/**
* @param string $path
* @param string $action
* @return string|false
*/
public function composerUpdate($path, $action = 'install')
{
$composer = Composer::getComposerExecutor();
@@ -100,7 +111,7 @@ trait ConsoleTrait
* @param array $all
*
* @return int
* @throws \Exception
* @throws Exception
*/
public function clearCache($all = [])
{
@@ -113,6 +124,9 @@ trait ConsoleTrait
return $command->run($input, $this->output);
}
/**
* @return void
*/
public function invalidateCache()
{
Cache::invalidateCache();
@@ -121,7 +135,7 @@ trait ConsoleTrait
/**
* 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()
{

View File

@@ -9,6 +9,7 @@
namespace Grav\Console\Gpm;
use Exception;
use Grav\Common\Cache;
use Grav\Common\Grav;
use Grav\Common\Filesystem\Folder;
@@ -16,11 +17,18 @@ use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
use Grav\Common\GPM\Response;
use Grav\Console\ConsoleCommand;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use function is_array;
use function is_callable;
/**
* Class DirectInstallCommand
* @package Grav\Console\Gpm
*/
class DirectInstallCommand extends ConsoleCommand
{
/** @var string */
@@ -29,7 +37,10 @@ class DirectInstallCommand extends ConsoleCommand
/** @var string */
protected $destination;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('direct-install')
@@ -57,15 +68,16 @@ class DirectInstallCommand extends ConsoleCommand
}
/**
* @return bool
* @return int
*/
protected function serve()
protected function serve(): int
{
if (!class_exists(\ZipArchive::class)) {
$io = new SymfonyStyle($this->input, $this->output);
$io->title('Direct Install');
$io->error('php-zip extension needs to be enabled!');
exit;
return 1;
}
// Making sure the destination is usable
@@ -75,9 +87,9 @@ class DirectInstallCommand extends ConsoleCommand
!Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK])
) {
$this->output->writeln('<red>ERROR</red>: ' . Installer::lastErrorMsg());
exit;
}
return 1;
}
$this->all_yes = $this->input->getOption('all-yes');
@@ -91,7 +103,8 @@ class DirectInstallCommand extends ConsoleCommand
if (!$answer) {
$this->output->writeln('exiting...');
$this->output->writeln('');
exit;
return 1;
}
$tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
@@ -105,11 +118,12 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->write(' |- Downloading package... 0%');
try {
$zip = GPM::downloadPackage($package_file, $tmp_zip);
} catch (\RuntimeException $e) {
} catch (RuntimeException $e) {
$this->output->writeln('');
$this->output->writeln(" `- <red>ERROR: {$e->getMessage()}</red>");
$this->output->writeln('');
exit;
return 1;
}
if ($zip) {
@@ -138,7 +152,8 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln(' |- Extracting package... <red>failed</red>');
Folder::delete($tmp_source);
Folder::delete($tmp_zip);
exit;
return 1;
}
$this->output->write("\x0D");
@@ -152,7 +167,8 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln('');
Folder::delete($tmp_source);
Folder::delete($tmp_zip);
exit;
return 1;
}
$blueprint = GPM::getBlueprints($extracted);
@@ -181,7 +197,8 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln('');
Folder::delete($tmp_source);
Folder::delete($tmp_zip);
exit;
return 1;
}
}
}
@@ -196,7 +213,8 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln('');
Folder::delete($tmp_source);
Folder::delete($tmp_zip);
exit;
return 1;
}
$this->output->write("\x0D");
@@ -204,7 +222,7 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->write(' |- Installing package... ');
static::upgradeGrav($zip, $extracted);
$this->upgradeGrav($zip, $extracted);
} else {
$name = GPM::getPackageName($extracted);
@@ -213,7 +231,8 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln('');
Folder::delete($tmp_source);
Folder::delete($tmp_zip);
exit;
return 1;
}
$install_path = GPM::getInstallPath($type, $name);
@@ -222,14 +241,15 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->write(' |- Checking destination... ');
Installer::isValidDestination(GRAV_ROOT . DS . $install_path);
if (Installer::lastErrorCode() == Installer::IS_LINK) {
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('');
Folder::delete($tmp_source);
Folder::delete($tmp_zip);
exit;
return 1;
}
$this->output->write("\x0D");
@@ -263,6 +283,9 @@ class DirectInstallCommand extends ConsoleCommand
}
} else {
$this->output->writeln(" '- <red>ERROR: ZIP package could not be found</red>");
Folder::delete($tmp_zip);
return 1;
}
Folder::delete($tmp_zip);
@@ -270,9 +293,14 @@ class DirectInstallCommand extends ConsoleCommand
// clear cache after successful upgrade
$this->clearCache();
return true;
return 0;
}
/**
* @param string $zip
* @param string $folder
* @param false $keepFolder
*/
private function upgradeGrav($zip, $folder, $keepFolder = false)
{
static $ignores = [
@@ -306,7 +334,7 @@ class DirectInstallCommand extends ConsoleCommand
Cache::clearCache();
}
} catch (\Exception $e) {
} catch (Exception $e) {
Installer::setError($e->getMessage());
}
}

View File

@@ -14,9 +14,15 @@ use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Remote\Packages;
use Grav\Common\Utils;
use Grav\Console\ConsoleCommand;
use League\CLImate\CLImate;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Style\SymfonyStyle;
use function count;
/**
* Class IndexCommand
* @package Grav\Console\Gpm
*/
class IndexCommand extends ConsoleCommand
{
/** @var Packages */
@@ -28,7 +34,10 @@ class IndexCommand extends ConsoleCommand
/** @var array */
protected $options;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('index')
@@ -86,7 +95,10 @@ class IndexCommand extends ConsoleCommand
;
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->options = $this->input->getOptions();
$this->gpm = new GPM($this->options['force']);
@@ -95,28 +107,30 @@ class IndexCommand extends ConsoleCommand
$data = $this->filter($this->data);
$climate = new CLImate;
$climate->extend('Grav\Console\TerminalObjects\Table');
$io = new SymfonyStyle($this->input, $this->output);
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->writeln('');
$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)) {
$table = [];
$index = 0;
$section = $this->output->section('Packages table');
$table = new Table($section);
$table->setHeaders(['Count', 'Name', 'Slug', 'Version', 'Installed']);
$index = 0;
foreach ($packages as $slug => $package) {
$row = [
'Count' => $index++ + 1,
@@ -125,21 +139,24 @@ class IndexCommand extends ConsoleCommand
'Version'=> $this->version($package),
'Installed' => $this->installed($package)
];
$table[] = $row;
$table->addRow($row);
}
$climate->table($table);
$table->render();
}
$this->output->writeln('');
$io->writeln('');
}
$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->writeln('');
$io->writeln('Or you can install a package by typing:');
$io->writeln(" <green>{$this->argv} install <cyan><package></cyan></green>");
$io->writeln('');
return 0;
}
/**
@@ -205,7 +222,7 @@ class IndexCommand extends ConsoleCommand
$this->options['desc']
];
if (\count(array_filter($filter))) {
if (count(array_filter($filter))) {
foreach ($data as $type => $packages) {
foreach ($packages as $slug => $package) {
$filter = true;

View File

@@ -15,6 +15,10 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Class InfoCommand
* @package Grav\Console\Gpm
*/
class InfoCommand extends ConsoleCommand
{
/** @var array */
@@ -26,7 +30,10 @@ class InfoCommand extends ConsoleCommand
/** @var string */
protected $all_yes;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('info')
@@ -48,13 +55,13 @@ class InfoCommand extends ConsoleCommand
'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');
->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'));
@@ -70,7 +77,8 @@ class InfoCommand extends ConsoleCommand
$this->output->writeln('You can list all the available packages by typing:');
$this->output->writeln(" <green>{$this->argv} index</green>");
$this->output->writeln('');
exit;
return 1;
}
$this->output->writeln("Found package <cyan>'{$this->input->getArgument('package')}'</cyan> under the '<green>" . ucfirst($foundPackage->package_type) . "</green>' section");
@@ -147,7 +155,7 @@ class InfoCommand extends ConsoleCommand
$this->output->writeln('');
foreach ($changelog as $version => $log) {
$title = $version . ' [' . $log['date'] . ']';
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', function ($match) {
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', static function ($match) {
return "\n" . ucfirst($match[1]) . ':';
}, $log['content']);
@@ -176,5 +184,7 @@ class InfoCommand extends ConsoleCommand
}
$this->output->writeln('');
return 0;
}
}

View File

@@ -9,6 +9,7 @@
namespace Grav\Console\Gpm;
use Exception;
use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
@@ -22,9 +23,15 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use function array_key_exists;
use function count;
\define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/(.*)/');
/**
* Class InstallCommand
* @package Grav\Console\Gpm
*/
class InstallCommand extends ConsoleCommand
{
/** @var array */
@@ -54,7 +61,10 @@ class InstallCommand extends ConsoleCommand
/** @var string */
protected $all_yes;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('install')
@@ -97,15 +107,16 @@ class InstallCommand extends ConsoleCommand
}
/**
* @return bool
* @return int
*/
protected function serve()
protected function serve(): int
{
if (!class_exists(\ZipArchive::class)) {
$io = new SymfonyStyle($this->input, $this->output);
$io->title('GPM Install');
$io->error('php-zip extension needs to be enabled!');
exit;
return 1;
}
$this->gpm = new GPM($this->input->getOption('force'));
@@ -124,7 +135,8 @@ class InstallCommand extends ConsoleCommand
!Installer::isValidDestination($this->destination, [Installer::EXISTS, Installer::IS_LINK])
) {
$this->output->writeln('<red>ERROR</red>: ' . Installer::lastErrorMsg());
exit;
return 1;
}
$this->output->writeln('');
@@ -132,10 +144,11 @@ class InstallCommand extends ConsoleCommand
if (!$this->data['total']) {
$this->output->writeln('Nothing to install.');
$this->output->writeln('');
exit;
return 0;
}
if (\count($this->data['not_found'])) {
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'])
@@ -161,11 +174,12 @@ class InstallCommand extends ConsoleCommand
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;
return 1;
}
if ($dependencies) {
@@ -173,9 +187,10 @@ class InstallCommand extends ConsoleCommand
$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) {
} catch (Exception $e) {
$this->output->writeln('<red>Installation aborted</red>');
return false;
return 1;
}
$this->output->writeln('<green>Dependencies are OK</green>');
@@ -197,9 +212,10 @@ class InstallCommand extends ConsoleCommand
try {
$this->askConfirmationIfMajorVersionUpdated($package);
$this->gpm->checkNoOtherPackageNeedsThisDependencyInALowerVersion($package->slug, $package->available, array_keys($data));
} catch (\Exception $e) {
} catch (Exception $e) {
$this->output->writeln("<red>{$e->getMessage()}</red>");
return false;
return 1;
}
$helper = $this->getHelper('question');
@@ -223,7 +239,7 @@ class InstallCommand extends ConsoleCommand
}
}
if (\count($this->demo_processing) > 0) {
if (count($this->demo_processing) > 0) {
foreach ($this->demo_processing as $package) {
$this->installDemoContent($package);
}
@@ -232,15 +248,16 @@ 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 $package
* @return void
*/
public function askConfirmationIfMajorVersionUpdated($package)
public function askConfirmationIfMajorVersionUpdated($package): void
{
$helper = $this->getHelper('question');
$package_name = $package->name;
@@ -273,15 +290,15 @@ 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($dependencies, $type, $message, $required = true): void
{
$packages = array_filter($dependencies, function ($action) use ($type) {
$packages = array_filter($dependencies, static function ($action) use ($type) {
return $action === $type;
});
if (\count($packages) > 0) {
if (count($packages) > 0) {
$this->output->writeln($message);
foreach ($packages as $dependencyName => $dependencyVersion) {
@@ -298,13 +315,13 @@ class InstallCommand extends ConsoleCommand
$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';
@@ -319,10 +336,8 @@ class InstallCommand extends ConsoleCommand
$this->processPackage($package, $type === 'update');
}
$this->output->writeln('');
} else {
if ($required) {
throw new \Exception();
}
} elseif ($required) {
throw new Exception();
}
}
}
@@ -330,8 +345,9 @@ class InstallCommand extends ConsoleCommand
/**
* @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, $is_update = false): void
{
if (!$package) {
$this->output->writeln('<red>Package not found on the GPM!</red>');
@@ -355,8 +371,9 @@ class InstallCommand extends ConsoleCommand
* Add package to the queue to process the demo content, if demo content exists
*
* @param Package $package
* @return void
*/
private function processDemo($package)
private function processDemo($package): void
{
$demo_dir = $this->destination . DS . $package->install_path . DS . '_demo';
if (file_exists($demo_dir)) {
@@ -368,8 +385,9 @@ class InstallCommand extends ConsoleCommand
* Prompt to install the demo content of a package
*
* @param Package $package
* @return void
*/
private function installDemoContent($package)
private function installDemoContent($package): void
{
$demo_dir = $this->destination . DS . $package->install_path . DS . '_demo';
@@ -424,8 +442,7 @@ class InstallCommand extends ConsoleCommand
/**
* @param Package $package
*
* @return array|bool
* @return array|false
*/
private function getGitRegexMatches($package)
{
@@ -442,8 +459,7 @@ class InstallCommand extends ConsoleCommand
/**
* @param Package $package
*
* @return bool|string
* @return string|false
*/
private function getSymlinkSource($package)
{
@@ -470,10 +486,10 @@ class InstallCommand extends ConsoleCommand
/**
* @param Package $package
* @return void
*/
private function processSymlink($package)
private function processSymlink($package): void
{
exec('cd ' . $this->destination);
$to = $this->destination . DS . $package->install_path;
@@ -491,8 +507,7 @@ class InstallCommand extends ConsoleCommand
if (!$checks) {
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
$this->output->writeln('');
} else {
if (file_exists($to)) {
} elseif (file_exists($to)) {
$this->output->writeln(" '- <red>Symlink cannot overwrite an existing package, please remove first</red>");
$this->output->writeln('');
} else {
@@ -503,7 +518,6 @@ class InstallCommand extends ConsoleCommand
$this->output->writeln(" '- <green>Success!</green> ");
$this->output->writeln('');
}
}
return;
}
@@ -515,12 +529,11 @@ class InstallCommand extends ConsoleCommand
/**
* @param Package $package
* @param bool $is_update
*
* @return bool
*/
private function processGpm($package, $is_update = false)
{
$version = isset($package->available) ? $package->available : $package->version;
$version = $package->available ?? $package->version;
$license = Licenses::get($package->slug);
$this->output->writeln("Preparing to install <cyan>{$package->name}</cyan> [v{$version}]");
@@ -561,7 +574,6 @@ class InstallCommand extends ConsoleCommand
/**
* @param Package $package
* @param string|null $license
*
* @return string|null
*/
private function downloadPackage($package, $license = null)
@@ -573,7 +585,7 @@ class InstallCommand extends ConsoleCommand
$query = '';
if (!empty($package->premium)) {
$query = \json_encode(array_merge(
$query = json_encode(array_merge(
$package->premium,
[
'slug' => $package->slug,
@@ -588,7 +600,7 @@ class InstallCommand extends ConsoleCommand
try {
$output = Response::get($package->zipball_url . $query, [], [$this, 'progress']);
} catch (\Exception $e) {
} catch (Exception $e) {
$error = str_replace("\n", "\n | '- ", $e->getMessage());
$this->output->write("\x0D");
// extra white spaces to clear out the buffer properly
@@ -611,16 +623,15 @@ class InstallCommand extends ConsoleCommand
/**
* @param Package $package
*
* @return bool
*/
private function checkDestination($package)
private function checkDestination($package): bool
{
$question_helper = $this->getHelper('question');
Installer::isValidDestination($this->destination . DS . $package->install_path);
if (Installer::lastErrorCode() == Installer::IS_LINK) {
if (Installer::lastErrorCode() === Installer::IS_LINK) {
$this->output->write("\x0D");
$this->output->writeln(' |- Checking destination... <yellow>symbolic link</yellow>');
@@ -656,7 +667,6 @@ class InstallCommand extends ConsoleCommand
*
* @param Package $package
* @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)
@@ -692,8 +702,9 @@ class InstallCommand extends ConsoleCommand
/**
* @param array $progress
* @return void
*/
public function progress($progress)
public function progress($progress): void
{
$this->output->write("\x0D");
$this->output->write(' |- Downloading package... ' . str_pad(

View File

@@ -9,6 +9,7 @@
namespace Grav\Console\Gpm;
use Exception;
use Grav\Common\Cache;
use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\Installer;
@@ -20,7 +21,13 @@ use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use function is_callable;
use function strlen;
/**
* Class SelfupgradeCommand
* @package Grav\Console\Gpm
*/
class SelfupgradeCommand extends ConsoleCommand
{
/** @var array */
@@ -47,7 +54,10 @@ class SelfupgradeCommand extends ConsoleCommand
/** @var int */
protected $timeout;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('self-upgrade')
@@ -81,13 +91,17 @@ class SelfupgradeCommand extends ConsoleCommand
->setHelp('The <info>update</info> command updates Grav itself when a new version is available');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
if (!class_exists(\ZipArchive::class)) {
$io = new SymfonyStyle($this->input, $this->output);
$io->title('GPM Self Upgrade');
$io->error('php-zip extension needs to be enabled!');
exit;
return 1;
}
$this->upgrader = new Upgrader($this->input->getOption('force'));
@@ -111,12 +125,14 @@ class SelfupgradeCommand extends ConsoleCommand
$this->output->writeln('');
$this->output->writeln('Selfupgrade aborted.');
$this->output->writeln('');
exit;
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;
return 0;
}
Installer::isValidDestination(GRAV_ROOT . '/system');
@@ -124,7 +140,8 @@ class SelfupgradeCommand extends ConsoleCommand
$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;
return 1;
}
// not used but preloaded just in case!
@@ -148,12 +165,12 @@ class SelfupgradeCommand extends ConsoleCommand
$this->output->writeln('');
foreach ($changelog as $version => $log) {
$title = $version . ' [' . $log['date'] . ']';
$content = preg_replace_callback('/\d\.\s\[\]\(#(.*)\)/', function ($match) {
$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(str_repeat('-', strlen($title)));
$this->output->writeln($content);
$this->output->writeln('');
}
@@ -168,7 +185,7 @@ class SelfupgradeCommand extends ConsoleCommand
if (!$answer) {
$this->output->writeln('Aborting...');
exit;
return 1;
}
}
@@ -181,9 +198,11 @@ class SelfupgradeCommand extends ConsoleCommand
$this->output->write(' |- Installing upgrade... ');
$installation = $this->upgrade();
$error = 0;
if (!$installation) {
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
$this->output->writeln('');
$error = 1;
} else {
$this->output->writeln(" '- <green>Success!</green> ");
$this->output->writeln('');
@@ -191,11 +210,12 @@ class SelfupgradeCommand extends ConsoleCommand
// clear cache after successful upgrade
$this->clearCache(['all']);
return $error;
}
/**
* @param array $package
*
* @return string
*/
private function download($package)
@@ -235,7 +255,7 @@ class SelfupgradeCommand extends ConsoleCommand
$folder = false;
}
static::upgradeGrav($this->file, $folder);
$this->upgradeGrav($this->file, $folder);
$errorCode = Installer::lastErrorCode();
@@ -261,8 +281,9 @@ class SelfupgradeCommand extends ConsoleCommand
/**
* @param array $progress
* @return void
*/
public function progress($progress)
public function progress($progress): void
{
$this->output->write("\x0D");
$this->output->write(" |- Downloading upgrade [{$this->formatBytes($progress['filesize']) }]... " . str_pad(
@@ -276,7 +297,6 @@ class SelfupgradeCommand extends ConsoleCommand
/**
* @param int|float $size
* @param int $precision
*
* @return string
*/
public function formatBytes($size, $precision = 2)
@@ -287,6 +307,11 @@ class SelfupgradeCommand extends ConsoleCommand
return round(1024 ** ($base - floor($base)), $precision) . $suffixes[(int)floor($base)];
}
/**
* @param string $zip
* @param string $folder
* @param false $keepFolder
*/
private function upgradeGrav($zip, $folder, $keepFolder = false)
{
static $ignores = [
@@ -320,7 +345,7 @@ class SelfupgradeCommand extends ConsoleCommand
Cache::clearCache();
}
} catch (\Exception $e) {
} catch (Exception $e) {
Installer::setError($e->getMessage());
}
}

View File

@@ -17,7 +17,14 @@ use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use function count;
use function in_array;
use function is_array;
/**
* Class UninstallCommand
* @package Grav\Console\Gpm
*/
class UninstallCommand extends ConsoleCommand
{
/** @var array */
@@ -41,7 +48,10 @@ class UninstallCommand extends ConsoleCommand
/** @var string */
protected $all_yes;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('uninstall')
@@ -60,7 +70,10 @@ class UninstallCommand extends ConsoleCommand
->setHelp('The <info>uninstall</info> command allows to uninstall plugins and themes');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
$this->gpm = new GPM();
@@ -87,7 +100,8 @@ class UninstallCommand extends ConsoleCommand
if (!$this->data['total']) {
$this->output->writeln('Nothing to uninstall.');
$this->output->writeln('');
exit;
return 0;
}
if (count($this->data['not_found'])) {
@@ -99,6 +113,7 @@ class UninstallCommand extends ConsoleCommand
unset($this->data['not_found'], $this->data['total']);
$error = 0;
foreach ($this->data as $slug => $package) {
$this->output->writeln("Preparing to uninstall <cyan>{$package->name}</cyan> [v{$package->version}]");
@@ -108,11 +123,13 @@ class UninstallCommand extends ConsoleCommand
if (!$checks) {
$this->output->writeln(" '- <red>Installation failed or aborted.</red>");
$this->output->writeln('');
$error = 1;
} else {
$uninstall = $this->uninstallPackage($slug, $package);
if (!$uninstall) {
$this->output->writeln(" '- <red>Uninstallation failed or aborted.</red>");
$error = 1;
} else {
$this->output->writeln(" '- <green>Success!</green> ");
}
@@ -121,13 +138,13 @@ class UninstallCommand extends ConsoleCommand
// clear cache after successful upgrade
$this->clearCache();
}
return $error;
}
/**
* @param string $slug
* @param Package $package
*
* @return bool
*/
private function uninstallPackage($slug, $package, $is_dependency = false)
@@ -143,7 +160,7 @@ class UninstallCommand extends ConsoleCommand
$this->output->writeln('');
$this->output->writeln('<red>Uninstallation failed.</red>');
$this->output->writeln('');
if (\count($dependent_packages) > ($is_dependency ? 2 : 1)) {
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.');
} else {
$this->output->writeln('The installed package <cyan>' . implode('</cyan>, <cyan>', $dependent_packages) . '</cyan> depends on this package. Please remove it first.');
@@ -158,23 +175,21 @@ class UninstallCommand extends ConsoleCommand
if ($is_dependency) {
foreach ($dependencies as $key => $dependency) {
if (\in_array($dependency['name'], $this->dependencies, true)) {
if (in_array($dependency['name'], $this->dependencies, true)) {
unset($dependencies[$key]);
}
}
} else {
if (\count($dependencies) > 0) {
} elseif (count($dependencies) > 0) {
$this->output->writeln(' `- Dependencies found...');
$this->output->writeln('');
}
}
$questionHelper = $this->getHelper('question');
foreach ($dependencies as $dependency) {
$this->dependencies[] = $dependency['name'];
if (\is_array($dependency)) {
if (is_array($dependency)) {
$dependency = $dependency['name'];
}
if ($dependency === 'grav' || $dependency === 'php') {
@@ -239,10 +254,8 @@ class UninstallCommand extends ConsoleCommand
/**
* @param string $slug
* @param Package $package
*
* @return bool
*/
private function checkDestination($slug, $package)
{
$questionHelper = $this->getHelper('question');
@@ -289,6 +302,7 @@ class UninstallCommand extends ConsoleCommand
{
$path = Grav::instance()['locator']->findResource($package->package_type . '://' . $slug);
Installer::isValidDestination($path);
return Installer::lastErrorCode();
}
}

View File

@@ -18,7 +18,13 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Style\SymfonyStyle;
use function array_key_exists;
use function count;
/**
* Class UpdateCommand
* @package Grav\Console\Gpm
*/
class UpdateCommand extends ConsoleCommand
{
/** @var array */
@@ -45,7 +51,10 @@ class UpdateCommand extends ConsoleCommand
/** @var Upgrader */
protected $upgrader;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('update')
@@ -95,13 +104,17 @@ class UpdateCommand extends ConsoleCommand
->setHelp('The <info>update</info> command updates plugins and themes when a new version is available');
}
protected function serve()
/**
* @return int
*/
protected function serve(): int
{
if (!class_exists(\ZipArchive::class)) {
$io = new SymfonyStyle($this->input, $this->output);
$io->title('GPM Update');
$io->error('php-zip extension needs to be enabled!');
exit;
return 1;
}
$this->upgrader = new Upgrader($this->input->getOption('force'));
@@ -116,7 +129,8 @@ class UpdateCommand extends ConsoleCommand
if (!$answer) {
$this->output->writeln('<red>Update aborted. Exiting...</red>');
exit;
return 1;
}
}
@@ -152,7 +166,8 @@ class UpdateCommand extends ConsoleCommand
if (!$this->overwrite && !$this->data['total']) {
$this->output->writeln('Nothing to update.');
exit;
return 0;
}
$this->output->write("Found <green>{$this->gpm->countInstalled()}</green> packages installed of which <magenta>{$this->data['total']}</magenta>{$description}");
@@ -170,7 +185,7 @@ class UpdateCommand extends ConsoleCommand
$index = 0;
foreach ($this->data as $packages) {
foreach ($packages as $slug => $package) {
if (!array_key_exists($slug, $limit_to) && \count($only_packages)) {
if (!array_key_exists($slug, $limit_to) && count($only_packages)) {
continue;
}
@@ -199,7 +214,8 @@ class UpdateCommand extends ConsoleCommand
if (!$answer) {
$this->output->writeln('<red>Update aborted. Exiting...</red>');
exit;
return 1;
}
}
@@ -217,13 +233,15 @@ class UpdateCommand extends ConsoleCommand
if ($command_exec != 0) {
$this->output->writeln('<red>Error:</red> An error occurred while trying to install the packages');
exit;
return 1;
}
return 0;
}
/**
* @param array $only_packages
*
* @return array
*/
private function userInputPackages($only_packages)
@@ -231,7 +249,7 @@ class UpdateCommand extends ConsoleCommand
$found = ['total' => 0];
$ignore = [];
if (!\count($only_packages)) {
if (!count($only_packages)) {
$this->output->writeln('');
} else {
foreach ($only_packages as $only_package) {
@@ -262,7 +280,7 @@ class UpdateCommand extends ConsoleCommand
) . '</cyan>');
}
if (\count($ignore)) {
if (count($ignore)) {
$this->output->writeln('');
$this->output->writeln('Packages not found or not requiring updates: <red>' . implode(
'</red>, <red>',

View File

@@ -11,17 +11,26 @@ namespace Grav\Console\Gpm;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Upgrader;
use Grav\Common\Grav;
use Grav\Console\ConsoleCommand;
use RocketTheme\Toolbox\File\YamlFile;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use function count;
/**
* Class VersionCommand
* @package Grav\Console\Gpm
*/
class VersionCommand extends ConsoleCommand
{
/** @var GPM */
protected $gpm;
protected function configure()
/**
* @return void
*/
protected function configure(): void
{
$this
->setName('version')
@@ -41,9 +50,9 @@ class VersionCommand extends ConsoleCommand
}
/**
* @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');
@@ -70,7 +79,7 @@ class VersionCommand extends ConsoleCommand
}
} 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');
@@ -107,5 +116,7 @@ class VersionCommand extends ConsoleCommand
$this->output->writeln("Package <red>{$package}</red> not found");
}
}
return 0;
}
}

View File

@@ -9,8 +9,15 @@
namespace Grav\Console\TerminalObjects;
/**
* Class Table
* @package Grav\Console\TerminalObjects
*/
class Table extends \League\CLImate\TerminalObject\Basic\Table
{
/**
* @return array
*/
public function result()
{
$this->column_widths = $this->getColumnWidths();