From 26fff3a0b737f69df60e32548dfec3afe4764830 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:13:32 +0100 Subject: [PATCH] WIP: `cr:list` command --- .../ContentStreamCommandController.php | 18 ++++- .../Classes/Command/CrCommandController.php | 74 +++++++++++++++++++ .../Classes/ContentRepositoryRegistry.php | 13 ++++ .../Classes/Command/SiteCommandController.php | 2 + 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/ContentStreamCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/ContentStreamCommandController.php index a692a22fdd7..5b1a6f4876b 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/ContentStreamCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/ContentStreamCommandController.php @@ -28,9 +28,14 @@ class ContentStreamCommandController extends CommandController * If you also call with "--removeTemporary", will delete ALL content streams which are currently not assigned * to a workspace (f.e. dangling ones in FORKED or CREATED.). */ - public function pruneCommand(string $contentRepositoryIdentifier = 'default', bool $removeTemporary = false): void + public function pruneCommand(string $contentRepository = 'default', bool $removeTemporary = false): void { - $contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier); + if (!$this->output->askConfirmation(sprintf('> This operation in "%s" cannot be reverted. Are you sure to proceed? (y/n) ', $contentRepository), false)) { + $this->outputLine('Abort.'); + return; + } + + $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); $contentStreamPruner = $this->contentRepositoryRegistry->buildService($contentRepositoryId, new ContentStreamPrunerFactory()); $unusedContentStreams = $contentStreamPruner->prune($removeTemporary); @@ -47,9 +52,14 @@ public function pruneCommand(string $contentRepositoryIdentifier = 'default', bo /** * Remove unused and deleted content streams from the event stream; effectively REMOVING information completely */ - public function pruneRemovedFromEventStreamCommand(string $contentRepositoryIdentifier = 'default'): void + public function pruneRemovedFromEventStreamCommand(string $contentRepository = 'default'): void { - $contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier); + if (!$this->output->askConfirmation(sprintf('> This operation in "%s" cannot be reverted. Are you sure to proceed? (y/n) ', $contentRepository), false)) { + $this->outputLine('Abort.'); + return; + } + + $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); $contentStreamPruner = $this->contentRepositoryRegistry->buildService($contentRepositoryId, new ContentStreamPrunerFactory()); $unusedContentStreams = $contentStreamPruner->pruneRemovedFromEventStream(); diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php index c82eebe9106..f5bfbcdfca1 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php @@ -7,12 +7,16 @@ use Neos\ContentRepository\Core\Projection\CatchUpOptions; use Neos\ContentRepository\Core\Projection\ProjectionStatusType; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; +use Neos\ContentRepositoryRegistry\Exception\InvalidConfigurationException; use Neos\ContentRepositoryRegistry\Service\ProjectionReplayServiceFactory; use Neos\EventStore\Model\Event\SequenceNumber; use Neos\EventStore\Model\EventStore\StatusType; use Neos\Flow\Cli\CommandController; use Neos\ContentRepository\Core\Service\ContentStreamPrunerFactory; use Neos\ContentRepository\Core\Service\WorkspaceMaintenanceServiceFactory; +use Neos\Flow\Persistence\Doctrine\Exception\DatabaseException; +use Neos\Neos\Domain\Model\Site; +use Neos\Neos\Domain\Repository\SiteRepository; use Symfony\Component\Console\Output\Output; final class CrCommandController extends CommandController @@ -21,6 +25,7 @@ final class CrCommandController extends CommandController public function __construct( private readonly ContentRepositoryRegistry $contentRepositoryRegistry, private readonly ProjectionReplayServiceFactory $projectionServiceFactory, + private readonly SiteRepository $siteRepository, ) { parent::__construct(); } @@ -217,4 +222,73 @@ public function pruneCommand(string $contentRepository = 'default', bool $force $this->outputLine('Done.'); } + + public function listCommand() + { + $rows = []; + + /** @var list $sites */ + $sites = []; + try { + $sites = iterator_to_array($this->siteRepository->findAll()); + } catch (DatabaseException) { + // doctrine might have not been migrated yet or no database is connected. + $this->outputLine('Site repository is not accessible.'); + } + + foreach ($this->contentRepositoryRegistry->getAllContentRepositoryIds() as $contentRepositoryId) { + $contentRepository = null; + try { + $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); + } catch (InvalidConfigurationException $exception) { + $this->outputLine('Content repository %s is not well configures: %s.', [$contentRepositoryId->value, $exception->getMessage()]); + } + + $configuredSites = []; + foreach ($sites as $site) { + if (!$site->getConfiguration()->contentRepositoryId->equals($contentRepositoryId)) { + continue; + } + $configuredSites[] = $site->getName(); + } + + $statusString = '-'; + $workspacesString = '-'; + $contentStreamsString = '-'; + $nodesString = '-'; + + if ($contentRepository) { + $statusString = $contentRepository->status()->isOk() ? 'okay' : 'not okay'; + + try { + $workspacesString = sprintf('%d entries', count($contentRepository->getWorkspaceFinder()->findAll())); + } catch (\Throwable $e) { + $this->outputLine('WorkspaceFinder of %s not functional: %s.', [$contentRepositoryId->value, $e->getMessage()]); + } + + try { + $contentStreamsString = sprintf('%d entries', iterator_count($contentRepository->getContentStreamFinder()->findAllIds())); + } catch (\Throwable $e) { + $this->outputLine('ContentStreamFinder of %s not functional: %s.', [$contentRepositoryId->value, $e->getMessage()]); + } + + try { + $nodesString = sprintf('%d entries', $contentRepository->getContentGraph()->countNodes()); + } catch (\Throwable $e) { + $this->outputLine('ContentGraph of %s not functional: %s.', [$contentRepositoryId->value, $e->getMessage()]); + } + } + + $rows[] = [ + $contentRepositoryId->value, + $statusString, + join(', ', $configuredSites) ?: '-', + $workspacesString, + $contentStreamsString, + $nodesString + ]; + } + + $this->output->outputTable($rows, ['Identifier', 'Status', 'Sites', 'Workspaces', 'Contentstreams', 'Nodes']); + } } diff --git a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php index 367ba4da484..d986fa88dcd 100644 --- a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php +++ b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php @@ -64,6 +64,19 @@ public function get(ContentRepositoryId $contentRepositoryId): ContentRepository return $this->getFactory($contentRepositoryId)->getOrBuild(); } + /** + * @return iterable + */ + public function getAllContentRepositoryIds(): iterable + { + if (!is_array($this->settings['contentRepositories'] ?? null)) { + throw InvalidConfigurationException::fromMessage('No Content Repositories are configured'); + } + foreach (array_keys($this->settings['contentRepositories']) as $contentRepositoryId) { + yield ContentRepositoryId::fromString($contentRepositoryId); + } + } + /** * @internal for test cases only */ diff --git a/Neos.Neos/Classes/Command/SiteCommandController.php b/Neos.Neos/Classes/Command/SiteCommandController.php index 888c0923ed3..c1629333a11 100644 --- a/Neos.Neos/Classes/Command/SiteCommandController.php +++ b/Neos.Neos/Classes/Command/SiteCommandController.php @@ -175,6 +175,8 @@ public function listCommand() } } + // todo use outputTable + $this->outputLine(); $this->outputLine(' ' . str_pad('Name', $longestSiteName + 15) . str_pad('Node name', $longestNodeName + 15)