diff --git a/CHANGELOG.md b/CHANGELOG.md index 314529cc..ddc22f92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ dev-master ### Features +- [general] The shell supports being embedded as a dependency - [node:edit] New command `node:edit` enables editing of entire node alpha-4 diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 175947ad..7ff2c64e 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -50,7 +50,7 @@ public function beforeScenario() $session = $this->getSession(null, true); - $this->applicationTester = new ApplicationTester($this->application); + $this->applicationTester = new ApplicationTester(); $this->applicationTester->run(array( '--transport' => 'jackrabbit', '--no-interaction' => true, diff --git a/spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php b/spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php new file mode 100644 index 00000000..0fe61b98 --- /dev/null +++ b/spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php @@ -0,0 +1,20 @@ +beConstructedWith(EmbeddedApplication::MODE_COMMAND); + } + + function it_is_initializable() + { + $this->shouldHaveType('PHPCR\Shell\Console\Application\EmbeddedApplication'); + } +} diff --git a/src/PHPCR/Shell/Console/Application/EmbeddedApplication.php b/src/PHPCR/Shell/Console/Application/EmbeddedApplication.php new file mode 100644 index 00000000..9b20e06a --- /dev/null +++ b/src/PHPCR/Shell/Console/Application/EmbeddedApplication.php @@ -0,0 +1,71 @@ + + */ +class EmbeddedApplication extends ShellApplication +{ + const MODE_SHELL = 'shell'; + const MODE_COMMAND = 'command'; + + protected $mode = self::MODE_SHELL; + + /** + * The $mode can be one of EmbeddedApplication::MODE_SHELL or EmbeddedApplication::MODE_COMMAND. + * + * - Shell mode initializes the whole environement + * - Command mode initailizes only enough to run commands + * + * @param string $mode + */ + public function __construct($mode) + { + parent::__construct(SessionApplication::APP_NAME, SessionApplication::APP_VERSION); + $this->mode = $mode; + $this->setAutoExit(false); + } + + /** + * {@inheritDoc} + */ + public function init() + { + if (true === $this->initialized) { + return; + } + + $this->registerPhpcrCommands(); + + if ($this->mode === self::MODE_SHELL) { + $this->registerShellCommands(); + } + + $this->initialized = true; + } + + /** + * {@inheritDoc} + */ + protected function getDefaultCommand() + { + return 'shell:path:show'; + } + + /** + * {@inheritDoc} + */ + protected function registerEventListeners() + { + $this->dispatcher->addSubscriber(new Subscriber\ProfileFromSessionInputSubscriber()); + $this->dispatcher->addSubscriber(new Subscriber\ExceptionSubscriber()); + $this->dispatcher->addSubscriber(new Subscriber\AliasSubscriber($this->getHelperSet())); + $this->dispatcher->addSubscriber(new Subscriber\AutoSaveSubscriber()); + } +} diff --git a/src/PHPCR/Shell/Console/Application/SessionApplication.php b/src/PHPCR/Shell/Console/Application/SessionApplication.php index 0018736c..d43d6098 100644 --- a/src/PHPCR/Shell/Console/Application/SessionApplication.php +++ b/src/PHPCR/Shell/Console/Application/SessionApplication.php @@ -28,10 +28,7 @@ public function __construct() { parent::__construct(self::APP_NAME, self::APP_VERSION); - $this->shellApplication = new ShellApplication( - self::APP_NAME, - self::APP_VERSION - ); + $this->shellApplication = new ShellApplication(); $command = new ShellCommand($this->shellApplication); $command->setApplication($this); diff --git a/src/PHPCR/Shell/Console/Application/ShellApplication.php b/src/PHPCR/Shell/Console/Application/ShellApplication.php index 835063db..9fe76ec0 100644 --- a/src/PHPCR/Shell/Console/Application/ShellApplication.php +++ b/src/PHPCR/Shell/Console/Application/ShellApplication.php @@ -56,11 +56,11 @@ class ShellApplication extends Application * * {@inheritDoc} */ - public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + public function __construct() { - parent::__construct($name, $version); + parent::__construct(SessionApplication::APP_NAME, SessionApplication::APP_VERSION); $this->profile = new Profile(); - $this->dispatcher = new EventDispatcher(); + $this->setDispatcher($this->dispatcher = new EventDispatcher()); $this->transportRegistry = new TransportRegistry(); $this->registerTransports(); $this->registerHelpers(); @@ -101,6 +101,9 @@ public function setShowUnsupported($boolean) * Note that we do this "lazily" because we instantiate the ShellApplication early, * before the SessionInput has been set. The SessionInput must be set before we * can initialize the application. + * + * @todo: The above scenario is no longer true, we use a Profile. So maybe it can + * be refactored. */ public function init() { @@ -108,7 +111,8 @@ public function init() return; } - $this->registerCommands(); + $this->registerPhpcrCommands(); + $this->registerShellCommands(); $event = new ApplicationInitEvent($this); $this->dispatcher->dispatch(PhpcrShellEvents::APPLICATION_INIT, $event); @@ -119,7 +123,7 @@ public function init() /** * Register the helpers required by the application */ - private function registerHelpers() + protected function registerHelpers() { $phpcrHelper = new PhpcrHelper($this->transportRegistry, $this->profile); @@ -143,7 +147,7 @@ private function registerHelpers() /** * Register the commands used in the shell */ - private function registerCommands() + protected function registerPhpcrCommands() { // phpcr commands $this->add(new CommandPhpcr\AccessControlPrivilegeListCommand()); @@ -217,7 +221,10 @@ private function registerCommands() $this->add(new CommandPhpcr\LockTokenListCommand()); $this->add(new CommandPhpcr\LockTokenRemoveCommand()); $this->add(new CommandPhpcr\LockUnlockCommand()); + } + protected function registerShellCommands() + { // add shell-specific commands $this->add(new CommandShell\AliasListCommand()); $this->add(new CommandShell\ConfigInitCommand()); @@ -227,7 +234,7 @@ private function registerCommands() $this->add(new CommandShell\ExitCommand()); } - private function registerEventListeners() + protected function registerEventListeners() { $this->dispatcher->addSubscriber(new Subscriber\ProfileFromSessionInputSubscriber()); $this->dispatcher->addSubscriber(new Subscriber\ProfileWriterSubscriber( @@ -293,7 +300,7 @@ public function doRun(InputInterface $input, OutputInterface $output) $input = $event->getInput(); if (!$name) { - $input = new ArrayInput(array('command' => 'shell:path:show')); + $input = new ArrayInput(array('command' => $this->getDefaultCommand())); } try { @@ -307,6 +314,14 @@ public function doRun(InputInterface $input, OutputInterface $output) return $exitCode; } + /** + * Return the default command + */ + protected function getDefaultCommand() + { + return 'shell:path:show'; + } + /** * Render an exception to the console * diff --git a/src/PHPCR/Shell/Console/Helper/ConfigHelper.php b/src/PHPCR/Shell/Console/Helper/ConfigHelper.php index 69e271a3..d7435e43 100644 --- a/src/PHPCR/Shell/Console/Helper/ConfigHelper.php +++ b/src/PHPCR/Shell/Console/Helper/ConfigHelper.php @@ -98,6 +98,11 @@ public function getConfigDir() return $home; } + private function getDistConfigDir() + { + return __DIR__ . '/../../Resources/config.dist'; + } + /** * Load the configuration */ @@ -106,13 +111,17 @@ public function loadConfig() $config = array(); $configDir = $this->getConfigDir(); + $distConfigDir = $this->getDistConfigDir(); foreach ($this->configKeys as $configKey) { $fullPath = $configDir . '/' . $configKey . '.yml'; + $fullDistPath = $distConfigDir . '/' . $configKey . '.yml'; $config[$configKey] = array(); if ($this->filesystem->exists($fullPath)) { $config[$configKey] = Yaml::parse($fullPath); + } elseif($this->filesystem->exists($fullDistPath)) { + $config[$configKey] = Yaml::parse($fullDistPath); } } @@ -153,7 +162,7 @@ public function initConfig(OutputInterface $output = null, DialogHelper $dialogH } $configDir = $this->getConfigDir(); - $distDir = __DIR__ . '/../../Resources/config.dist'; + $distDir = $this->getDistConfigDir(); if (!$this->filesystem->exists($configDir)) { $log('[+] Creating directory: ' . $configDir); diff --git a/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php b/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php index 6e6160bb..12a927de 100644 --- a/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php +++ b/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php @@ -8,6 +8,7 @@ use PHPCR\Shell\PhpcrSession; use PHPCR\SimpleCredentials; use PHPCR\Shell\Transport\TransportRegistryInterface; +use PHPCR\SessionInterface; /** * Helper for managing PHPCR sessions @@ -30,13 +31,6 @@ class PhpcrHelper extends Helper */ protected $transportRegistry; - /** - * Lazy initialize PHPCR session - * - * @var boolean - */ - protected $initialized = false; - /** * @param TransportRegistryInterface $transportRegistry * @param Profile $profile @@ -57,12 +51,16 @@ public function getName() private function init() { - if (false === $this->initialized) { + if (null === $this->session) { $this->initSession(); - $this->initialized = true; } } + public function setSession(SessionInterface $session) + { + $this->session = $session; + } + /** * Initialize the PHPCR session * diff --git a/src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php b/src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php new file mode 100644 index 00000000..6d397d4b --- /dev/null +++ b/src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php @@ -0,0 +1,34 @@ + + */ +class AutoSaveSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + ConsoleEvents::TERMINATE => 'handleTerminate', + ); + } + + public function handleTerminate(ConsoleTerminateEvent $event) + { + $command = $event->getCommand(); + $output = $event->getOutput(); + $session = $command->getHelper('phpcr')->getSession(); + + if ($session->hasPendingChanges()) { + $output->writeln('Auto-saving session'); + } + $session->save(); + } +}