diff --git a/Classes/Command/AbstractCommandController.php b/Classes/Command/AbstractCommandController.php index 6ef5b3b..1069a22 100644 --- a/Classes/Command/AbstractCommandController.php +++ b/Classes/Command/AbstractCommandController.php @@ -9,10 +9,10 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\Core\Bootstrap; use Neos\Flow\Cli\CommandController; +use Sitegeist\MagicWand\Domain\Service\ConfigurationService; abstract class AbstractCommandController extends CommandController { - const HIDE_RESULT = 1; const HIDE_COMMAND = 2; @@ -44,6 +44,12 @@ abstract class AbstractCommandController extends CommandController */ protected $flowCommand; + /** + * @Flow\Inject + * @var ConfigurationService + */ + protected $configurationService; + /** * @param string $commands * @param array $arguments diff --git a/Classes/Command/CloneCommandController.php b/Classes/Command/CloneCommandController.php index f50b713..2ee5052 100644 --- a/Classes/Command/CloneCommandController.php +++ b/Classes/Command/CloneCommandController.php @@ -10,7 +10,6 @@ use Neos\Utility\Arrays; use Neos\Flow\Core\Bootstrap; use Sitegeist\MagicWand\DBAL\SimpleDBAL; -use Sitegeist\MagicWand\Domain\Service\ConfigurationService; use Symfony\Component\Yaml\Yaml; /** @@ -43,12 +42,6 @@ class CloneCommandController extends AbstractCommandController */ protected $dbal; - /** - * @Flow\Inject - * @var ConfigurationService - */ - protected $configurationService; - /** * Show the list of predefined clone configurations */ diff --git a/Classes/Command/StashCommandController.php b/Classes/Command/StashCommandController.php index 4efa509..81f5c63 100644 --- a/Classes/Command/StashCommandController.php +++ b/Classes/Command/StashCommandController.php @@ -15,9 +15,6 @@ */ class StashCommandController extends AbstractCommandController { - - - /** * Creates a new stash entry with the given name. * @@ -32,10 +29,7 @@ public function createCommand($name) # Build Paths # ####################### - $basePath = sprintf( - FLOW_PATH_ROOT . 'Data/MagicWandStash/%s', - $name - ); + $basePath = $this->getStashEntryPath($name); $databaseDestination = $basePath . '/database.sql'; $persistentDestination = $basePath . '/persistent/'; @@ -55,6 +49,24 @@ public function createCommand($name) $this->addSecret($this->databaseConfiguration['user']); $this->addSecret($this->databaseConfiguration['password']); + ###################### + # Write Manifest # + ###################### + $this->renderHeadLine('Write Manifest'); + $presetName = $this->configurationService->getCurrentPreset(); + $presetConfiguration = $this->configurationService->getCurrentConfiguration(); + $cloneTimestamp = $this->configurationService->getMostRecentCloneTimeStamp(); + $stashTimestamp = time(); + + $this->writeStashEntryManifest($name, [ + 'preset' => [ + 'name' => $presetName, + 'configuration' => $presetConfiguration + ], + 'cloned_at' => $cloneTimestamp, + 'stashed_at' => $stashTimestamp + ]); + ###################### # Backup Database # ###################### @@ -102,6 +114,8 @@ public function createCommand($name) */ public function listCommand() { + $head = ['Name', 'Stashed At', 'From Preset', 'Cloned At']; + $rows = []; $basePath = sprintf(FLOW_PATH_ROOT . 'Data/MagicWandStash'); if (!is_dir($basePath)) { @@ -114,7 +128,16 @@ public function listCommand() foreach ($baseDir as $entry) { if (!in_array($entry, ['.', '..'])) { - $this->renderLine(' • %s', [$entry->getFilename()]); + $stashEntryName = $entry->getFilename(); + $manifest = $this->readStashEntryManifest($stashEntryName) ?: []; + + $rows[] = [ + $stashEntryName, + $manifest['stashed_at'] ? date('Y-m-d H:i:s', $manifest['stashed_at']) : 'N/A', + isset($manifest['preset']['name']) ? $manifest['preset']['name'] : 'N/A', + $manifest['cloned_at'] ? date('Y-m-d H:i:s', $manifest['cloned_at']) : 'N/A', + ]; + $anyEntry = true; } } @@ -123,6 +146,8 @@ public function listCommand() $this->renderLine('Stash is empty.'); $this->quit(1); } + + $this->output->outputTable($rows, $head); } /** @@ -158,7 +183,7 @@ public function clearCommand() */ public function restoreCommand($name, $yes = false, $keepDb = false) { - $basePath = sprintf(FLOW_PATH_ROOT . 'Data/MagicWandStash/%s', $name); + $basePath = $this->getStashEntryPath($name); $this->restoreStashEntry($basePath, $name, $yes, true, $keepDb); } @@ -277,7 +302,7 @@ protected function restoreStashEntry($source, $name, $force = false, $preserve = . '`; CREATE DATABASE `' . $this->databaseConfiguration['dbname'] . '` collate utf8_unicode_ci;'; - + $this->executeLocalShellCommand( 'echo %s | mysql --host=%s --user=%s --password=%s', [ @@ -347,6 +372,13 @@ protected function restoreStashEntry($source, $name, $force = false, $preserve = $this->renderHeadLine('Publish Resources'); $this->executeLocalFlowCommand('resource:publish'); + ############################# + # Restore Clone Information # + ############################# + if($manifest = $this->readStashEntryManifest($name)) { + $this->configurationService->setCurrentStashEntry($name, $manifest); + } + ################# # Final Message # ################# @@ -372,4 +404,57 @@ protected function checkConfiguration() $this->renderLine(' - Configuration seems ok ...'); } + + /** + * @param string $stashEntryName + * @return string + */ + protected function getStashEntryPath(string $stashEntryName): string + { + return sprintf( + FLOW_PATH_ROOT . 'Data/MagicWandStash/%s', + $stashEntryName + ); + } + + /** + * @param string $stashEntryName + * @return array|null + */ + protected function readStashEntryManifest(string $stashEntryName): ?array + { + $manifestDestination = $this->getStashEntryPath($stashEntryName) . '/manifest.json'; + + if (file_exists($manifestDestination)) { + if ($manifest = json_decode(file_get_contents($manifestDestination), true)) { + if (is_array($manifest)) { + return $manifest; + } + } + + $this->outputLine('Manifest file has been corrupted.'); + } + + return null; + } + + /** + * @param string $stashEntryName + * @param array $manifest + * @return void + */ + protected function writeStashEntryManifest(string $stashEntryName, array $manifest): void + { + $manifestDestination = $this->getStashEntryPath($stashEntryName) . '/manifest.json'; + + // Create directory, if not exists + if (!file_exists(dirname($manifestDestination))) { + FileUtils::createDirectoryRecursively(dirname($manifestDestination)); + } + + // Write manifest file + file_put_contents($manifestDestination, json_encode($manifest, JSON_PRETTY_PRINT)); + + $this->outputLine('Wrote "%s"', [$manifestDestination]); + } } diff --git a/Classes/Domain/Service/ConfigurationService.php b/Classes/Domain/Service/ConfigurationService.php index d48c71e..b461d46 100644 --- a/Classes/Domain/Service/ConfigurationService.php +++ b/Classes/Domain/Service/ConfigurationService.php @@ -19,17 +19,46 @@ class ConfigurationService */ protected $clonePresets; + /** + * @return string + */ + public function getCurrentPreset(): ?string + { + $clonePresetInformation = $this->clonePresetInformationCache->get('current'); + + if ($clonePresetInformation && is_array($clonePresetInformation) && isset($clonePresetInformation['presetName'])) { + return $clonePresetInformation['presetName']; + } + + return null; + } + + /** + * @return integer + */ + public function getMostRecentCloneTimeStamp(): ?int + { + $clonePresetInformation = $this->clonePresetInformationCache->get('current'); + + if ($clonePresetInformation && is_array($clonePresetInformation) && isset($clonePresetInformation['cloned_at'])) { + return intval($clonePresetInformation['cloned_at']); + } + + return null; + } + /** * @return array */ public function getCurrentConfiguration(): array { - $cloneInformations = $this->clonePresetInformationCache->get('current'); - if ($cloneInformations && is_array($this->clonePresets) && array_key_exists($cloneInformations['presetName'], $this->clonePresets)) { - return $this->clonePresets[$cloneInformations['presetName']]; - } else { - return []; + if ($presetName = $this->getCurrentPreset()) { + if (is_array($this->clonePresets) && array_key_exists($presetName, $this->clonePresets)) { + return $this->clonePresets[$presetName]; + } } + + return []; } /** @@ -44,17 +73,56 @@ public function getCurrentConfigurationByPath($path) /** * @return boolean */ - public function hasConfiguration(): bool + public function hasCurrentPreset(): bool { - return $this->clonePresetInformationCache->has('current'); + if ($this->clonePresetInformationCache->has('current')) { + return true; + } + + $clonePresetInformation = $this->clonePresetInformationCache->get('current'); + + if ($clonePresetInformation && is_array($clonePresetInformation) && isset($clonePresetInformation['presetName'])) { + return true; + } + + return false; } /** * @param $presetName string + * @return void * @throws \Neos\Cache\Exception */ public function setCurrentPreset(string $presetName): void { - $this->clonePresetInformationCache->set('current', ['presetName' => $presetName, 'timestamp' => time()]); + $this->clonePresetInformationCache->set('current', [ + 'presetName' => $presetName, + 'cloned_at' => time() + ]); + } + + /** + * @param string $stashEntryName + * @param array $stashEntryManifest + * @return void + * @throws \Neos\Cache\Exception + */ + public function setCurrentStashEntry(string $stashEntryName, array $stashEntryManifest): void + { + if (!isset($stashEntryManifest['preset']['name'])) { + return; + } + + if (!isset($stashEntryManifest['cloned_at'])) { + return; + } + + $presetName = $stashEntryManifest['preset']['name']; + $clonedAt = $stashEntryManifest['cloned_at']; + + $this->clonePresetInformationCache->set('current', [ + 'presetName' => $presetName, + 'cloned_at' => $clonedAt + ]); } }