diff --git a/.travis.yml b/.travis.yml
index fff2af97..d7ffd9bd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,5 +10,5 @@ before_script:
script:
- phpunit --coverage-text
- - php vendor/behat/behat/bin/behat --format=failed
+ - php vendor/behat/behat/bin/behat
- php vendor/bin/phpspec run
diff --git a/features/fixtures/cms.xml b/features/fixtures/cms.xml
index 37f4bcd2..09f92f8a 100644
--- a/features/fixtures/cms.xml
+++ b/features/fixtures/cms.xml
@@ -19,10 +19,19 @@
nt:unstructured
+
+
+ nt:unstructured
+
+
+
nt:unstructured
+
+ mix:shareable
+
nt:unstructured
diff --git a/features/access_control_privilege_list.feature b/features/phpcr_access_control_privilege_list.feature
similarity index 100%
rename from features/access_control_privilege_list.feature
rename to features/phpcr_access_control_privilege_list.feature
diff --git a/features/lock_info.feature b/features/phpcr_lock_info.feature
similarity index 100%
rename from features/lock_info.feature
rename to features/phpcr_lock_info.feature
diff --git a/features/lock_lock.feature b/features/phpcr_lock_lock.feature
similarity index 100%
rename from features/lock_lock.feature
rename to features/phpcr_lock_lock.feature
diff --git a/features/lock_refresh.feature b/features/phpcr_lock_refresh.feature
similarity index 100%
rename from features/lock_refresh.feature
rename to features/phpcr_lock_refresh.feature
diff --git a/features/lock_token_add.feature b/features/phpcr_lock_token_add.feature
similarity index 100%
rename from features/lock_token_add.feature
rename to features/phpcr_lock_token_add.feature
diff --git a/features/lock_token_list.feature b/features/phpcr_lock_token_list.feature
similarity index 100%
rename from features/lock_token_list.feature
rename to features/phpcr_lock_token_list.feature
diff --git a/features/lock_token_remove.feature b/features/phpcr_lock_token_remove.feature
similarity index 100%
rename from features/lock_token_remove.feature
rename to features/phpcr_lock_token_remove.feature
diff --git a/features/lock_unlock.feature b/features/phpcr_lock_unlock.feature
similarity index 100%
rename from features/lock_unlock.feature
rename to features/phpcr_lock_unlock.feature
diff --git a/features/namespace_unregister.feature b/features/phpcr_namespace_unregister.feature
similarity index 100%
rename from features/namespace_unregister.feature
rename to features/phpcr_namespace_unregister.feature
diff --git a/features/node_clone.feature b/features/phpcr_node_clone.feature
similarity index 100%
rename from features/node_clone.feature
rename to features/phpcr_node_clone.feature
diff --git a/features/node_copy.feature b/features/phpcr_node_copy.feature
similarity index 70%
rename from features/node_copy.feature
rename to features/phpcr_node_copy.feature
index 1a2ad311..d503c824 100644
--- a/features/node_copy.feature
+++ b/features/phpcr_node_copy.feature
@@ -16,7 +16,8 @@ Feature: Copy a node from a given workspace to the current workspace
And I save the session
And there should exist a node at "/foo"
- Scenario: Copy node from a different workspace
- Given I execute the "node:copy /tests_general_base/index.txt /index.txt default_1" command
- Then the command should not fail
- And there should exist a node at "/index.txt"
+ # Does not currently work with jackrabbit..
+ #Scenario: Copy node from a different workspace
+ # Given I execute the "node:copy /tests_general_base/index.txt /index.txt default_1" command
+ # Then the command should not fail
+ # And there should exist a node at "/index.txt"
diff --git a/features/node_corresponding.feature b/features/phpcr_node_corresponding.feature
similarity index 100%
rename from features/node_corresponding.feature
rename to features/phpcr_node_corresponding.feature
diff --git a/features/node_create.feature b/features/phpcr_node_create.feature
similarity index 100%
rename from features/node_create.feature
rename to features/phpcr_node_create.feature
diff --git a/features/node_definition.feature b/features/phpcr_node_definition.feature
similarity index 100%
rename from features/node_definition.feature
rename to features/phpcr_node_definition.feature
diff --git a/features/node_info.feature b/features/phpcr_node_info.feature
similarity index 100%
rename from features/node_info.feature
rename to features/phpcr_node_info.feature
diff --git a/features/node_lifecycle_follow_transition.feature b/features/phpcr_node_lifecycle_follow_transition.feature
similarity index 100%
rename from features/node_lifecycle_follow_transition.feature
rename to features/phpcr_node_lifecycle_follow_transition.feature
diff --git a/features/node_lifecycle_list.feature b/features/phpcr_node_lifecycle_list.feature
similarity index 100%
rename from features/node_lifecycle_list.feature
rename to features/phpcr_node_lifecycle_list.feature
diff --git a/features/node_list.feature b/features/phpcr_node_list.feature
similarity index 100%
rename from features/node_list.feature
rename to features/phpcr_node_list.feature
diff --git a/features/node_mixin_add.feature b/features/phpcr_node_mixin_add.feature
similarity index 100%
rename from features/node_mixin_add.feature
rename to features/phpcr_node_mixin_add.feature
diff --git a/features/node_mixin_remove.feature b/features/phpcr_node_mixin_remove.feature
similarity index 100%
rename from features/node_mixin_remove.feature
rename to features/phpcr_node_mixin_remove.feature
diff --git a/features/node_move.feature b/features/phpcr_node_move.feature
similarity index 100%
rename from features/node_move.feature
rename to features/phpcr_node_move.feature
diff --git a/features/node_property_edit.feature b/features/phpcr_node_property_edit.feature
similarity index 100%
rename from features/node_property_edit.feature
rename to features/phpcr_node_property_edit.feature
diff --git a/features/node_property_remove.feature b/features/phpcr_node_property_remove.feature
similarity index 100%
rename from features/node_property_remove.feature
rename to features/phpcr_node_property_remove.feature
diff --git a/features/node_property_set.feature b/features/phpcr_node_property_set.feature
similarity index 74%
rename from features/node_property_set.feature
rename to features/phpcr_node_property_set.feature
index e70dc788..58b84460 100644
--- a/features/node_property_set.feature
+++ b/features/phpcr_node_property_set.feature
@@ -22,9 +22,18 @@ Feature: Set a node property
| node:property:set thisisnew foobar --type=string | /properties/thisisnew | foobar |
Scenario: Update a property but do not specify the type
- Given I execute the "node:set /properties/decimal 1234" command
+ Given I execute the "node:property:set /properties/decimal 1234" command
And I execute the "node:list /properties" command
Then I should see the following:
"""
decimal | DECIMAL
"""
+
+ Scenario: Create a new property
+ Given I execute the "node:property:set /properties/new 1234" command
+ Then the command should not fail
+ And I execute the "node:list /properties" command
+ Then I should see the following:
+ """
+ new | STRING
+ """
diff --git a/features/node_property_show.feature b/features/phpcr_node_property_show.feature
similarity index 82%
rename from features/node_property_show.feature
rename to features/phpcr_node_property_show.feature
index 7a8f0d0e..ec5da370 100644
--- a/features/node_property_show.feature
+++ b/features/phpcr_node_property_show.feature
@@ -36,6 +36,14 @@ hello world
2011-04-21T14:34:20+01:00
"""
+ Scenario: Attempt to show a node
+ Given I execute the "node:property:show /tests_general_base" command
+ Then the command should fail
+ And I should see the following:
+ """
+ Item at "/tests_general_base" is not a property
+ """
+
Scenario: Try to show non-existing property
Given I execute the "node:property:show /this/path/does/not/exist" command
Then the command should fail
diff --git a/features/node_references.feature b/features/phpcr_node_references.feature
similarity index 100%
rename from features/node_references.feature
rename to features/phpcr_node_references.feature
diff --git a/features/node_remove.feature b/features/phpcr_node_remove.feature
similarity index 100%
rename from features/node_remove.feature
rename to features/phpcr_node_remove.feature
diff --git a/features/node_rename.feature b/features/phpcr_node_rename.feature
similarity index 100%
rename from features/node_rename.feature
rename to features/phpcr_node_rename.feature
diff --git a/features/node_reorder_before.feature b/features/phpcr_node_reorder_before.feature
similarity index 100%
rename from features/node_reorder_before.feature
rename to features/phpcr_node_reorder_before.feature
diff --git a/features/node_set_primary_type.feature b/features/phpcr_node_set_primary_type.feature
similarity index 100%
rename from features/node_set_primary_type.feature
rename to features/phpcr_node_set_primary_type.feature
diff --git a/features/node_shared_remove.feature b/features/phpcr_node_shared_remove.feature
similarity index 100%
rename from features/node_shared_remove.feature
rename to features/phpcr_node_shared_remove.feature
diff --git a/features/node_shared_show.feature b/features/phpcr_node_shared_show.feature
similarity index 100%
rename from features/node_shared_show.feature
rename to features/phpcr_node_shared_show.feature
diff --git a/features/node_type_edit.feature b/features/phpcr_node_type_edit.feature
similarity index 100%
rename from features/node_type_edit.feature
rename to features/phpcr_node_type_edit.feature
diff --git a/features/node_type_list.feature b/features/phpcr_node_type_list.feature
similarity index 100%
rename from features/node_type_list.feature
rename to features/phpcr_node_type_list.feature
diff --git a/features/node_type_load.feature b/features/phpcr_node_type_load.feature
similarity index 100%
rename from features/node_type_load.feature
rename to features/phpcr_node_type_load.feature
diff --git a/features/node_type_show.feature b/features/phpcr_node_type_show.feature
similarity index 100%
rename from features/node_type_show.feature
rename to features/phpcr_node_type_show.feature
diff --git a/features/node_type_unregister.feature b/features/phpcr_node_type_unregister.feature
similarity index 100%
rename from features/node_type_unregister.feature
rename to features/phpcr_node_type_unregister.feature
diff --git a/features/node_update.feature b/features/phpcr_node_update.feature
similarity index 100%
rename from features/node_update.feature
rename to features/phpcr_node_update.feature
diff --git a/features/query.feature b/features/phpcr_query.feature
similarity index 100%
rename from features/query.feature
rename to features/phpcr_query.feature
diff --git a/features/query_select.feature b/features/phpcr_query_select.feature
similarity index 100%
rename from features/query_select.feature
rename to features/phpcr_query_select.feature
diff --git a/features/repository_descriptor_list.feature b/features/phpcr_repository_descriptor_list.feature
similarity index 100%
rename from features/repository_descriptor_list.feature
rename to features/phpcr_repository_descriptor_list.feature
diff --git a/features/retention_hold_add.feature b/features/phpcr_retention_hold_add.feature
similarity index 100%
rename from features/retention_hold_add.feature
rename to features/phpcr_retention_hold_add.feature
diff --git a/features/retention_hold_list.feature b/features/phpcr_retention_hold_list.feature
similarity index 100%
rename from features/retention_hold_list.feature
rename to features/phpcr_retention_hold_list.feature
diff --git a/features/retention_hold_remove.feature b/features/phpcr_retention_hold_remove.feature
similarity index 100%
rename from features/retention_hold_remove.feature
rename to features/phpcr_retention_hold_remove.feature
diff --git a/features/retention_policy_get.feature b/features/phpcr_retention_policy_get.feature
similarity index 100%
rename from features/retention_policy_get.feature
rename to features/phpcr_retention_policy_get.feature
diff --git a/features/retention_policy_remove.feature b/features/phpcr_retention_policy_remove.feature
similarity index 100%
rename from features/retention_policy_remove.feature
rename to features/phpcr_retention_policy_remove.feature
diff --git a/features/session_export_view.feature b/features/phpcr_session_export_view.feature
similarity index 100%
rename from features/session_export_view.feature
rename to features/phpcr_session_export_view.feature
diff --git a/features/session_impersonate.feature b/features/phpcr_session_impersonate.feature
similarity index 100%
rename from features/session_impersonate.feature
rename to features/phpcr_session_impersonate.feature
diff --git a/features/session_import.feature b/features/phpcr_session_import.feature
similarity index 100%
rename from features/session_import.feature
rename to features/phpcr_session_import.feature
diff --git a/features/session_info.feature b/features/phpcr_session_info.feature
similarity index 100%
rename from features/session_info.feature
rename to features/phpcr_session_info.feature
diff --git a/features/session_login.feature b/features/phpcr_session_login.feature
similarity index 100%
rename from features/session_login.feature
rename to features/phpcr_session_login.feature
diff --git a/features/session_logout.feature b/features/phpcr_session_logout.feature
similarity index 100%
rename from features/session_logout.feature
rename to features/phpcr_session_logout.feature
diff --git a/features/session_namespace_list.feature b/features/phpcr_session_namespace_list.feature
similarity index 100%
rename from features/session_namespace_list.feature
rename to features/phpcr_session_namespace_list.feature
diff --git a/features/session_namespace_set.feature b/features/phpcr_session_namespace_set.feature
similarity index 100%
rename from features/session_namespace_set.feature
rename to features/phpcr_session_namespace_set.feature
diff --git a/features/session_refresh.feature b/features/phpcr_session_refresh.feature
similarity index 100%
rename from features/session_refresh.feature
rename to features/phpcr_session_refresh.feature
diff --git a/features/session_save.feature b/features/phpcr_session_save.feature
similarity index 100%
rename from features/session_save.feature
rename to features/phpcr_session_save.feature
diff --git a/features/version_checkin.feature b/features/phpcr_version_checkin.feature
similarity index 100%
rename from features/version_checkin.feature
rename to features/phpcr_version_checkin.feature
diff --git a/features/version_checkout.feature b/features/phpcr_version_checkout.feature
similarity index 100%
rename from features/version_checkout.feature
rename to features/phpcr_version_checkout.feature
diff --git a/features/version_checkpoint.feature b/features/phpcr_version_checkpoint.feature
similarity index 100%
rename from features/version_checkpoint.feature
rename to features/phpcr_version_checkpoint.feature
diff --git a/features/version_history.feature b/features/phpcr_version_history.feature
similarity index 100%
rename from features/version_history.feature
rename to features/phpcr_version_history.feature
diff --git a/features/version_remove.feature b/features/phpcr_version_remove.feature
similarity index 100%
rename from features/version_remove.feature
rename to features/phpcr_version_remove.feature
diff --git a/features/version_restore.feature b/features/phpcr_version_restore.feature
similarity index 100%
rename from features/version_restore.feature
rename to features/phpcr_version_restore.feature
diff --git a/features/workspace_create.feature b/features/phpcr_workspace_create.feature
similarity index 100%
rename from features/workspace_create.feature
rename to features/phpcr_workspace_create.feature
diff --git a/features/workspace_delete.feature b/features/phpcr_workspace_delete.feature
similarity index 100%
rename from features/workspace_delete.feature
rename to features/phpcr_workspace_delete.feature
diff --git a/features/workspace_list.feature b/features/phpcr_workspace_list.feature
similarity index 100%
rename from features/workspace_list.feature
rename to features/phpcr_workspace_list.feature
diff --git a/features/workspace_namespace_list.feature b/features/phpcr_workspace_namespace_list.feature
similarity index 100%
rename from features/workspace_namespace_list.feature
rename to features/phpcr_workspace_namespace_list.feature
diff --git a/features/workspace_namespace_register.feature b/features/phpcr_workspace_namespace_register.feature
similarity index 100%
rename from features/workspace_namespace_register.feature
rename to features/phpcr_workspace_namespace_register.feature
diff --git a/features/workspace_namespace_unregister.feature b/features/phpcr_workspace_namespace_unregister.feature
similarity index 100%
rename from features/workspace_namespace_unregister.feature
rename to features/phpcr_workspace_namespace_unregister.feature
diff --git a/features/workspace_use.feature b/features/phpcr_workspace_use.feature
similarity index 100%
rename from features/workspace_use.feature
rename to features/phpcr_workspace_use.feature
diff --git a/features/shell_alias.feature b/features/shell_alias.feature
new file mode 100644
index 00000000..fc63c54f
--- /dev/null
+++ b/features/shell_alias.feature
@@ -0,0 +1,35 @@
+Feature: Command aliases
+ In order to be more effective when using the shell
+ As a user
+ I want to be able to use the default command aliases
+
+ Background:
+ Given that I am logged in as "testuser"
+ And the "cms.xml" fixtures are loaded
+
+ Scenario Outline: Execute an alias
+ Given I execute the "" command
+ Then the command should not fail
+
+ Examples:
+ | command |
+ | use default |
+ | select * from [nt:unstructured] |
+ | cd cms |
+ | rm cms |
+ | mv cms smc |
+ | ls |
+ | ls cms |
+ | sl cms/articles cms/test/foobar |
+ | cat cms/articles/article1/title |
+
+ Scenario: List aliases
+ Given I execute the "shell:alias:list" command
+ Then the command should not fail
+ And I should see a table containing the following rows:
+ | Alias | Command |
+ | cd | shell:path:change {arg1} |
+ | ls | node:list {arg1} |
+
+
+
diff --git a/features/shell_config_init.feature b/features/shell_config_init.feature
new file mode 100644
index 00000000..880619c7
--- /dev/null
+++ b/features/shell_config_init.feature
@@ -0,0 +1,12 @@
+Feature: Initialize a new local configuration
+ In order to create a default configuration
+ As a user
+ I want to be able to execute a command which does that
+
+ Scenario: Initialize configuration
+ Given I execute the "shell:config:init --no-ansi --no-interaction" command
+ Then the command should not fail
+ And I should see the following:
+ """
+ alias.yml
+ """
diff --git a/features/shell_config_reload.feature b/features/shell_config_reload.feature
new file mode 100644
index 00000000..7e7ecd55
--- /dev/null
+++ b/features/shell_config_reload.feature
@@ -0,0 +1,8 @@
+Feature: Reload the configuration
+ In order to reload the configuration
+ As a user
+ I want to be able to execute a command which does that
+
+ Scenario: Reload configuration
+ Given I execute the "shell:config:reload" command
+ Then the command should not fail
diff --git a/spec/PHPCR/Shell/Console/Application/ShellApplicationSpec.php b/spec/PHPCR/Shell/Console/Application/ShellApplicationSpec.php
new file mode 100644
index 00000000..c2f1bf2c
--- /dev/null
+++ b/spec/PHPCR/Shell/Console/Application/ShellApplicationSpec.php
@@ -0,0 +1,14 @@
+shouldHaveType('PHPCR\Shell\Console\Application\ShellApplication');
+ }
+}
diff --git a/spec/PHPCR/Shell/Console/Helper/ConfigHelperSpec.php b/spec/PHPCR/Shell/Console/Helper/ConfigHelperSpec.php
new file mode 100644
index 00000000..c5b33d27
--- /dev/null
+++ b/spec/PHPCR/Shell/Console/Helper/ConfigHelperSpec.php
@@ -0,0 +1,43 @@
+beConstructedWith($filesystem);
+ }
+
+ function it_is_initializable()
+ {
+ $this->shouldHaveType('PHPCR\Shell\Console\Helper\ConfigHelper');
+ }
+
+ function it_should_have_a_method_to_get_the_users_config_directory()
+ {
+ putenv('PHPCRSH_HOME=/home/foobar');
+ $this->getConfigDir()->shouldReturn('/home/foobar');
+ }
+
+ function it_should_be_able_to_parse_a_config_file_and_return_the_config_as_an_array(
+ Filesystem $filesystem
+ )
+ {
+ $dir = __DIR__ . '/fixtures/config';
+ putenv('PHPCRSH_HOME=' . $dir);
+ $filesystem->exists(Argument::any())->willReturn(true);
+
+ $config = $this->getConfig('alias')->shouldReturn(array(
+ 'foobar' => 'barfoo',
+ 'barfoo' => 'foobar',
+ ));
+
+ }
+}
diff --git a/spec/PHPCR/Shell/Console/Helper/fixtures/config/alias.yml b/spec/PHPCR/Shell/Console/Helper/fixtures/config/alias.yml
new file mode 100644
index 00000000..c7130a52
--- /dev/null
+++ b/spec/PHPCR/Shell/Console/Helper/fixtures/config/alias.yml
@@ -0,0 +1,2 @@
+foobar: barfoo
+barfoo: foobar
diff --git a/spec/PHPCR/Shell/Event/ApplicationInitEventSpec.php b/spec/PHPCR/Shell/Event/ApplicationInitEventSpec.php
new file mode 100644
index 00000000..f91a457e
--- /dev/null
+++ b/spec/PHPCR/Shell/Event/ApplicationInitEventSpec.php
@@ -0,0 +1,29 @@
+shouldHaveType('PHPCR\Shell\Event\ApplicationInitEvent');
+ }
+
+ function let(
+ Application $application
+ )
+ {
+ $this->beConstructedWith($application);
+ }
+
+ function it_will_return_the_application(
+ Application $application
+ )
+ {
+ $this->getApplication()->shouldReturn($application);
+ }
+}
diff --git a/spec/PHPCR/Shell/Event/CommandExceptionEventSpec.php b/spec/PHPCR/Shell/Event/CommandExceptionEventSpec.php
new file mode 100644
index 00000000..3cba40e1
--- /dev/null
+++ b/spec/PHPCR/Shell/Event/CommandExceptionEventSpec.php
@@ -0,0 +1,30 @@
+shouldHaveType('PHPCR\Shell\Event\CommandExceptionEvent');
+ }
+
+ function let(
+ \Exception $exception,
+ OutputInterface $output
+ ) {
+ $this->beConstructedWith($exception, $output);
+ }
+
+ function it_should_provide_access_to_event_parameters(
+ \Exception $exception,
+ OutputInterface $output
+ ) {
+ $this->getException()->shouldReturn($exception);
+ $this->getOutput()->shouldReturn($output);
+ }
+}
diff --git a/spec/PHPCR/Shell/Subscriber/AliasSubscriberSpec.php b/spec/PHPCR/Shell/Subscriber/AliasSubscriberSpec.php
new file mode 100644
index 00000000..1525a007
--- /dev/null
+++ b/spec/PHPCR/Shell/Subscriber/AliasSubscriberSpec.php
@@ -0,0 +1,60 @@
+shouldHaveType('PHPCR\Shell\Subscriber\AliasSubscriber');
+ }
+
+ function let(
+ ConfigHelper $config
+ ) {
+ $this->beConstructedWith(
+ $config
+ );
+
+ $config->getConfig('alias')->willReturn(array(
+ 'ls' => 'list:command {arg1}',
+ 'mv' => 'move {arg1} {arg2}',
+ ));
+ }
+
+ function it_should_convert_an_aliased_input_into_a_real_command_input(
+ CommandPreRunEvent $event,
+ ConfigHelper $config,
+ StringInput $input
+ ) {
+ $event->getInput()->willReturn($input);
+ $input->getFirstArgument()->willReturn('ls');
+ $input->getTokens()->willReturn(array(
+ 'ls', 'me'
+ ));
+ $event->setInput(Argument::type('PHPCR\Shell\Console\Input\StringInput'))->shouldBeCalled();
+
+ $this->handleAlias($event)->shouldReturn('list:command me');
+ }
+
+ function it_should_ommit_missing_arguments(
+ CommandPreRunEvent $event,
+ ConfigHelper $config,
+ StringInput $input
+ ) {
+ $event->getInput()->willReturn($input);
+ $input->getFirstArgument()->willReturn('ls');
+ $input->getTokens()->willReturn(array(
+ 'ls'
+ ));
+ $event->setInput(Argument::type('PHPCR\Shell\Console\Input\StringInput'))->shouldBeCalled();
+
+ $this->handleAlias($event)->shouldReturn('list:command');
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Application/ShellApplication.php b/src/PHPCR/Shell/Console/Application/ShellApplication.php
index db310caf..1bab6dc8 100644
--- a/src/PHPCR/Shell/Console/Application/ShellApplication.php
+++ b/src/PHPCR/Shell/Console/Application/ShellApplication.php
@@ -3,110 +3,56 @@
namespace PHPCR\Shell\Console\Application;
use Symfony\Component\Console\Application;
-
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Formatter\OutputFormatter;
+use Symfony\Component\Console\Formatter\OutputFormatterStyle;
+use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\OutputInterface;
+use PHPCR\SimpleCredentials;
-use Jackalope\NotImplementedException;
-use PHPCR\Shell\Console\Command\Phpcr\AccessControlPrivilegeListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockInfoCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockLockCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockRefreshCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockTokenAddCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockTokenListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockTokenRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\LockUnlockCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeCorrespondingCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeCreateCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeDefinitionCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeInfoCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeLifecycleFollowCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeLifecycleListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeMixinAddCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeMixinRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeOrderBeforeCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeReferencesCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeRenameCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodePropertySetCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeSetPrimaryTypeCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeSharedRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeSharedShowCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeTypeEditCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeTypeListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeTypeLoadCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeTypeShowCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeTypeUnregisterCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeUpdateCommand;
-use PHPCR\Shell\Console\Command\Phpcr\PhpcrShellCommand;
-use PHPCR\Shell\Console\Command\Phpcr\QueryCommand;
-use PHPCR\Shell\Console\Command\Phpcr\QuerySelectCommand;
-use PHPCR\Shell\Console\Command\Phpcr\RepositoryDescriptorListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\RetentionHoldAddCommand;
-use PHPCR\Shell\Console\Command\Phpcr\RetentionHoldListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\RetentionHoldRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\RetentionPolicyGetCommand;
-use PHPCR\Shell\Console\Command\Phpcr\RetentionPolicyRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionExportViewCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionImpersonateCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionImportXMLCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionInfoCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionLoginCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionLogoutCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionNamespaceListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionNamespaceSetCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeMoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionNodeShowCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodePropertyEditCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodePropertyRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodePropertyShowCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionRefreshCommand;
-use PHPCR\Shell\Console\Command\Phpcr\SessionSaveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\VersionCheckinCommand;
-use PHPCR\Shell\Console\Command\Phpcr\VersionCheckoutCommand;
-use PHPCR\Shell\Console\Command\Phpcr\VersionCheckpointCommand;
-use PHPCR\Shell\Console\Command\Phpcr\VersionHistoryCommand;
-use PHPCR\Shell\Console\Command\Phpcr\VersionRemoveCommand;
-use PHPCR\Shell\Console\Command\Phpcr\VersionRestoreCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceCreateCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceDeleteCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceNamespaceListCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceNamespaceRegisterCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceNamespaceUnregisterCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeCloneCommand;
-use PHPCR\Shell\Console\Command\Phpcr\NodeCopyCommand;
-use PHPCR\Shell\Console\Command\Phpcr\WorkspaceUseCommand;
-use PHPCR\Shell\Console\Command\Shell\ChangePathCommand;
-use PHPCR\Shell\Console\Command\Shell\ExitCommand;
-use PHPCR\Shell\Console\Command\Shell\ListTreeCommand;
-use PHPCR\Shell\Console\Command\Shell\PwdCommand;
+use PHPCR\Util\Console\Helper\PhpcrConsoleDumperHelper;
+use PHPCR\Util\Console\Helper\PhpcrHelper;
+
+use PHPCR\Shell\Console\Command\Phpcr as CommandPhpcr;
+use PHPCR\Shell\Console\Command\Shell as CommandShell;
+use PHPCR\Shell\Console\Helper\ConfigHelper;
use PHPCR\Shell\Console\Helper\EditorHelper;
use PHPCR\Shell\Console\Helper\NodeHelper;
use PHPCR\Shell\Console\Helper\PathHelper;
use PHPCR\Shell\Console\Helper\RepositoryHelper;
use PHPCR\Shell\Console\Helper\ResultFormatterHelper;
use PHPCR\Shell\Console\Helper\TextHelper;
-use PHPCR\Shell\PhpcrSession;
-use PHPCR\SimpleCredentials;
-use PHPCR\Util\Console\Command\NodeDumpCommand;
-use PHPCR\Util\Console\Command\NodeTouchCommand;
-use PHPCR\Util\Console\Command\NodeTypeRegisterCommand;
-use PHPCR\Util\Console\Command\NodesUpdateCommand;
-use PHPCR\Util\Console\Command\WorkspacePurgeCommand;
-use PHPCR\Util\Console\Helper\PhpcrConsoleDumperHelper;
-use PHPCR\Util\Console\Helper\PhpcrHelper;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Formatter\OutputFormatter;
-use Symfony\Component\Console\Formatter\OutputFormatterStyle;
-use Symfony\Component\Console\Input\ArrayInput;
+use PHPCR\Shell\Subscriber;
+use PHPCR\Shell\Event;
+use PHPCR\Shell\PhpcrSession;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use PHPCR\Shell\Event\PhpcrShellEvents;
+use PHPCR\Shell\Event\ApplicationInitEvent;
+
+/**
+ * Main application for PHPCRSH
+ *
+ * @author Daniel Leech
+ */
class ShellApplication extends Application
{
+ /**
+ * @var \PHPCR\TransportInterface[]
+ */
protected $transports;
+
+ /**
+ * @var boolean
+ */
protected $initialized;
+
+ /**
+ * @var \Symfony\Component\Console\Input\InputInterface
+ */
protected $sessionInput;
/**
@@ -114,15 +60,28 @@ class ShellApplication extends Application
*/
private $session;
+ public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
+ {
+ parent::__construct($name, $version);
+
+ $this->dispatcher = new EventDispatcher();
+ }
+
+
/**
- * Input from the shell command, containing the connection
- * parameters etc.
+ * The SessionInput is the input used to intialize the shell.
+ * It contains the connection parameters.
+ *
+ * @param \Symfony\Component\Console\Input\InputInterface $input
*/
public function setSessionInput(InputInterface $input)
{
$this->sessionInput = $input;
}
+ /**
+ * Initialize the application
+ */
public function init()
{
if (true === $this->initialized) {
@@ -135,135 +94,153 @@ public function init()
);
}
- // initialize transports
- foreach (array(
+
+ $this->initializeTransports();
+ $this->initSession();
+ $this->registerHelpers();
+ $this->registerCommands();
+ $this->registerEventListeners();
+
+ $event = new ApplicationInitEvent($this);
+ $this->dispatcher->dispatch(PhpcrShellEvents::APPLICATION_INIT, $event);
+
+ $this->initialized = true;
+ }
+
+ /**
+ * Initialize the supported transports.
+ */
+ private function initializeTransports()
+ {
+ $transports = array(
new \PHPCR\Shell\Transport\DoctrineDbal($this->sessionInput),
new \PHPCR\Shell\Transport\Jackrabbit($this->sessionInput),
- ) as $transport) {
+ );
+
+ foreach ($transports as $transport) {
$this->transports[$transport->getName()] = $transport;;
}
+ }
- $session = $this->initSession();
-
- $this->getHelperSet()->set(new EditorHelper($this->session));
- $this->getHelperSet()->set(new PhpcrConsoleDumperHelper());
- $this->getHelperSet()->set(new PhpcrHelper($this->session));
- $this->getHelperSet()->set(new ResultFormatterHelper());
- $this->getHelperSet()->set(new TextHelper());
- $this->getHelperSet()->set(new NodeHelper($this->session));
- $this->getHelperSet()->set(new PathHelper($this->session));
- $this->getHelperSet()->set(new RepositoryHelper($this->session->getRepository()));
-
- // add new commands
- $this->add(new AccessControlPrivilegeListCommand());
- $this->add(new RepositoryDescriptorListCommand());
- $this->add(new SessionExportViewCommand());
- $this->add(new SessionImpersonateCommand());
- $this->add(new SessionImportXMLCommand());
- $this->add(new SessionInfoCommand());
- $this->add(new SessionLoginCommand());
- $this->add(new SessionLogoutCommand());
- $this->add(new SessionNamespaceListCommand());
- $this->add(new SessionNamespaceSetCommand());
- $this->add(new NodePropertyEditCommand());
- $this->add(new NodePropertyRemoveCommand());
- $this->add(new NodePropertyShowCommand());
- $this->add(new SessionRefreshCommand());
- $this->add(new SessionSaveCommand());
- $this->add(new QuerySelectCommand());
- $this->add(new QueryCommand());
- $this->add(new RetentionHoldAddCommand());
- $this->add(new RetentionHoldListCommand());
- $this->add(new RetentionHoldRemoveCommand());
- $this->add(new RetentionPolicyGetCommand());
- $this->add(new RetentionPolicyRemoveCommand());
- $this->add(new WorkspaceCreateCommand());
- $this->add(new WorkspaceDeleteCommand());
- $this->add(new WorkspaceListCommand());
- $this->add(new NodeCloneCommand());
- $this->add(new NodeCopyCommand());
- $this->add(new WorkspaceNamespaceListCommand());
- $this->add(new WorkspaceNamespaceRegisterCommand());
- $this->add(new WorkspaceNamespaceUnregisterCommand());
- $this->add(new WorkspaceUseCommand());
- $this->add(new NodeTypeShowCommand());
- $this->add(new NodeTypeEditCommand());
- $this->add(new NodeTypeUnregisterCommand());
- $this->add(new NodeTypeListCommand());
- $this->add(new NodeTypeLoadCommand());
- $this->add(new VersionCheckoutCommand());
- $this->add(new VersionHistoryCommand());
- $this->add(new VersionRestoreCommand());
- $this->add(new VersionRemoveCommand());
- $this->add(new VersionCheckpointCommand());
- $this->add(new VersionCheckinCommand());
- $this->add(new NodeCreateCommand());
- $this->add(new NodeCorrespondingCommand());
- $this->add(new NodeDefinitionCommand());
- $this->add(new NodePropertySetCommand());
- $this->add(new NodeSetPrimaryTypeCommand());
- $this->add(new NodeRenameCommand());
- $this->add(new NodeMoveCommand());
- $this->add(new NodeMixinAddCommand());
- $this->add(new NodeMixinRemoveCommand());
- $this->add(new NodeOrderBeforeCommand());
- $this->add(new NodeInfoCommand());
- $this->add(new NodeLifecycleFollowCommand());
- $this->add(new NodeLifecycleListCommand());
- $this->add(new NodeListCommand());
- $this->add(new NodeUpdateCommand());
- $this->add(new NodeReferencesCommand());
- $this->add(new NodeSharedShowCommand());
- $this->add(new NodeSharedRemoveCommand());
- $this->add(new NodeRemoveCommand());
- $this->add(new LockLockCommand());
- $this->add(new LockInfoCommand());
- $this->add(new LockRefreshCommand());
- $this->add(new LockTokenAddCommand());
- $this->add(new LockTokenListCommand());
- $this->add(new LockTokenRemoveCommand());
- $this->add(new LockUnlockCommand());
-
- // add shell-specific commands
- $this->add(new ChangePathCommand());
- $this->add(new PwdCommand());
- $this->add(new ExitCommand());
-
- // wrap phpcr-util commands
- $this->add($this->wrap(new NodeDumpCommand())
- ->setName('dump')
- ->setDescription('Alias for dump')
+ /**
+ * Register the helpers required by the application
+ */
+ private function registerHelpers()
+ {
+ $helpers = array(
+ new ConfigHelper(),
+ new EditorHelper($this->session),
+ new NodeHelper($this->session),
+ new PathHelper($this->session),
+ new PhpcrConsoleDumperHelper(),
+ new PhpcrHelper($this->session),
+ new RepositoryHelper($this->session->getRepository()),
+ new ResultFormatterHelper(),
+ new TextHelper(),
);
- $ls = $this->get('dump');
- $ls->getDefinition()->getArgument('identifier')->setDefault(null);
- $this->add(new ListTreeCommand());
+ foreach ($helpers as $helper) {
+ $this->getHelperSet()->set($helper);
+ }
+ }
- $this->add($this->wrap(new NodeListCommand())
- ->setName('ls')
- );
- $this->add($this->wrap(new NodeRemoveCommand())
- ->setName('rm')
- );
- $this->add($this->wrap(new NodesUpdateCommand())
- ->setName('update')
- );
- $this->add($this->wrap(new NodeTouchCommand())
- ->setName('touch')
- );
- $this->add($this->wrap(new NodeTypeRegisterCommand())
- ->setName('nt-register')
- );
- $this->add($this->wrap(new WorkspacePurgeCommand())
- ->setName('workspace-purge')
- );
+ /**
+ * Register the commands used in the shell
+ */
+ private function registerCommands()
+ {
+ // phpcr commands
+ $this->add(new CommandPhpcr\AccessControlPrivilegeListCommand());
+ $this->add(new CommandPhpcr\RepositoryDescriptorListCommand());
+ $this->add(new CommandPhpcr\SessionExportViewCommand());
+ $this->add(new CommandPhpcr\SessionImpersonateCommand());
+ $this->add(new CommandPhpcr\SessionImportXMLCommand());
+ $this->add(new CommandPhpcr\SessionInfoCommand());
+ $this->add(new CommandPhpcr\SessionLoginCommand());
+ $this->add(new CommandPhpcr\SessionLogoutCommand());
+ $this->add(new CommandPhpcr\SessionNamespaceListCommand());
+ $this->add(new CommandPhpcr\SessionNamespaceSetCommand());
+ $this->add(new CommandPhpcr\NodePropertyEditCommand());
+ $this->add(new CommandPhpcr\NodePropertyRemoveCommand());
+ $this->add(new CommandPhpcr\NodePropertyShowCommand());
+ $this->add(new CommandPhpcr\SessionRefreshCommand());
+ $this->add(new CommandPhpcr\SessionSaveCommand());
+ $this->add(new CommandPhpcr\QuerySelectCommand());
+ $this->add(new CommandPhpcr\QueryCommand());
+ $this->add(new CommandPhpcr\RetentionHoldAddCommand());
+ $this->add(new CommandPhpcr\RetentionHoldListCommand());
+ $this->add(new CommandPhpcr\RetentionHoldRemoveCommand());
+ $this->add(new CommandPhpcr\RetentionPolicyGetCommand());
+ $this->add(new CommandPhpcr\RetentionPolicyRemoveCommand());
+ $this->add(new CommandPhpcr\WorkspaceCreateCommand());
+ $this->add(new CommandPhpcr\WorkspaceDeleteCommand());
+ $this->add(new CommandPhpcr\WorkspaceListCommand());
+ $this->add(new CommandPhpcr\NodeCloneCommand());
+ $this->add(new CommandPhpcr\NodeCopyCommand());
+ $this->add(new CommandPhpcr\WorkspaceNamespaceListCommand());
+ $this->add(new CommandPhpcr\WorkspaceNamespaceRegisterCommand());
+ $this->add(new CommandPhpcr\WorkspaceNamespaceUnregisterCommand());
+ $this->add(new CommandPhpcr\WorkspaceUseCommand());
+ $this->add(new CommandPhpcr\NodeTypeShowCommand());
+ $this->add(new CommandPhpcr\NodeTypeEditCommand());
+ $this->add(new CommandPhpcr\NodeTypeUnregisterCommand());
+ $this->add(new CommandPhpcr\NodeTypeListCommand());
+ $this->add(new CommandPhpcr\NodeTypeLoadCommand());
+ $this->add(new CommandPhpcr\VersionCheckoutCommand());
+ $this->add(new CommandPhpcr\VersionHistoryCommand());
+ $this->add(new CommandPhpcr\VersionRestoreCommand());
+ $this->add(new CommandPhpcr\VersionRemoveCommand());
+ $this->add(new CommandPhpcr\VersionCheckpointCommand());
+ $this->add(new CommandPhpcr\VersionCheckinCommand());
+ $this->add(new CommandPhpcr\NodeCreateCommand());
+ $this->add(new CommandPhpcr\NodeCorrespondingCommand());
+ $this->add(new CommandPhpcr\NodeDefinitionCommand());
+ $this->add(new CommandPhpcr\NodePropertySetCommand());
+ $this->add(new CommandPhpcr\NodeSetPrimaryTypeCommand());
+ $this->add(new CommandPhpcr\NodeRenameCommand());
+ $this->add(new CommandPhpcr\NodeMoveCommand());
+ $this->add(new CommandPhpcr\NodeMixinAddCommand());
+ $this->add(new CommandPhpcr\NodeMixinRemoveCommand());
+ $this->add(new CommandPhpcr\NodeOrderBeforeCommand());
+ $this->add(new CommandPhpcr\NodeInfoCommand());
+ $this->add(new CommandPhpcr\NodeLifecycleFollowCommand());
+ $this->add(new CommandPhpcr\NodeLifecycleListCommand());
+ $this->add(new CommandPhpcr\NodeListCommand());
+ $this->add(new CommandPhpcr\NodeUpdateCommand());
+ $this->add(new CommandPhpcr\NodeReferencesCommand());
+ $this->add(new CommandPhpcr\NodeSharedShowCommand());
+ $this->add(new CommandPhpcr\NodeSharedRemoveCommand());
+ $this->add(new CommandPhpcr\NodeRemoveCommand());
+ $this->add(new CommandPhpcr\LockLockCommand());
+ $this->add(new CommandPhpcr\LockInfoCommand());
+ $this->add(new CommandPhpcr\LockRefreshCommand());
+ $this->add(new CommandPhpcr\LockTokenAddCommand());
+ $this->add(new CommandPhpcr\LockTokenListCommand());
+ $this->add(new CommandPhpcr\LockTokenRemoveCommand());
+ $this->add(new CommandPhpcr\LockUnlockCommand());
- $this->initialized = true;
+ // add shell-specific commands
+ $this->add(new CommandShell\AliasListCommand());
+ $this->add(new CommandShell\ConfigInitCommand());
+ $this->add(new CommandShell\ConfigReloadCommand());
+ $this->add(new CommandShell\PathChangeCommand());
+ $this->add(new CommandShell\PathShowCommand());
+ $this->add(new CommandShell\ExitCommand());
+ }
+
+ private function registerEventListeners()
+ {
+ $this->dispatcher->addSubscriber(new Subscriber\ConfigInitSubscriber());
+ $this->dispatcher->addSubscriber(new Subscriber\ExceptionSubscriber());
+ $this->dispatcher->addSubscriber(new Subscriber\AliasSubscriber($this->getHelperSet()->get('config')));
}
+ /**
+ * Initialize the PHPCR session
+ */
private function initSession()
{
- $transport = $this->getTransport($this->sessionInput);
+ $transport = $this->getTransport();
$repository = $transport->getRepository();
$credentials = new SimpleCredentials(
$this->sessionInput->getOption('phpcr-username'),
@@ -282,6 +259,8 @@ private function initSession()
/**
* Change the current workspace
*
+ * @todo: Move to session helper?
+ *
* @param string $workspaceName
*/
public function changeWorkspace($workspaceName)
@@ -291,6 +270,15 @@ public function changeWorkspace($workspaceName)
$this->initSession($this->sessionInput);
}
+ /**
+ * Login (again)
+ *
+ * @todo: Move to session helper
+ *
+ * @param string $username
+ * @param string $password
+ * @param string $workspaceName
+ */
public function relogin($username, $password, $workspaceName = null)
{
$this->session->logout();
@@ -303,9 +291,12 @@ public function relogin($username, $password, $workspaceName = null)
$this->initSession($this->sessionInput);
}
- private function getTransport(InputInterface $input)
+ /**
+ * Return the transport as defined in the sessionInput
+ */
+ private function getTransport()
{
- $transportName = $input->getOption('transport');
+ $transportName = $this->sessionInput->getOption('transport');
if (!isset($this->transports[$transportName])) {
throw new \InvalidArgumentException(sprintf(
@@ -319,11 +310,9 @@ private function getTransport(InputInterface $input)
return $transport;
}
- public function wrap(Command $command)
- {
- return $command;
- }
-
+ /**
+ * Configure the output formatter
+ */
private function configureFormatter(OutputFormatter $formatter)
{
$style = new OutputFormatterStyle(null, null, array('bold'));
@@ -340,53 +329,71 @@ private function configureFormatter(OutputFormatter $formatter)
$style = new OutputFormatterStyle(null, null, array());
$formatter->setStyle('property-value', $style);
+
+ $style = new OutputFormatterStyle(null, 'red', array());
+ $formatter->setStyle('exception', $style);
}
+ /**
+ * {@inheritDoc}
+ */
public function doRun(InputInterface $input, OutputInterface $output)
{
$this->init();
+
+ // configure the formatter for the output
$this->configureFormatter($output->getFormatter());
$name = $this->getCommandName($input);
+ $event = new Event\CommandPreRunEvent($name, $input);
+ $this->dispatcher->dispatch(PhpcrShellEvents::COMMAND_PRE_RUN, $event);
+ $input = $event->getInput();
+
if (!$name) {
- $input = new ArrayInput(array('command' => 'pwd'));
+ $input = new ArrayInput(array('command' => 'shell:path:show'));
}
try {
$exitCode = parent::doRun($input, $output);
} catch (\Exception $e) {
- if (!$e->getMessage()) {
- if ($e instanceof \PHPCR\UnsupportedRepositoryOperationException) {
- throw new \Exception('Unsupported repository operation');
- }
- }
-
- if ($e instanceof NotImplementedException) {
- throw new \Exception('Not implemented: ' . $e->getMessage());
- }
-
- $output->writeln('(' . get_class($e) .') ' . $e->getMessage() . '');
+ $this->dispatcher->dispatch(PhpcrShellEvents::COMMAND_EXCEPTION, new Event\CommandExceptionEvent($e, $output));
return 1;
}
return $exitCode;
}
- public function renderException($e, $output)
+ /**
+ * {@inheritDoc}
+ *
+ * Render an exception to the console
+ *
+ * @access public
+ *
+ * @param \Exception $e $exception
+ * @param OutputInterface $output
+ */
+ public function renderException($exception, $output)
{
- do {
- $output->writeln(sprintf('%s', $e->getMessage()));
- } while ($e = $e->getPrevious());
+ $output->writeln(sprintf('%s', $exception->getMessage()));
}
+ /**
+ * {@inheritDoc}
+ *
+ * Wrap the add method and do not register commands which are unsupported by
+ * the current transport.
+ *
+ * @param Command $command
+ */
public function add(Command $command)
{
if ($command instanceof PhpcrShellCommand) {
$showUnsupported = $this->sessionInput->getOption('unsupported');
if ($showUnsupported || $command->isSupported($this->getHelperSet()->get('repository'))) {
- return parent::add($command);
+ parent::add($command);
}
} else {
parent::add($command);
diff --git a/src/PHPCR/Shell/Console/Command/Phpcr/NodeListCommand.php b/src/PHPCR/Shell/Console/Command/Phpcr/NodeListCommand.php
index e400f2d2..5878687b 100644
--- a/src/PHPCR/Shell/Console/Command/Phpcr/NodeListCommand.php
+++ b/src/PHPCR/Shell/Console/Command/Phpcr/NodeListCommand.php
@@ -22,7 +22,7 @@ protected function configure()
{
$this->setName('node:list');
$this->setDescription('List the children / properties of this node');
- $this->addArgument('path', InputArgument::OPTIONAL, 'Path of node');
+ $this->addArgument('path', InputArgument::OPTIONAL, 'Path of node', '.');
$this->addOption('children', null, InputOption::VALUE_NONE, 'List only the children of this node');
$this->addOption('properties', null, InputOption::VALUE_NONE, 'List only the properties of this node');
$this->addOption('filter', 'f', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Optional filter to apply');
diff --git a/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertySetCommand.php b/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertySetCommand.php
index 269435de..c48acf29 100644
--- a/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertySetCommand.php
+++ b/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertySetCommand.php
@@ -12,6 +12,7 @@
use PHPCR\NamespaceException;
use Symfony\Component\Console\Input\InputOption;
use PHPCR\PropertyType;
+use PHPCR\PathNotFoundException;
class NodePropertySetCommand extends Command
{
@@ -79,10 +80,15 @@ public function execute(InputInterface $input, OutputInterface $output)
if ($type) {
$intType = PropertyType::valueFromName($type);
} else {
- $property = $node->getProperty($propName);
- $intType = $property->getType();
+ try {
+ $property = $node->getProperty($propName);
+ $intType = $property->getType();
+ } catch (PathNotFoundException $e) {
+ // property doesn't exist and no type specified, default to string
+ $intType = PropertyType::STRING;
+ }
}
- $node->setProperty($propName, $value);
+ $node->setProperty($propName, $value, $intType);
}
}
diff --git a/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertyShowCommand.php b/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertyShowCommand.php
index 5609e458..801241d4 100644
--- a/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertyShowCommand.php
+++ b/src/PHPCR/Shell/Console/Command/Phpcr/NodePropertyShowCommand.php
@@ -7,6 +7,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use PHPCR\PathNotFoundException;
+use PHPCR\PropertyInterface;
class NodePropertyShowCommand extends Command
{
@@ -24,7 +25,7 @@ protected function configure()
public function execute(InputInterface $input, OutputInterface $output)
{
$session = $this->getHelper('phpcr')->getSession();
- $absPath = $input->getArgument('absPath');
+ $absPath = $session->getAbsPath($input->getArgument('absPath'));
$resultFormatHelper = $this->getHelper('result_formatter');
try {
@@ -35,6 +36,14 @@ public function execute(InputInterface $input, OutputInterface $output)
));
}
+ if (!$property instanceof PropertyInterface) {
+ throw new \Exception(sprintf(
+ 'Item at "%s" is not a property.',
+ $absPath
+ ));
+
+ }
+
$output->writeln($resultFormatHelper->formatValue($property, true));
}
}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/AliasListCommand.php b/src/PHPCR/Shell/Console/Command/Shell/AliasListCommand.php
new file mode 100644
index 00000000..d5593c1a
--- /dev/null
+++ b/src/PHPCR/Shell/Console/Command/Shell/AliasListCommand.php
@@ -0,0 +1,35 @@
+setName('shell:alias:list');
+ $this->setDescription('List all the registered aliases');
+ $this->setHelp(<<~/.phpcrsh/aliases.yml.
+EOT
+ );
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output)
+ {
+ $config = $this->getHelper('config');
+ $aliases = $config->getConfig('alias');
+
+ $table = clone $this->getHelper('table');
+ $table->setHeaders(array('Alias', 'Command'));
+
+ foreach ($aliases as $alias => $command) {
+ $table->addRow(array($alias, $command));
+ }
+
+ $table->render($output);
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/ConfigInitCommand.php b/src/PHPCR/Shell/Console/Command/Shell/ConfigInitCommand.php
new file mode 100644
index 00000000..4e9a9ca8
--- /dev/null
+++ b/src/PHPCR/Shell/Console/Command/Shell/ConfigInitCommand.php
@@ -0,0 +1,30 @@
+setName('shell:config:init');
+ $this->setDescription('Initialize a local configuration with default values');
+ $this->setHelp(<<.phpcrsh in the users HOME directory.
+EOT
+ );
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->output = $output;
+ $configHelper = $this->getHelper('config');
+ $configHelper->initConfig($output, $this->getHelper('dialog'), $input->getOption('no-interaction'));
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/ConfigReloadCommand.php b/src/PHPCR/Shell/Console/Command/Shell/ConfigReloadCommand.php
new file mode 100644
index 00000000..49d9bff5
--- /dev/null
+++ b/src/PHPCR/Shell/Console/Command/Shell/ConfigReloadCommand.php
@@ -0,0 +1,30 @@
+setName('shell:config:reload');
+ $this->setDescription('Reload the configuration');
+ $this->setHelp(<<output = $output;
+ $config = $this->getHelper('config');
+ $config->loadConfig();
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/ExitCommand.php b/src/PHPCR/Shell/Console/Command/Shell/ExitCommand.php
index efdc7ad9..f662f433 100644
--- a/src/PHPCR/Shell/Console/Command/Shell/ExitCommand.php
+++ b/src/PHPCR/Shell/Console/Command/Shell/ExitCommand.php
@@ -10,7 +10,7 @@ class ExitCommand extends Command
{
public function configure()
{
- $this->setName('exit');
+ $this->setName('shell:exit');
$this->setDescription('Logout and quit the shell');
}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/ListTreeCommand.php b/src/PHPCR/Shell/Console/Command/Shell/ListTreeCommand.php
deleted file mode 100644
index 33ba01af..00000000
--- a/src/PHPCR/Shell/Console/Command/Shell/ListTreeCommand.php
+++ /dev/null
@@ -1,98 +0,0 @@
-setName('ls');
- $this->setDescription('List tree');
- $this->addOption('max-depth', 'd', InputOption::VALUE_REQUIRED, 'Depth', 1);
- $this->addOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit results', null);
- $this->addOption('show-system', null, InputOption::VALUE_NONE, 'Show system nodes');
- }
-
- public function execute(InputInterface $input, OutputInterface $output)
- {
- $this->nodeCount = 0;
-
- $session = $this->getHelper('phpcr')->getSession();
- $node = $session->getNode($session->getCwd());
- $this->maxDepth = $input->getOption('max-depth');
- $this->maxResults = $input->getOption('limit');
- $this->showSystem = $input->getOption('show-system');
-
- $rows = new \ArrayObject();
- $this->iterateTree($node, $rows);
-
- $table = clone $this->getHelper('table');
- $table->setHeaders(array('Node / Prop', 'Type', 'Value'));
-
- foreach ($rows as $row) {
- $table->addRow($row);
- }
-
- $table->render($output);
-
- $output->writeln('');
- $output->writeln($this->nodeCount . ' node(s)');
- }
-
- public function iterateTree(NodeInterface $node, $rows, $depth = -1)
- {
- if (null !== $this->maxResults && $this->nodeCount >= $this->maxResults) {
- return;
- }
-
- if (true === NodeHelper::isSystemItem($node) && false === $this->showSystem) {
- return;
- }
-
- $this->nodeCount++;
-
- $formatter = $this->getHelper('result_formatter');
- $properties = $node->getProperties();
-
- $rows[] = array(
- str_repeat(' ', $depth + 1) . '' . $node->getName() . '/',
- '' . $node->getPrimaryNodeType()->getName() . '',
- '',
- );
-
- $depth++;
- if ($depth >= $this->maxDepth) {
- return;
- }
-
- foreach ($properties as $key => $property) {
- if (true === NodeHelper::isSystemItem($property) && false === $this->showSystem) {
- continue;
- }
- $rows[] = array(
- sprintf('%s -%s', str_repeat(' ', $depth), $key),
- $formatter->getPropertyTypeName($property->getType()) . ($property->isMultiple() ? '[]' : ''),
- substr($formatter->formatValue($property), 0, 55),
- );
- }
-
- foreach ($node->getNodes() as $child) {
- if ($depth < $this->maxDepth) {
- $this->iterateTree($child, $rows, $depth);
- }
- }
- }
-}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/ChangePathCommand.php b/src/PHPCR/Shell/Console/Command/Shell/PathChangeCommand.php
similarity index 90%
rename from src/PHPCR/Shell/Console/Command/Shell/ChangePathCommand.php
rename to src/PHPCR/Shell/Console/Command/Shell/PathChangeCommand.php
index 1ebe32a8..2f090419 100644
--- a/src/PHPCR/Shell/Console/Command/Shell/ChangePathCommand.php
+++ b/src/PHPCR/Shell/Console/Command/Shell/PathChangeCommand.php
@@ -7,11 +7,11 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-class ChangePathCommand extends Command
+class PathChangeCommand extends Command
{
protected function configure()
{
- $this->setName('cd');
+ $this->setName('shell:path:change');
$this->setDescription('Change the current path');
$this->addArgument('path');
}
diff --git a/src/PHPCR/Shell/Console/Command/Shell/PwdCommand.php b/src/PHPCR/Shell/Console/Command/Shell/PathShowCommand.php
similarity index 87%
rename from src/PHPCR/Shell/Console/Command/Shell/PwdCommand.php
rename to src/PHPCR/Shell/Console/Command/Shell/PathShowCommand.php
index 05066421..9f2396e6 100644
--- a/src/PHPCR/Shell/Console/Command/Shell/PwdCommand.php
+++ b/src/PHPCR/Shell/Console/Command/Shell/PathShowCommand.php
@@ -6,11 +6,11 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
-class PwdCommand extends Command
+class PathShowCommand extends Command
{
protected function configure()
{
- $this->setName('pwd');
+ $this->setName('shell:path:show');
$this->setDescription('Print Working Directory (or path)');
}
diff --git a/src/PHPCR/Shell/Console/Helper/ConfigHelper.php b/src/PHPCR/Shell/Console/Helper/ConfigHelper.php
new file mode 100644
index 00000000..efee3a13
--- /dev/null
+++ b/src/PHPCR/Shell/Console/Helper/ConfigHelper.php
@@ -0,0 +1,190 @@
+
+ */
+class ConfigHelper extends Helper
+{
+ /**
+ * Base filenames of all the possible configuration files
+ * in the users configuration directory.
+ *
+ * @var array
+ */
+ protected $configKeys = array(
+ 'alias'
+ );
+
+ /**
+ * Cached configuration
+ *
+ * @var array
+ */
+ protected $cachedConfig = null;
+
+ /**
+ * Filesystem
+ *
+ * @var Filesystem
+ */
+ protected $filesystem;
+
+ public function __construct(Filesystem $filesystem = null)
+ {
+ if (null === $filesystem) {
+ $filesystem = new Filesystem();
+ }
+
+ $this->filesystem = $filesystem;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName()
+ {
+ return 'config';
+ }
+
+ /**
+ * Return the configuration directory
+ *
+ * @return string
+ */
+ public function getConfigDir()
+ {
+ $home = getenv('PHPCRSH_HOME');
+
+ if ($home) {
+ return $home;
+ }
+
+ // handle windows ..
+ if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
+ if (!getenv('APPDATA')) {
+ throw new \RuntimeException(
+ 'The APPDATA or phpcrsh_HOME environment variable must be set for phpcrsh to run correctly'
+ );
+ }
+ $home = strtr(getenv('APPDATA'), '\\', '/').'/phpcrsh';
+
+ return $home;
+ }
+
+ if (!getenv('HOME')) {
+ throw new \RuntimeException(
+ 'The HOME or phpcrsh_HOME environment variable must be set for phpcrsh to run correctly'
+ );
+ }
+
+ $home = rtrim(getenv('HOME'), '/').'/.phpcrsh';
+
+ return $home;
+ }
+
+ /**
+ * Load the configuration
+ */
+ public function loadConfig()
+ {
+ $config = array();
+
+ $configDir = $this->getConfigDir();
+
+ foreach ($this->configKeys as $configKey) {
+ $fullPath = $configDir . '/' . $configKey . '.yml';
+ $config[$configKey] = array();
+
+ if ($this->filesystem->exists($fullPath)) {
+ $config[$configKey] = Yaml::parse($fullPath);
+ }
+ }
+
+ $this->cachedConfig = $config;
+
+ return $config;
+ }
+
+ /**
+ * Return the configuration
+ *
+ * @return array
+ */
+ public function getConfig($type)
+ {
+ if (null !== $this->cachedConfig) {
+ return $this->cachedConfig[$type];
+ }
+
+ $this->loadConfig();
+
+ return $this->cachedConfig[$type];
+ }
+
+ /**
+ * Initialize a configuration files
+ */
+ public function initConfig(OutputInterface $output = null, DialogHelper $dialogHelper = null, $noInteraction = false)
+ {
+ $log = function ($message) use ($output) {
+ if ($output) {
+ $output->writeln($message);
+ }
+ };
+
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ throw new \RuntimeException('This feature is currently only supported on Linux and OSX (maybe). Please submit a PR to support it on windows.');
+ }
+
+ $configDir = $this->getConfigDir();
+ $distDir = __DIR__ . '/../../Resources/config.dist';
+
+ if (!$this->filesystem->exists($configDir)) {
+ $log('[+] Creating directory: ' . $configDir);
+ $this->filesystem->mkdir($configDir);
+ }
+
+ $configFilenames = array(
+ 'alias.yml',
+ );
+
+ foreach ($configFilenames as $configFilename) {
+ $srcFile = $distDir . '/' . $configFilename;
+ $destFile = $configDir . '/' . $configFilename;
+
+ if (!$this->filesystem->exists($srcFile)) {
+ throw new \Exception('Dist (source) file "' . $srcFile . '" does not exist.');
+ }
+
+ if ($this->filesystem->exists($destFile)) {
+ if (null !== $dialogHelper) {
+ if (false === $noInteraction) {
+ $confirmed = $dialogHelper->askConfirmation(
+ $output,
+ '"' . $configFilename . '" already exists, do you want to overwrite it?'
+ );
+
+ if (!$confirmed) {
+ return;
+ }
+ }
+ } else {
+ $log(sprintf('File %s already exists, not overwriting.', $destFile));
+ }
+ }
+
+ $this->filesystem->copy($srcFile, $destFile);
+ $log('[+] Creating file: ' . $destFile);
+ }
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Input/StringInput.php b/src/PHPCR/Shell/Console/Input/StringInput.php
index df963b28..d4bfaa94 100644
--- a/src/PHPCR/Shell/Console/Input/StringInput.php
+++ b/src/PHPCR/Shell/Console/Input/StringInput.php
@@ -7,6 +7,7 @@
class StringInput extends BaseInput
{
protected $rawCommand;
+ protected $tokens;
public function __construct($command)
{
@@ -38,6 +39,17 @@ protected function parse()
}
}
+ protected function setTokens(array $tokens)
+ {
+ $this->tokens = $tokens;
+ parent::setTokens($tokens);
+ }
+
+ public function getTokens()
+ {
+ return $this->tokens;
+ }
+
protected function isQuery()
{
if (strpos(strtolower($this->rawCommand), 'select') === 0) {
diff --git a/src/PHPCR/Shell/Event/ApplicationInitEvent.php b/src/PHPCR/Shell/Event/ApplicationInitEvent.php
new file mode 100644
index 00000000..c0cde764
--- /dev/null
+++ b/src/PHPCR/Shell/Event/ApplicationInitEvent.php
@@ -0,0 +1,28 @@
+
+ */
+class ApplicationInitEvent extends Event
+{
+ protected $application;
+
+ public function __construct(Application $application)
+ {
+ $this->application = $application;
+ }
+
+ public function getApplication()
+ {
+ return $this->application;
+ }
+
+}
diff --git a/src/PHPCR/Shell/Event/CommandExceptionEvent.php b/src/PHPCR/Shell/Event/CommandExceptionEvent.php
new file mode 100644
index 00000000..5d066b3f
--- /dev/null
+++ b/src/PHPCR/Shell/Event/CommandExceptionEvent.php
@@ -0,0 +1,30 @@
+exception = $exception;
+ $this->output = $output;
+ }
+
+ public function getException()
+ {
+ return $this->exception;
+ }
+
+ public function getOutput()
+ {
+ return $this->output;
+ }
+}
diff --git a/src/PHPCR/Shell/Event/CommandPreRunEvent.php b/src/PHPCR/Shell/Event/CommandPreRunEvent.php
new file mode 100644
index 00000000..dac210e2
--- /dev/null
+++ b/src/PHPCR/Shell/Event/CommandPreRunEvent.php
@@ -0,0 +1,34 @@
+commandName = $commandName;
+ $this->input = $input;
+ }
+
+ public function getInput()
+ {
+ return $this->input;
+ }
+
+ public function setInput($input)
+ {
+ $this->input = $input;
+ }
+
+ public function getCommandName()
+ {
+ return $this->commandName;
+ }
+
+}
diff --git a/src/PHPCR/Shell/Event/PhpcrShellEvents.php b/src/PHPCR/Shell/Event/PhpcrShellEvents.php
new file mode 100644
index 00000000..92fd6ca7
--- /dev/null
+++ b/src/PHPCR/Shell/Event/PhpcrShellEvents.php
@@ -0,0 +1,10 @@
+
+ */
+class AliasSubscriber implements EventSubscriberInterface
+{
+ protected $config;
+
+ public function __construct(ConfigHelper $config)
+ {
+ $this->config = $config;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ PhpcrShellEvents::COMMAND_PRE_RUN => 'handleAlias',
+ );
+ }
+
+ /**
+ * Check for an alias and replace the input with a new string command
+ * if the alias exists.
+ *
+ * @return string New command string (for testing purposes)
+ */
+ public function handleAlias(CommandPreRunEvent $event)
+ {
+ $input = $event->getInput();
+
+ $commandName = $input->getFirstArgument();
+
+ $aliasConfig = $this->config->getConfig('alias');
+
+ if (!isset($aliasConfig[$commandName])) {
+ return;
+ }
+
+ $commandTemplate = $aliasConfig[$commandName];
+ $replaces = array();
+
+ preg_match_all('{\{arg[0-9]+\}}', $commandTemplate, $matches);
+
+ $args = array();
+ if (isset($matches[0])) {
+ $args = $matches[0];
+ }
+
+ $tokens = $input->getTokens();
+
+ foreach ($tokens as $i => $token) {
+ $replaces['{arg' . $i . '}'] = $token;
+ }
+
+ $command = strtr($commandTemplate, $replaces);
+
+ foreach ($args as $arg) {
+ $command = str_replace($arg, '', $command);
+ }
+
+ $command = trim($command);
+
+ $newInput = new StringInput($command);
+ $event->setInput($newInput);
+
+ return $command;
+ }
+}
diff --git a/src/PHPCR/Shell/Subscriber/ConfigInitSubscriber.php b/src/PHPCR/Shell/Subscriber/ConfigInitSubscriber.php
new file mode 100644
index 00000000..fa4ab864
--- /dev/null
+++ b/src/PHPCR/Shell/Subscriber/ConfigInitSubscriber.php
@@ -0,0 +1,34 @@
+
+ */
+class ConfigInitSubscriber implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array(
+ PhpcrShellEvents::APPLICATION_INIT => 'handleApplicationInit',
+ );
+ }
+
+ public function handleApplicationInit(ApplicationInitEvent $event)
+ {
+ $application = $event->getApplication();
+ $config = $application->getHelperSet()->get('config');
+ $configDir = $config->getConfigDir();
+
+ if (!file_exists($configDir)) {
+ $config->initConfig();
+ }
+ }
+}
diff --git a/src/PHPCR/Shell/Subscriber/ExceptionSubscriber.php b/src/PHPCR/Shell/Subscriber/ExceptionSubscriber.php
new file mode 100644
index 00000000..ea005d03
--- /dev/null
+++ b/src/PHPCR/Shell/Subscriber/ExceptionSubscriber.php
@@ -0,0 +1,40 @@
+
+ */
+class ExceptionSubscriber implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array(
+ PhpcrShellEvents::COMMAND_EXCEPTION => 'handleException',
+ );
+ }
+
+ public function handleException(CommandExceptionEvent $event)
+ {
+ $exception = $event->getException();
+ $output = $event->getOutput();
+
+ if ($exception instanceof UnsupportedRepositoryOperationException) {
+ $output->writeln('Unsupported repository operation: This repository is not capable of performing the requested action');
+ }
+
+ if ($exception instanceof NotImplementedException) {
+ $output->writeln('Not implemented: ' . $exception->getMessage() . '');
+ }
+
+ $output->writeln('[' . get_class($exception) .'] ' . $exception->getMessage() . '');
+ }
+}