From a93b8e10f5954be0853eec693c13e84c4bd9e6f2 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Fri, 15 Dec 2017 11:24:35 -0800 Subject: Kanboard requires at least PHP 5.6 now --- vendor/symfony/console/Application.php | 605 +++++++++-------- vendor/symfony/console/CHANGELOG.md | 39 ++ vendor/symfony/console/Command/Command.php | 164 ++--- vendor/symfony/console/Command/HelpCommand.php | 12 - vendor/symfony/console/Command/ListCommand.php | 7 - vendor/symfony/console/Command/LockableTrait.php | 72 ++ .../CommandLoader/CommandLoaderInterface.php | 37 ++ .../CommandLoader/ContainerCommandLoader.php | 55 ++ .../console/CommandLoader/FactoryCommandLoader.php | 62 ++ vendor/symfony/console/ConsoleEvents.php | 35 +- .../DependencyInjection/AddConsoleCommandPass.php | 106 +++ .../console/Descriptor/ApplicationDescription.php | 18 +- vendor/symfony/console/Descriptor/Descriptor.php | 17 +- .../symfony/console/Descriptor/JsonDescriptor.php | 36 +- .../console/Descriptor/MarkdownDescriptor.php | 73 +- .../symfony/console/Descriptor/TextDescriptor.php | 109 ++- .../symfony/console/Descriptor/XmlDescriptor.php | 20 +- .../symfony/console/Event/ConsoleCommandEvent.php | 2 - vendor/symfony/console/Event/ConsoleErrorEvent.php | 83 +++ vendor/symfony/console/Event/ConsoleEvent.php | 4 +- .../console/Event/ConsoleExceptionEvent.php | 4 + .../console/EventListener/ErrorListener.php | 91 +++ .../console/Exception/CommandNotFoundException.php | 10 +- .../symfony/console/Formatter/OutputFormatter.php | 78 +-- .../console/Formatter/OutputFormatterInterface.php | 2 + .../console/Formatter/OutputFormatterStyle.php | 4 +- .../Formatter/OutputFormatterStyleInterface.php | 2 - .../Formatter/OutputFormatterStyleStack.php | 16 +- vendor/symfony/console/Helper/DescriptorHelper.php | 5 +- vendor/symfony/console/Helper/DialogHelper.php | 502 -------------- vendor/symfony/console/Helper/FormatterHelper.php | 24 + vendor/symfony/console/Helper/Helper.php | 33 +- vendor/symfony/console/Helper/HelperInterface.php | 2 - vendor/symfony/console/Helper/HelperSet.php | 23 +- vendor/symfony/console/Helper/ProcessHelper.php | 24 +- vendor/symfony/console/Helper/ProgressBar.php | 150 ++--- vendor/symfony/console/Helper/ProgressHelper.php | 471 ------------- .../symfony/console/Helper/ProgressIndicator.php | 61 +- vendor/symfony/console/Helper/QuestionHelper.php | 84 ++- .../console/Helper/SymfonyQuestionHelper.php | 31 +- vendor/symfony/console/Helper/Table.php | 146 ++-- vendor/symfony/console/Helper/TableCell.php | 11 +- vendor/symfony/console/Helper/TableHelper.php | 269 -------- vendor/symfony/console/Helper/TableSeparator.php | 4 - vendor/symfony/console/Helper/TableStyle.php | 18 +- vendor/symfony/console/Input/ArgvInput.php | 94 +-- vendor/symfony/console/Input/ArrayInput.php | 60 +- vendor/symfony/console/Input/Input.php | 95 +-- vendor/symfony/console/Input/InputArgument.php | 2 - vendor/symfony/console/Input/InputDefinition.php | 63 +- vendor/symfony/console/Input/InputInterface.php | 39 +- vendor/symfony/console/Input/InputOption.php | 4 - .../console/Input/StreamableInputInterface.php | 37 ++ vendor/symfony/console/Input/StringInput.php | 19 +- vendor/symfony/console/LICENSE | 2 +- vendor/symfony/console/Logger/ConsoleLogger.php | 62 +- vendor/symfony/console/Output/BufferedOutput.php | 5 +- vendor/symfony/console/Output/ConsoleOutput.php | 20 +- .../console/Output/ConsoleOutputInterface.php | 5 - vendor/symfony/console/Output/NullOutput.php | 12 + vendor/symfony/console/Output/Output.php | 14 +- vendor/symfony/console/Output/OutputInterface.php | 33 +- vendor/symfony/console/Output/StreamOutput.php | 6 +- vendor/symfony/console/Question/ChoiceQuestion.php | 24 +- .../console/Question/ConfirmationQuestion.php | 2 - vendor/symfony/console/Question/Question.php | 30 +- vendor/symfony/console/Shell.php | 233 ------- vendor/symfony/console/Style/OutputStyle.php | 45 +- vendor/symfony/console/Style/StyleInterface.php | 5 - vendor/symfony/console/Style/SymfonyStyle.php | 153 ++--- vendor/symfony/console/Terminal.php | 137 ++++ .../symfony/console/Tester/ApplicationTester.php | 76 ++- vendor/symfony/console/Tester/CommandTester.php | 40 +- vendor/symfony/console/Tests/ApplicationTest.php | 736 ++++++++++++++++++--- .../symfony/console/Tests/Command/CommandTest.php | 117 ++-- .../console/Tests/Command/HelpCommandTest.php | 5 +- .../console/Tests/Command/ListCommandTest.php | 5 +- .../console/Tests/Command/LockableTraitTest.php | 67 ++ .../CommandLoader/ContainerCommandLoaderTest.php | 61 ++ .../CommandLoader/FactoryCommandLoaderTest.php | 60 ++ .../AddConsoleCommandPassTest.php | 187 ++++++ .../Tests/Descriptor/AbstractDescriptorTest.php | 9 +- .../Tests/Descriptor/JsonDescriptorTest.php | 4 +- .../Tests/Descriptor/MarkdownDescriptorTest.php | 18 + .../console/Tests/Descriptor/ObjectsProvider.php | 5 + .../Tests/Descriptor/TextDescriptorTest.php | 26 + .../Tests/EventListener/ErrorListenerTest.php | 156 +++++ .../Tests/Fixtures/DescriptorApplication2.php | 2 + .../Fixtures/DescriptorApplicationMbString.php | 24 + .../console/Tests/Fixtures/DescriptorCommand3.php | 27 + .../console/Tests/Fixtures/DescriptorCommand4.php | 25 + .../Tests/Fixtures/DescriptorCommandMbString.php | 32 + .../symfony/console/Tests/Fixtures/DummyOutput.php | 2 +- .../symfony/console/Tests/Fixtures/Foo3Command.php | 2 +- .../console/Tests/Fixtures/FooLock2Command.php | 28 + .../console/Tests/Fixtures/FooLockCommand.php | 27 + .../console/Tests/Fixtures/FooOptCommand.php | 36 + .../Tests/Fixtures/FooSameCaseLowercaseCommand.php | 11 + .../Tests/Fixtures/FooSameCaseUppercaseCommand.php | 11 + .../Style/SymfonyStyle/command/command_0.php | 4 +- .../Style/SymfonyStyle/command/command_1.php | 4 +- .../Style/SymfonyStyle/command/command_10.php | 4 +- .../Style/SymfonyStyle/command/command_11.php | 11 +- .../Style/SymfonyStyle/command/command_12.php | 13 + .../Style/SymfonyStyle/command/command_13.php | 14 + .../Style/SymfonyStyle/command/command_14.php | 17 + .../Style/SymfonyStyle/command/command_15.php | 14 + .../Style/SymfonyStyle/command/command_16.php | 15 + .../Style/SymfonyStyle/command/command_17.php | 13 + .../Style/SymfonyStyle/command/command_2.php | 4 +- .../Style/SymfonyStyle/command/command_3.php | 4 +- .../Style/SymfonyStyle/command/command_4.php | 4 +- .../Style/SymfonyStyle/command/command_5.php | 6 +- .../Style/SymfonyStyle/command/command_6.php | 4 +- .../Style/SymfonyStyle/command/command_7.php | 4 +- .../Style/SymfonyStyle/command/command_8.php | 4 +- .../Style/SymfonyStyle/command/command_9.php | 4 +- .../SymfonyStyle/command/interactive_command_1.php | 19 + .../SymfonyStyle/output/interactive_output_1.txt | 7 + .../Style/SymfonyStyle/output/output_11.txt | 6 +- .../Style/SymfonyStyle/output/output_12.txt | 6 + .../Style/SymfonyStyle/output/output_13.txt | 7 + .../Style/SymfonyStyle/output/output_14.txt | 6 + .../Style/SymfonyStyle/output/output_15.txt | 7 + .../Style/SymfonyStyle/output/output_16.txt | 8 + .../Style/SymfonyStyle/output/output_17.txt | 7 + .../console/Tests/Fixtures/application_1.json | 157 ++++- .../console/Tests/Fixtures/application_1.md | 165 ++--- .../console/Tests/Fixtures/application_1.txt | 2 +- .../console/Tests/Fixtures/application_1.xml | 14 +- .../console/Tests/Fixtures/application_2.json | 510 +++++++++++++- .../console/Tests/Fixtures/application_2.md | 397 ++++++----- .../console/Tests/Fixtures/application_2.txt | 7 +- .../console/Tests/Fixtures/application_2.xml | 88 ++- .../console/Tests/Fixtures/application_astext1.txt | 20 - .../console/Tests/Fixtures/application_astext2.txt | 16 - .../console/Tests/Fixtures/application_asxml1.txt | 146 ---- .../console/Tests/Fixtures/application_asxml2.txt | 37 -- .../Fixtures/application_filtered_namespace.txt | 16 + .../console/Tests/Fixtures/application_gethelp.txt | 2 +- .../console/Tests/Fixtures/application_mbstring.md | 269 ++++++++ .../Tests/Fixtures/application_mbstring.txt | 19 + .../Fixtures/application_renderexception1.txt | 7 +- .../Fixtures/application_renderexception2.txt | 9 +- .../Fixtures/application_renderexception3.txt | 18 +- .../application_renderexception3decorated.txt | 20 +- .../Fixtures/application_renderexception4.txt | 9 +- .../application_renderexception_doublewidth1.txt | 2 +- ...ation_renderexception_doublewidth1decorated.txt | 2 +- .../application_renderexception_doublewidth2.txt | 2 +- .../application_renderexception_escapeslines.txt | 9 + .../application_renderexception_linebreaks.txt | 11 + .../console/Tests/Fixtures/application_run2.txt | 41 +- .../console/Tests/Fixtures/application_run3.txt | 31 +- .../symfony/console/Tests/Fixtures/command_1.json | 16 +- vendor/symfony/console/Tests/Fixtures/command_1.md | 15 +- .../symfony/console/Tests/Fixtures/command_1.txt | 2 +- .../symfony/console/Tests/Fixtures/command_1.xml | 2 +- .../symfony/console/Tests/Fixtures/command_2.json | 34 +- vendor/symfony/console/Tests/Fixtures/command_2.md | 28 +- .../symfony/console/Tests/Fixtures/command_2.txt | 8 +- .../symfony/console/Tests/Fixtures/command_2.xml | 2 +- .../console/Tests/Fixtures/command_astext.txt | 18 - .../console/Tests/Fixtures/command_asxml.txt | 38 -- .../console/Tests/Fixtures/command_mbstring.md | 29 + .../console/Tests/Fixtures/command_mbstring.txt | 13 + .../console/Tests/Fixtures/definition_astext.txt | 11 - .../console/Tests/Fixtures/definition_asxml.txt | 39 -- .../console/Tests/Fixtures/input_argument_1.json | 8 +- .../console/Tests/Fixtures/input_argument_1.md | 4 +- .../console/Tests/Fixtures/input_argument_2.json | 8 +- .../console/Tests/Fixtures/input_argument_2.md | 6 +- .../console/Tests/Fixtures/input_argument_3.json | 8 +- .../console/Tests/Fixtures/input_argument_3.md | 6 +- .../console/Tests/Fixtures/input_argument_4.json | 8 +- .../console/Tests/Fixtures/input_argument_4.md | 8 +- .../console/Tests/Fixtures/input_argument_4.txt | 2 +- .../input_argument_with_default_inf_value.json | 7 + .../input_argument_with_default_inf_value.md | 7 + .../input_argument_with_default_inf_value.txt | 1 + .../input_argument_with_default_inf_value.xml | 7 + .../Tests/Fixtures/input_argument_with_style.json | 7 + .../Tests/Fixtures/input_argument_with_style.md | 7 + .../Tests/Fixtures/input_argument_with_style.txt | 1 + .../Tests/Fixtures/input_argument_with_style.xml | 7 + .../console/Tests/Fixtures/input_definition_1.json | 5 +- .../console/Tests/Fixtures/input_definition_2.json | 13 +- .../console/Tests/Fixtures/input_definition_2.md | 6 +- .../console/Tests/Fixtures/input_definition_3.json | 15 +- .../console/Tests/Fixtures/input_definition_3.md | 7 +- .../console/Tests/Fixtures/input_definition_4.json | 23 +- .../console/Tests/Fixtures/input_definition_4.md | 13 +- .../console/Tests/Fixtures/input_option_1.json | 10 +- .../console/Tests/Fixtures/input_option_1.md | 5 +- .../console/Tests/Fixtures/input_option_2.json | 10 +- .../console/Tests/Fixtures/input_option_2.md | 7 +- .../console/Tests/Fixtures/input_option_3.json | 10 +- .../console/Tests/Fixtures/input_option_3.md | 7 +- .../console/Tests/Fixtures/input_option_4.json | 10 +- .../console/Tests/Fixtures/input_option_4.md | 7 +- .../console/Tests/Fixtures/input_option_5.json | 10 +- .../console/Tests/Fixtures/input_option_5.md | 9 +- .../console/Tests/Fixtures/input_option_5.txt | 2 +- .../console/Tests/Fixtures/input_option_6.json | 10 +- .../console/Tests/Fixtures/input_option_6.md | 7 +- .../input_option_with_default_inf_value.json | 9 + .../input_option_with_default_inf_value.md | 8 + .../input_option_with_default_inf_value.txt | 1 + .../input_option_with_default_inf_value.xml | 7 + .../Tests/Fixtures/input_option_with_style.json | 9 + .../Tests/Fixtures/input_option_with_style.md | 8 + .../Tests/Fixtures/input_option_with_style.txt | 1 + .../Tests/Fixtures/input_option_with_style.xml | 7 + .../Fixtures/input_option_with_style_array.json | 12 + .../Fixtures/input_option_with_style_array.md | 8 + .../Fixtures/input_option_with_style_array.txt | 1 + .../Fixtures/input_option_with_style_array.xml | 8 + .../Formatter/OutputFormatterStyleStackTest.php | 3 +- .../Tests/Formatter/OutputFormatterStyleTest.php | 7 +- .../Tests/Formatter/OutputFormatterTest.php | 73 +- .../Tests/Helper/AbstractQuestionHelperTest.php | 34 + .../console/Tests/Helper/FormatterHelperTest.php | 39 +- .../symfony/console/Tests/Helper/HelperSetTest.php | 12 +- vendor/symfony/console/Tests/Helper/HelperTest.php | 3 +- .../Tests/Helper/LegacyDialogHelperTest.php | 263 -------- .../Tests/Helper/LegacyProgressHelperTest.php | 224 ------- .../console/Tests/Helper/LegacyTableHelperTest.php | 316 --------- .../console/Tests/Helper/ProcessHelperTest.php | 21 +- .../console/Tests/Helper/ProgressBarTest.php | 240 +++++-- .../console/Tests/Helper/ProgressIndicatorTest.php | 13 +- .../console/Tests/Helper/QuestionHelperTest.php | 599 +++++++++++++++-- .../Tests/Helper/SymfonyQuestionHelperTest.php | 156 +++++ .../console/Tests/Helper/TableStyleTest.php | 3 +- vendor/symfony/console/Tests/Helper/TableTest.php | 271 ++++++-- .../symfony/console/Tests/Input/ArgvInputTest.php | 125 +++- .../symfony/console/Tests/Input/ArrayInputTest.php | 42 +- .../console/Tests/Input/InputArgumentTest.php | 10 +- .../console/Tests/Input/InputDefinitionTest.php | 43 +- .../console/Tests/Input/InputOptionTest.php | 10 +- vendor/symfony/console/Tests/Input/InputTest.php | 19 +- .../console/Tests/Input/StringInputTest.php | 16 +- .../console/Tests/Logger/ConsoleLoggerTest.php | 165 ++++- .../console/Tests/Output/ConsoleOutputTest.php | 19 +- .../console/Tests/Output/NullOutputTest.php | 51 +- vendor/symfony/console/Tests/Output/OutputTest.php | 3 +- .../console/Tests/Output/StreamOutputTest.php | 3 +- .../console/Tests/Style/SymfonyStyleTest.php | 81 ++- vendor/symfony/console/Tests/TerminalTest.php | 44 ++ .../console/Tests/Tester/ApplicationTesterTest.php | 3 +- .../console/Tests/Tester/CommandTesterTest.php | 81 ++- vendor/symfony/console/composer.json | 19 +- vendor/symfony/console/phpunit.xml.dist | 2 + 252 files changed, 7609 insertions(+), 4889 deletions(-) create mode 100644 vendor/symfony/console/Command/LockableTrait.php create mode 100644 vendor/symfony/console/CommandLoader/CommandLoaderInterface.php create mode 100644 vendor/symfony/console/CommandLoader/ContainerCommandLoader.php create mode 100644 vendor/symfony/console/CommandLoader/FactoryCommandLoader.php create mode 100644 vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php create mode 100644 vendor/symfony/console/Event/ConsoleErrorEvent.php create mode 100644 vendor/symfony/console/EventListener/ErrorListener.php delete mode 100644 vendor/symfony/console/Helper/DialogHelper.php delete mode 100644 vendor/symfony/console/Helper/ProgressHelper.php delete mode 100644 vendor/symfony/console/Helper/TableHelper.php create mode 100644 vendor/symfony/console/Input/StreamableInputInterface.php delete mode 100644 vendor/symfony/console/Shell.php create mode 100644 vendor/symfony/console/Terminal.php create mode 100644 vendor/symfony/console/Tests/Command/LockableTraitTest.php create mode 100644 vendor/symfony/console/Tests/CommandLoader/ContainerCommandLoaderTest.php create mode 100644 vendor/symfony/console/Tests/CommandLoader/FactoryCommandLoaderTest.php create mode 100644 vendor/symfony/console/Tests/DependencyInjection/AddConsoleCommandPassTest.php create mode 100644 vendor/symfony/console/Tests/EventListener/ErrorListenerTest.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorApplicationMbString.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorCommand3.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorCommand4.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorCommandMbString.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooLock2Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooLockCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooOptCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooSameCaseLowercaseCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooSameCaseUppercaseCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_12.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_13.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_14.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_15.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_16.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_17.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/interactive_command_1.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/interactive_output_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_12.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_13.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_14.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_15.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_16.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_17.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/application_astext1.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/application_astext2.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/application_asxml1.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/application_asxml2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_filtered_namespace.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_mbstring.md create mode 100644 vendor/symfony/console/Tests/Fixtures/application_mbstring.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception_escapeslines.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception_linebreaks.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/command_astext.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/command_asxml.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/command_mbstring.md create mode 100644 vendor/symfony/console/Tests/Fixtures/command_mbstring.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/definition_astext.txt delete mode 100644 vendor/symfony/console/Tests/Fixtures/definition_asxml.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_default_inf_value.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_default_inf_value.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_default_inf_value.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_default_inf_value.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_style.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_style.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_style.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_with_style.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_default_inf_value.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_default_inf_value.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_default_inf_value.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_default_inf_value.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style_array.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style_array.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style_array.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_with_style_array.xml create mode 100644 vendor/symfony/console/Tests/Helper/AbstractQuestionHelperTest.php delete mode 100644 vendor/symfony/console/Tests/Helper/LegacyDialogHelperTest.php delete mode 100644 vendor/symfony/console/Tests/Helper/LegacyProgressHelperTest.php delete mode 100644 vendor/symfony/console/Tests/Helper/LegacyTableHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/SymfonyQuestionHelperTest.php create mode 100644 vendor/symfony/console/Tests/TerminalTest.php (limited to 'vendor/symfony/console') diff --git a/vendor/symfony/console/Application.php b/vendor/symfony/console/Application.php index 603559f0..f3bc0d59 100644 --- a/vendor/symfony/console/Application.php +++ b/vendor/symfony/console/Application.php @@ -11,20 +11,21 @@ namespace Symfony\Component\Console; -use Symfony\Component\Console\Descriptor\TextDescriptor; -use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\CommandLoader\CommandLoaderInterface; use Symfony\Component\Console\Exception\ExceptionInterface; +use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\DebugFormatterHelper; +use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Helper\ProcessHelper; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StreamableInputInterface; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputAwareInterface; -use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\ConsoleOutputInterface; @@ -33,14 +34,14 @@ use Symfony\Component\Console\Command\HelpCommand; use Symfony\Component\Console\Command\ListCommand; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\FormatterHelper; -use Symfony\Component\Console\Helper\DialogHelper; -use Symfony\Component\Console\Helper\ProgressHelper; -use Symfony\Component\Console\Helper\TableHelper; use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Debug\ErrorHandler; +use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -65,17 +66,18 @@ class Application private $runningCommand; private $name; private $version; + private $commandLoader; private $catchExceptions = true; private $autoExit = true; private $definition; private $helperSet; private $dispatcher; - private $terminalDimensions; + private $terminal; private $defaultCommand; + private $singleCommand; + private $initialized; /** - * Constructor. - * * @param string $name The name of the application * @param string $version The version of the application */ @@ -83,13 +85,8 @@ class Application { $this->name = $name; $this->version = $version; + $this->terminal = new Terminal(); $this->defaultCommand = 'list'; - $this->helperSet = $this->getDefaultHelperSet(); - $this->definition = $this->getDefaultInputDefinition(); - - foreach ($this->getDefaultCommands() as $command) { - $this->add($command); - } } public function setDispatcher(EventDispatcherInterface $dispatcher) @@ -97,18 +94,23 @@ class Application $this->dispatcher = $dispatcher; } + public function setCommandLoader(CommandLoaderInterface $commandLoader) + { + $this->commandLoader = $commandLoader; + } + /** * Runs the current application. * - * @param InputInterface $input An Input instance - * @param OutputInterface $output An Output instance - * * @return int 0 if everything went fine, or an error code * - * @throws \Exception When doRun returns Exception + * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. */ public function run(InputInterface $input = null, OutputInterface $output = null) { + putenv('LINES='.$this->terminal->getHeight()); + putenv('COLUMNS='.$this->terminal->getWidth()); + if (null === $input) { $input = new ArgvInput(); } @@ -117,6 +119,29 @@ class Application $output = new ConsoleOutput(); } + $renderException = function ($e) use ($output) { + if (!$e instanceof \Exception) { + $e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine()); + } + if ($output instanceof ConsoleOutputInterface) { + $this->renderException($e, $output->getErrorOutput()); + } else { + $this->renderException($e, $output); + } + }; + if ($phpHandler = set_exception_handler($renderException)) { + restore_exception_handler(); + if (!is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) { + $debugHandler = true; + } elseif ($debugHandler = $phpHandler[0]->setExceptionHandler($renderException)) { + $phpHandler[0]->setExceptionHandler($debugHandler); + } + } + + if (null !== $this->dispatcher && $this->dispatcher->hasListeners(ConsoleEvents::EXCEPTION)) { + @trigger_error(sprintf('The "ConsoleEvents::EXCEPTION" event is deprecated since Symfony 3.3 and will be removed in 4.0. Listen to the "ConsoleEvents::ERROR" event instead.'), E_USER_DEPRECATED); + } + $this->configureIO($input, $output); try { @@ -126,11 +151,7 @@ class Application throw $e; } - if ($output instanceof ConsoleOutputInterface) { - $this->renderException($e, $output->getErrorOutput()); - } else { - $this->renderException($e, $output); - } + $renderException($e); $exitCode = $e->getCode(); if (is_numeric($exitCode)) { @@ -141,6 +162,12 @@ class Application } else { $exitCode = 1; } + } finally { + if (!$phpHandler) { + restore_exception_handler(); + } elseif (!$debugHandler) { + $phpHandler[0]->setExceptionHandler(null); + } } if ($this->autoExit) { @@ -157,24 +184,21 @@ class Application /** * Runs the current application. * - * @param InputInterface $input An Input instance - * @param OutputInterface $output An Output instance - * * @return int 0 if everything went fine, or an error code */ public function doRun(InputInterface $input, OutputInterface $output) { - if (true === $input->hasParameterOption(array('--version', '-V'))) { + if (true === $input->hasParameterOption(array('--version', '-V'), true)) { $output->writeln($this->getLongVersion()); return 0; } $name = $this->getCommandName($input); - if (true === $input->hasParameterOption(array('--help', '-h'))) { + if (true === $input->hasParameterOption(array('--help', '-h'), true)) { if (!$name) { $name = 'help'; - $input = new ArrayInput(array('command' => 'help')); + $input = new ArrayInput(array('command_name' => $this->defaultCommand)); } else { $this->wantHelps = true; } @@ -182,11 +206,35 @@ class Application if (!$name) { $name = $this->defaultCommand; - $input = new ArrayInput(array('command' => $this->defaultCommand)); + $definition = $this->getDefinition(); + $definition->setArguments(array_merge( + $definition->getArguments(), + array( + 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name), + ) + )); } - // the command name MUST be the first element of the input - $command = $this->find($name); + try { + $e = $this->runningCommand = null; + // the command name MUST be the first element of the input + $command = $this->find($name); + } catch (\Exception $e) { + } catch (\Throwable $e) { + } + if (null !== $e) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch(ConsoleEvents::ERROR, $event); + $e = $event->getError(); + + if (0 === $event->getExitCode()) { + return 0; + } + } + + throw $e; + } $this->runningCommand = $command; $exitCode = $this->doRunCommand($command, $input, $output); @@ -195,11 +243,6 @@ class Application return $exitCode; } - /** - * Set a helper set to be used with the command. - * - * @param HelperSet $helperSet The helper set - */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; @@ -212,14 +255,13 @@ class Application */ public function getHelperSet() { + if (!$this->helperSet) { + $this->helperSet = $this->getDefaultHelperSet(); + } + return $this->helperSet; } - /** - * Set an input definition set to be used with this application. - * - * @param InputDefinition $definition The input definition - */ public function setDefinition(InputDefinition $definition) { $this->definition = $definition; @@ -232,19 +274,40 @@ class Application */ public function getDefinition() { + if (!$this->definition) { + $this->definition = $this->getDefaultInputDefinition(); + } + + if ($this->singleCommand) { + $inputDefinition = $this->definition; + $inputDefinition->setArguments(); + + return $inputDefinition; + } + return $this->definition; } /** * Gets the help message. * - * @return string A help message. + * @return string A help message */ public function getHelp() { return $this->getLongVersion(); } + /** + * Gets whether to catch exceptions or not during commands execution. + * + * @return bool Whether to catch exceptions or not during commands execution + */ + public function areExceptionsCaught() + { + return $this->catchExceptions; + } + /** * Sets whether to catch exceptions or not during commands execution. * @@ -255,6 +318,16 @@ class Application $this->catchExceptions = (bool) $boolean; } + /** + * Gets whether to automatically exit after a command execution or not. + * + * @return bool Whether to automatically exit after a command execution or not + */ + public function isAutoExitEnabled() + { + return $this->autoExit; + } + /** * Sets whether to automatically exit after a command execution or not. * @@ -314,13 +387,13 @@ class Application { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { - return sprintf('%s version %s', $this->getName(), $this->getVersion()); + return sprintf('%s %s', $this->getName(), $this->getVersion()); } - return sprintf('%s', $this->getName()); + return $this->getName(); } - return 'Console Tool'; + return 'Console Tool'; } /** @@ -338,6 +411,8 @@ class Application /** * Adds an array of command objects. * + * If a Command is not enabled it will not be added. + * * @param Command[] $commands An array of commands */ public function addCommands(array $commands) @@ -351,13 +426,14 @@ class Application * Adds a command object. * * If a command with the same name already exists, it will be overridden. + * If the command is not enabled it will not be added. * - * @param Command $command A Command object - * - * @return Command The registered command + * @return Command|null The registered command if enabled or null */ public function add(Command $command) { + $this->init(); + $command->setApplication($this); if (!$command->isEnabled()) { @@ -370,6 +446,10 @@ class Application throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))); } + if (!$command->getName()) { + throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($command))); + } + $this->commands[$command->getName()] = $command; foreach ($command->getAliases() as $alias) { @@ -386,11 +466,13 @@ class Application * * @return Command A Command object * - * @throws CommandNotFoundException When command name given does not exist + * @throws CommandNotFoundException When given command name does not exist */ public function get($name) { - if (!isset($this->commands[$name])) { + $this->init(); + + if (!$this->has($name)) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); } @@ -417,15 +499,17 @@ class Application */ public function has($name) { - return isset($this->commands[$name]); + $this->init(); + + return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name))); } /** * Returns an array of all unique namespaces used by currently registered commands. * - * It does not returns the global namespace which always exists. + * It does not return the global namespace which always exists. * - * @return array An array of namespaces + * @return string[] An array of namespaces */ public function getNamespaces() { @@ -474,7 +558,7 @@ class Application $exact = in_array($namespace, $namespaces, true); if (count($namespaces) > 1 && !$exact) { - throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); + throw new CommandNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); } return $exact ? $namespace : reset($namespaces); @@ -494,11 +578,18 @@ class Application */ public function find($name) { - $allCommands = array_keys($this->commands); + $this->init(); + + $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands); $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name); $commands = preg_grep('{^'.$expr.'}', $allCommands); - if (empty($commands) || count(preg_grep('{^'.$expr.'$}', $commands)) < 1) { + if (empty($commands)) { + $commands = preg_grep('{^'.$expr.'}i', $allCommands); + } + + // if no commands matched or we just matched namespaces + if (empty($commands) || count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) { if (false !== $pos = strrpos($name, ':')) { // check if a namespace exists and contains commands $this->findNamespace(substr($name, 0, $pos)); @@ -520,19 +611,33 @@ class Application // filter out aliases for commands which are already on the list if (count($commands) > 1) { - $commandList = $this->commands; - $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) { - $commandName = $commandList[$nameOrAlias]->getName(); + $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; + $commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) { + $commandName = $commandList[$nameOrAlias] instanceof Command ? $commandList[$nameOrAlias]->getName() : $nameOrAlias; return $commandName === $nameOrAlias || !in_array($commandName, $commands); - }); + })); } $exact = in_array($name, $commands, true); if (count($commands) > 1 && !$exact) { - $suggestions = $this->getAbbreviationSuggestions(array_values($commands)); + $usableWidth = $this->terminal->getWidth() - 10; + $abbrevs = array_values($commands); + $maxLen = 0; + foreach ($abbrevs as $abbrev) { + $maxLen = max(Helper::strlen($abbrev), $maxLen); + } + $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) { + if (!$commandList[$cmd] instanceof Command) { + return $cmd; + } + $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription(); + + return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev; + }, array_values($commands)); + $suggestions = $this->getAbbreviationSuggestions($abbrevs); - throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands)); + throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands)); } return $this->get($exact ? $name : reset($commands)); @@ -549,8 +654,21 @@ class Application */ public function all($namespace = null) { + $this->init(); + if (null === $namespace) { - return $this->commands; + if (!$this->commandLoader) { + return $this->commands; + } + + $commands = $this->commands; + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + + return $commands; } $commands = array(); @@ -560,6 +678,14 @@ class Application } } + if ($this->commandLoader) { + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + } + return $commands; } @@ -584,78 +710,41 @@ class Application } /** - * Returns a text representation of the Application. - * - * @param string $namespace An optional namespace name - * @param bool $raw Whether to return raw command list - * - * @return string A string representing the Application - * - * @deprecated since version 2.3, to be removed in 3.0. - */ - public function asText($namespace = null, $raw = false) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); - - $descriptor = new TextDescriptor(); - $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw); - $descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true)); - - return $output->fetch(); - } - - /** - * Returns an XML representation of the Application. - * - * @param string $namespace An optional namespace name - * @param bool $asDom Whether to return a DOM or an XML string - * - * @return string|\DOMDocument An XML string representing the Application - * - * @deprecated since version 2.3, to be removed in 3.0. + * Renders a caught exception. */ - public function asXml($namespace = null, $asDom = false) + public function renderException(\Exception $e, OutputInterface $output) { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + $output->writeln('', OutputInterface::VERBOSITY_QUIET); - $descriptor = new XmlDescriptor(); + $this->doRenderException($e, $output); - if ($asDom) { - return $descriptor->getApplicationDocument($this, $namespace); + if (null !== $this->runningCommand) { + $output->writeln(sprintf('%s', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET); + $output->writeln('', OutputInterface::VERBOSITY_QUIET); } - - $output = new BufferedOutput(); - $descriptor->describe($output, $this, array('namespace' => $namespace)); - - return $output->fetch(); } - /** - * Renders a caught exception. - * - * @param \Exception $e An exception instance - * @param OutputInterface $output An OutputInterface instance - */ - public function renderException($e, $output) + protected function doRenderException(\Exception $e, OutputInterface $output) { - $output->writeln('', OutputInterface::VERBOSITY_QUIET); - do { - $title = sprintf(' [%s] ', get_class($e)); - - $len = $this->stringWidth($title); + $message = trim($e->getMessage()); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $title = sprintf(' [%s%s] ', get_class($e), 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); + $len = Helper::strlen($title); + } else { + $len = 0; + } - $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX; + $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : PHP_INT_MAX; // HHVM only accepts 32 bits integer in str_split, even when PHP_INT_MAX is a 64 bit integer: https://github.com/facebook/hhvm/issues/1327 if (defined('HHVM_VERSION') && $width > 1 << 31) { $width = 1 << 31; } - $formatter = $output->getFormatter(); $lines = array(); - foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) { + foreach ('' !== $message ? preg_split('/\r?\n/', $message) : array() as $line) { foreach ($this->splitStringByWidth($line, $width - 4) as $line) { // pre-format lines to get the right string length - $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4; + $lineLength = Helper::strlen($line) + 4; $lines[] = array($line, $lineLength); $len = max($lineLength, $len); @@ -663,27 +752,26 @@ class Application } $messages = array(); - $messages[] = $emptyLine = $formatter->format(sprintf('%s', str_repeat(' ', $len))); - $messages[] = $formatter->format(sprintf('%s%s', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title))))); + if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = sprintf('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + } + $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::strlen($title)))); + } foreach ($lines as $line) { - $messages[] = $formatter->format(sprintf(' %s %s', $line[0], str_repeat(' ', $len - $line[1]))); + $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; - $output->writeln($messages, OutputInterface::OUTPUT_RAW | OutputInterface::VERBOSITY_QUIET); + $output->writeln($messages, OutputInterface::VERBOSITY_QUIET); if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET); // exception related properties $trace = $e->getTrace(); - array_unshift($trace, array( - 'function' => '', - 'file' => $e->getFile() !== null ? $e->getFile() : 'n/a', - 'line' => $e->getLine() !== null ? $e->getLine() : 'n/a', - 'args' => array(), - )); for ($i = 0, $count = count($trace); $i < $count; ++$i) { $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; @@ -698,71 +786,48 @@ class Application $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } while ($e = $e->getPrevious()); - - if (null !== $this->runningCommand) { - $output->writeln(sprintf('%s', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET); - $output->writeln('', OutputInterface::VERBOSITY_QUIET); - } } /** * Tries to figure out the terminal width in which this application runs. * * @return int|null + * + * @deprecated since version 3.2, to be removed in 4.0. Create a Terminal instance instead. */ protected function getTerminalWidth() { - $dimensions = $this->getTerminalDimensions(); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__), E_USER_DEPRECATED); - return $dimensions[0]; + return $this->terminal->getWidth(); } /** * Tries to figure out the terminal height in which this application runs. * * @return int|null + * + * @deprecated since version 3.2, to be removed in 4.0. Create a Terminal instance instead. */ protected function getTerminalHeight() { - $dimensions = $this->getTerminalDimensions(); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__), E_USER_DEPRECATED); - return $dimensions[1]; + return $this->terminal->getHeight(); } /** * Tries to figure out the terminal dimensions based on the current environment. * * @return array Array containing width and height + * + * @deprecated since version 3.2, to be removed in 4.0. Create a Terminal instance instead. */ public function getTerminalDimensions() { - if ($this->terminalDimensions) { - return $this->terminalDimensions; - } - - if ('\\' === DIRECTORY_SEPARATOR) { - // extract [w, H] from "wxh (WxH)" - if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { - return array((int) $matches[1], (int) $matches[2]); - } - // extract [w, h] from "wxh" - if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) { - return array((int) $matches[1], (int) $matches[2]); - } - } + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__), E_USER_DEPRECATED); - if ($sttyString = $this->getSttyColumns()) { - // extract [w, h] from "rows h; columns w;" - if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { - return array((int) $matches[2], (int) $matches[1]); - } - // extract [w, h] from "; h rows; w columns" - if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { - return array((int) $matches[2], (int) $matches[1]); - } - } - - return array(null, null); + return array($this->terminal->getWidth(), $this->terminal->getHeight()); } /** @@ -773,49 +838,82 @@ class Application * @param int $width The width * @param int $height The height * - * @return Application The current application + * @return $this + * + * @deprecated since version 3.2, to be removed in 4.0. Set the COLUMNS and LINES env vars instead. */ public function setTerminalDimensions($width, $height) { - $this->terminalDimensions = array($width, $height); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Set the COLUMNS and LINES env vars instead.', __METHOD__), E_USER_DEPRECATED); + + putenv('COLUMNS='.$width); + putenv('LINES='.$height); return $this; } /** * Configures the input and output instances based on the user arguments and options. - * - * @param InputInterface $input An InputInterface instance - * @param OutputInterface $output An OutputInterface instance */ protected function configureIO(InputInterface $input, OutputInterface $output) { - if (true === $input->hasParameterOption(array('--ansi'))) { + if (true === $input->hasParameterOption(array('--ansi'), true)) { $output->setDecorated(true); - } elseif (true === $input->hasParameterOption(array('--no-ansi'))) { + } elseif (true === $input->hasParameterOption(array('--no-ansi'), true)) { $output->setDecorated(false); } - if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) { + if (true === $input->hasParameterOption(array('--no-interaction', '-n'), true)) { $input->setInteractive(false); - } elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) { - $inputStream = $this->getHelperSet()->get('question')->getInputStream(); + } elseif (function_exists('posix_isatty')) { + $inputStream = null; + + if ($input instanceof StreamableInputInterface) { + $inputStream = $input->getStream(); + } + + // This check ensures that calling QuestionHelper::setInputStream() works + // To be removed in 4.0 (in the same time as QuestionHelper::setInputStream) + if (!$inputStream && $this->getHelperSet()->has('question')) { + $inputStream = $this->getHelperSet()->get('question')->getInputStream(false); + } + if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) { $input->setInteractive(false); } } - if (true === $input->hasParameterOption(array('--quiet', '-q'))) { + switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) { + case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break; + case 1: $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); break; + case 2: $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); break; + case 3: $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); break; + default: $shellVerbosity = 0; break; + } + + if (true === $input->hasParameterOption(array('--quiet', '-q'), true)) { $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + $shellVerbosity = -1; } else { - if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { + if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) { $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); - } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { + $shellVerbosity = 3; + } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); - } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { + $shellVerbosity = 2; + } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + $shellVerbosity = 1; } } + + if (-1 === $shellVerbosity) { + $input->setInteractive(false); + } + + putenv('SHELL_VERBOSITY='.$shellVerbosity); + $_ENV['SHELL_VERBOSITY'] = $shellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity; } /** @@ -824,13 +922,7 @@ class Application * If an event dispatcher has been attached to the application, * events are also dispatched during the life-cycle of the command. * - * @param Command $command A Command instance - * @param InputInterface $input An Input instance - * @param OutputInterface $output An Output instance - * * @return int 0 if everything went fine, or an error code - * - * @throws \Exception when the command being run threw an exception */ protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) { @@ -853,42 +945,56 @@ class Application } $event = new ConsoleCommandEvent($command, $input, $output); - $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event); + $e = null; + + try { + $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event); - if ($event->commandShouldRun()) { - try { + if ($event->commandShouldRun()) { $exitCode = $command->run($input, $output); - } catch (\Exception $e) { - $event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode()); + } else { + $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; + } + } catch (\Exception $e) { + } catch (\Throwable $e) { + } + if (null !== $e) { + if ($this->dispatcher->hasListeners(ConsoleEvents::EXCEPTION)) { + $x = $e instanceof \Exception ? $e : new FatalThrowableError($e); + $event = new ConsoleExceptionEvent($command, $input, $output, $x, $x->getCode()); $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event); - $e = $event->getException(); - - $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode()); - $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); + if ($x !== $event->getException()) { + $e = $event->getException(); + } + } + $event = new ConsoleErrorEvent($input, $output, $e, $command); + $this->dispatcher->dispatch(ConsoleEvents::ERROR, $event); + $e = $event->getError(); - throw $e; + if (0 === $exitCode = $event->getExitCode()) { + $e = null; } - } else { - $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; } $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); + if (null !== $e) { + throw $e; + } + return $event->getExitCode(); } /** * Gets the name of the command based on input. * - * @param InputInterface $input The input interface - * * @return string The command name */ protected function getCommandName(InputInterface $input) { - return $input->getFirstArgument(); + return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument(); } /** @@ -930,63 +1036,12 @@ class Application { return new HelperSet(array( new FormatterHelper(), - new DialogHelper(false), - new ProgressHelper(false), - new TableHelper(false), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper(), )); } - /** - * Runs and parses stty -a if it's available, suppressing any error output. - * - * @return string - */ - private function getSttyColumns() - { - if (!function_exists('proc_open')) { - return; - } - - $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); - $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); - if (is_resource($process)) { - $info = stream_get_contents($pipes[1]); - fclose($pipes[1]); - fclose($pipes[2]); - proc_close($process); - - return $info; - } - } - - /** - * Runs and parses mode CON if it's available, suppressing any error output. - * - * @return string x or null if it could not be parsed - */ - private function getConsoleMode() - { - if (!function_exists('proc_open')) { - return; - } - - $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); - $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); - if (is_resource($process)) { - $info = stream_get_contents($pipes[1]); - fclose($pipes[1]); - fclose($pipes[2]); - proc_close($process); - - if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { - return $matches[2].'x'.$matches[1]; - } - } - } - /** * Returns abbreviated suggestions in string format. * @@ -996,7 +1051,7 @@ class Application */ private function getAbbreviationSuggestions($abbrevs) { - return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); + return ' '.implode("\n ", $abbrevs); } /** @@ -1021,10 +1076,10 @@ class Application * Finds alternative of $name among $collection, * if nothing is found in $collection, try in $abbrevs. * - * @param string $name The string - * @param array|\Traversable $collection The collection + * @param string $name The string + * @param iterable $collection The collection * - * @return array A sorted array of similar string + * @return string[] A sorted array of similar string */ private function findAlternatives($name, $collection) { @@ -1063,7 +1118,7 @@ class Application } $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); - asort($alternatives); + ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE); return array_keys($alternatives); } @@ -1071,20 +1126,23 @@ class Application /** * Sets the default Command name. * - * @param string $commandName The Command name + * @param string $commandName The Command name + * @param bool $isSingleCommand Set to true if there is only one command in this application + * + * @return self */ - public function setDefaultCommand($commandName) + public function setDefaultCommand($commandName, $isSingleCommand = false) { $this->defaultCommand = $commandName; - } - private function stringWidth($string) - { - if (false === $encoding = mb_detect_encoding($string, null, true)) { - return strlen($string); + if ($isSingleCommand) { + // Ensure the command exist + $this->find($commandName); + + $this->singleCommand = true; } - return mb_strwidth($string, $encoding); + return $this; } private function splitStringByWidth($string, $width) @@ -1109,9 +1167,8 @@ class Application $lines[] = str_pad($line, $width); $line = $char; } - if ('' !== $line) { - $lines[] = count($lines) ? str_pad($line, $width) : $line; - } + + $lines[] = count($lines) ? str_pad($line, $width) : $line; mb_convert_variables($encoding, 'utf8', $lines); @@ -1123,7 +1180,7 @@ class Application * * @param string $name The full name of the command * - * @return array The namespaces of the command + * @return string[] The namespaces of the command */ private function extractAllNamespaces($name) { @@ -1141,4 +1198,16 @@ class Application return $namespaces; } + + private function init() + { + if ($this->initialized) { + return; + } + $this->initialized = true; + + foreach ($this->getDefaultCommands() as $command) { + $this->add($command); + } + } } diff --git a/vendor/symfony/console/CHANGELOG.md b/vendor/symfony/console/CHANGELOG.md index 8021068e..946ff1e0 100644 --- a/vendor/symfony/console/CHANGELOG.md +++ b/vendor/symfony/console/CHANGELOG.md @@ -1,6 +1,45 @@ CHANGELOG ========= +3.4.0 +----- + + * added `SHELL_VERBOSITY` env var to control verbosity + * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11 + `ContainerCommandLoader` for commands lazy-loading + * added a case-insensitive command name matching fallback + * added static `Command::$defaultName/getDefaultName()`, allowing for + commands to be registered at compile time in the application command loader. + Setting the `$defaultName` property avoids the need for filling the `command` + attribute on the `console.command` tag when using `AddConsoleCommandPass`. + +3.3.0 +----- + +* added `ExceptionListener` +* added `AddConsoleCommandPass` (originally in FrameworkBundle) +* [BC BREAK] `Input::getOption()` no longer returns the default value for options + with value optional explicitly passed empty +* added console.error event to catch exceptions thrown by other listeners +* deprecated console.exception event in favor of console.error +* added ability to handle `CommandNotFoundException` through the + `console.error` event +* deprecated default validation in `SymfonyQuestionHelper::ask` + +3.2.0 +------ + +* added `setInputs()` method to CommandTester for ease testing of commands expecting inputs +* added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface) +* added StreamableInputInterface +* added LockableTrait + +3.1.0 +----- + + * added truncate method to FormatterHelper + * added setColumnWidth(s) method to Table + 2.8.3 ----- diff --git a/vendor/symfony/console/Command/Command.php b/vendor/symfony/console/Command/Command.php index 6acbe219..06930425 100644 --- a/vendor/symfony/console/Command/Command.php +++ b/vendor/symfony/console/Command/Command.php @@ -11,14 +11,11 @@ namespace Symfony\Component\Console\Command; -use Symfony\Component\Console\Descriptor\TextDescriptor; -use Symfony\Component\Console\Descriptor\XmlDescriptor; use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Application; use Symfony\Component\Console\Helper\HelperSet; @@ -32,11 +29,17 @@ use Symfony\Component\Console\Exception\LogicException; */ class Command { + /** + * @var string|null The default command name + */ + protected static $defaultName; + private $application; private $name; private $processTitle; private $aliases = array(); private $definition; + private $hidden = false; private $help; private $description; private $ignoreValidationErrors = false; @@ -48,8 +51,17 @@ class Command private $helperSet; /** - * Constructor. - * + * @return string|null The default command name or null when no default name is set + */ + public static function getDefaultName() + { + $class = get_called_class(); + $r = new \ReflectionProperty($class, 'defaultName'); + + return $class === $r->class ? static::$defaultName : null; + } + + /** * @param string|null $name The name of the command; passing null means it must be set in configure() * * @throws LogicException When the command name is empty @@ -58,15 +70,11 @@ class Command { $this->definition = new InputDefinition(); - if (null !== $name) { + if (null !== $name || null !== $name = static::getDefaultName()) { $this->setName($name); } $this->configure(); - - if (!$this->name) { - throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this))); - } } /** @@ -79,11 +87,6 @@ class Command $this->ignoreValidationErrors = true; } - /** - * Sets the application instance for this command. - * - * @param Application $application An Application instance - */ public function setApplication(Application $application = null) { $this->application = $application; @@ -94,11 +97,6 @@ class Command } } - /** - * Sets the helper set. - * - * @param HelperSet $helperSet A HelperSet instance - */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; @@ -152,9 +150,6 @@ class Command * execute() method, you set the code to execute by passing * a Closure to the setCode() method. * - * @param InputInterface $input An InputInterface instance - * @param OutputInterface $output An OutputInterface instance - * * @return null|int null or 0 if everything went fine, or an error code * * @throws LogicException When this abstract method is not implemented @@ -172,9 +167,6 @@ class Command * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. - * - * @param InputInterface $input An InputInterface instance - * @param OutputInterface $output An OutputInterface instance */ protected function interact(InputInterface $input, OutputInterface $output) { @@ -185,9 +177,6 @@ class Command * * This is mainly useful when a lot of commands extends one main command * where some things need to be initialized based on the input arguments and options. - * - * @param InputInterface $input An InputInterface instance - * @param OutputInterface $output An OutputInterface instance */ protected function initialize(InputInterface $input, OutputInterface $output) { @@ -200,12 +189,9 @@ class Command * setCode() method or by overriding the execute() method * in a sub-class. * - * @param InputInterface $input An InputInterface instance - * @param OutputInterface $output An OutputInterface instance - * * @return int The command exit code * - * @throws \Exception + * @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}. * * @see setCode() * @see execute() @@ -232,7 +218,14 @@ class Command if (null !== $this->processTitle) { if (function_exists('cli_set_process_title')) { - cli_set_process_title($this->processTitle); + if (false === @cli_set_process_title($this->processTitle)) { + if ('Darwin' === PHP_OS) { + $output->writeln('Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.'); + } else { + $error = error_get_last(); + trigger_error($error['message'], E_USER_WARNING); + } + } } elseif (function_exists('setproctitle')) { setproctitle($this->processTitle); } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { @@ -270,22 +263,26 @@ class Command * * @param callable $code A callable(InputInterface $input, OutputInterface $output) * - * @return Command The current instance + * @return $this * * @throws InvalidArgumentException * * @see execute() */ - public function setCode($code) + public function setCode(callable $code) { - if (!is_callable($code)) { - throw new InvalidArgumentException('Invalid callable provided to Command::setCode.'); - } - - if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) { + if ($code instanceof \Closure) { $r = new \ReflectionFunction($code); if (null === $r->getClosureThis()) { - $code = \Closure::bind($code, $this); + if (\PHP_VERSION_ID < 70000) { + // Bug in PHP5: https://bugs.php.net/bug.php?id=64761 + // This means that we cannot bind static closures and therefore we must + // ignore any errors here. There is no way to test if the closure is + // bindable. + $code = @\Closure::bind($code, $this); + } else { + $code = \Closure::bind($code, $this); + } } } @@ -326,7 +323,7 @@ class Command * * @param array|InputDefinition $definition An array of argument and option instances or a definition instance * - * @return Command The current instance + * @return $this */ public function setDefinition($definition) { @@ -352,7 +349,7 @@ class Command } /** - * Gets the InputDefinition to be used to create XML and Text representations of this Command. + * Gets the InputDefinition to be used to create representations of this Command. * * Can be overridden to provide the original command representation when it would otherwise * be changed by merging with the application InputDefinition. @@ -374,7 +371,7 @@ class Command * @param string $description A description text * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) * - * @return Command The current instance + * @return $this */ public function addArgument($name, $mode = null, $description = '', $default = null) { @@ -392,7 +389,7 @@ class Command * @param string $description A description text * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) * - * @return Command The current instance + * @return $this */ public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) { @@ -411,7 +408,7 @@ class Command * * @param string $name The command name * - * @return Command The current instance + * @return $this * * @throws InvalidArgumentException When the name is invalid */ @@ -434,7 +431,7 @@ class Command * * @param string $title The process title * - * @return Command The current instance + * @return $this */ public function setProcessTitle($title) { @@ -453,12 +450,32 @@ class Command return $this->name; } + /** + * @param bool $hidden Whether or not the command should be hidden from the list of commands + * + * @return Command The current instance + */ + public function setHidden($hidden) + { + $this->hidden = (bool) $hidden; + + return $this; + } + + /** + * @return bool whether the command should be publicly shown or not + */ + public function isHidden() + { + return $this->hidden; + } + /** * Sets the description for the command. * * @param string $description The description for the command * - * @return Command The current instance + * @return $this */ public function setDescription($description) { @@ -482,7 +499,7 @@ class Command * * @param string $help The help for the command * - * @return Command The current instance + * @return $this */ public function setHelp($help) { @@ -528,7 +545,7 @@ class Command * * @param string[] $aliases An array of aliases for the command * - * @return Command The current instance + * @return $this * * @throws InvalidArgumentException When an alias is invalid */ @@ -579,6 +596,8 @@ class Command * Add a command usage example. * * @param string $usage The usage, it'll be prefixed with the command name + * + * @return $this */ public function addUsage($usage) { @@ -620,49 +639,6 @@ class Command return $this->helperSet->get($name); } - /** - * Returns a text representation of the command. - * - * @return string A string representing the command - * - * @deprecated since version 2.3, to be removed in 3.0. - */ - public function asText() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); - - $descriptor = new TextDescriptor(); - $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); - $descriptor->describe($output, $this, array('raw_output' => true)); - - return $output->fetch(); - } - - /** - * Returns an XML representation of the command. - * - * @param bool $asDom Whether to return a DOM or an XML string - * - * @return string|\DOMDocument An XML string representing the command - * - * @deprecated since version 2.3, to be removed in 3.0. - */ - public function asXml($asDom = false) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); - - $descriptor = new XmlDescriptor(); - - if ($asDom) { - return $descriptor->getCommandDocument($this); - } - - $output = new BufferedOutput(); - $descriptor->describe($output, $this); - - return $output->fetch(); - } - /** * Validates a command name. * diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php index c0e7b388..112679b3 100644 --- a/vendor/symfony/console/Command/HelpCommand.php +++ b/vendor/symfony/console/Command/HelpCommand.php @@ -37,7 +37,6 @@ class HelpCommand extends Command ->setName('help') ->setDefinition(array( new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), - new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), )) @@ -57,11 +56,6 @@ EOF ; } - /** - * Sets the command. - * - * @param Command $command The command to set - */ public function setCommand(Command $command) { $this->command = $command; @@ -76,12 +70,6 @@ EOF $this->command = $this->getApplication()->find($input->getArgument('command_name')); } - if ($input->getOption('xml')) { - @trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED); - - $input->setOption('format', 'xml'); - } - $helper = new DescriptorHelper(); $helper->describe($output, $this->command, array( 'format' => $input->getOption('format'), diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php index 5e1b926a..179ddea5 100644 --- a/vendor/symfony/console/Command/ListCommand.php +++ b/vendor/symfony/console/Command/ListCommand.php @@ -68,12 +68,6 @@ EOF */ protected function execute(InputInterface $input, OutputInterface $output) { - if ($input->getOption('xml')) { - @trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED); - - $input->setOption('format', 'xml'); - } - $helper = new DescriptorHelper(); $helper->describe($output, $this->getApplication(), array( 'format' => $input->getOption('format'), @@ -89,7 +83,6 @@ EOF { return new InputDefinition(array( new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), - new InputOption('xml', null, InputOption::VALUE_NONE, 'To output list as XML'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), )); diff --git a/vendor/symfony/console/Command/LockableTrait.php b/vendor/symfony/console/Command/LockableTrait.php new file mode 100644 index 00000000..308ebf28 --- /dev/null +++ b/vendor/symfony/console/Command/LockableTrait.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Lock\Factory; +use Symfony\Component\Lock\Lock; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Lock\Store\SemaphoreStore; + +/** + * Basic lock feature for commands. + * + * @author Geoffrey Brier + */ +trait LockableTrait +{ + /** @var Lock */ + private $lock; + + /** + * Locks a command. + * + * @return bool + */ + private function lock($name = null, $blocking = false) + { + if (!class_exists(SemaphoreStore::class)) { + throw new RuntimeException('To enable the locking feature you must install the symfony/lock component.'); + } + + if (null !== $this->lock) { + throw new LogicException('A lock is already in place.'); + } + + if (SemaphoreStore::isSupported($blocking)) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(); + } + + $this->lock = (new Factory($store))->createLock($name ?: $this->getName()); + if (!$this->lock->acquire($blocking)) { + $this->lock = null; + + return false; + } + + return true; + } + + /** + * Releases the command lock if there is one. + */ + private function release() + { + if ($this->lock) { + $this->lock->release(); + $this->lock = null; + } + } +} diff --git a/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php new file mode 100644 index 00000000..9462996f --- /dev/null +++ b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php @@ -0,0 +1,37 @@ + + */ +interface CommandLoaderInterface +{ + /** + * Loads a command. + * + * @param string $name + * + * @return Command + * + * @throws CommandNotFoundException + */ + public function get($name); + + /** + * Checks if a command exists. + * + * @param string $name + * + * @return bool + */ + public function has($name); + + /** + * @return string[] All registered command names + */ + public function getNames(); +} diff --git a/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php new file mode 100644 index 00000000..753ad0fb --- /dev/null +++ b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php @@ -0,0 +1,55 @@ + + */ +class ContainerCommandLoader implements CommandLoaderInterface +{ + private $container; + private $commandMap; + + /** + * @param ContainerInterface $container A container from which to load command services + * @param array $commandMap An array with command names as keys and service ids as values + */ + public function __construct(ContainerInterface $container, array $commandMap) + { + $this->container = $container; + $this->commandMap = $commandMap; + } + + /** + * {@inheritdoc} + */ + public function get($name) + { + if (!$this->has($name)) { + throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + } + + return $this->container->get($this->commandMap[$name]); + } + + /** + * {@inheritdoc} + */ + public function has($name) + { + return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]); + } + + /** + * {@inheritdoc} + */ + public function getNames() + { + return array_keys($this->commandMap); + } +} diff --git a/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php new file mode 100644 index 00000000..d9c20557 --- /dev/null +++ b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\CommandLoader; + +use Symfony\Component\Console\Exception\CommandNotFoundException; + +/** + * A simple command loader using factories to instantiate commands lazily. + * + * @author Maxime Steinhausser + */ +class FactoryCommandLoader implements CommandLoaderInterface +{ + private $factories; + + /** + * @param callable[] $factories Indexed by command names + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + */ + public function has($name) + { + return isset($this->factories[$name]); + } + + /** + * {@inheritdoc} + */ + public function get($name) + { + if (!isset($this->factories[$name])) { + throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + } + + $factory = $this->factories[$name]; + + return $factory(); + } + + /** + * {@inheritdoc} + */ + public function getNames() + { + return array_keys($this->factories); + } +} diff --git a/vendor/symfony/console/ConsoleEvents.php b/vendor/symfony/console/ConsoleEvents.php index 1ed41b7d..bf6cab9a 100644 --- a/vendor/symfony/console/ConsoleEvents.php +++ b/vendor/symfony/console/ConsoleEvents.php @@ -23,12 +23,7 @@ final class ConsoleEvents * executed by the console. It also allows you to modify the command, input and output * before they are handled to the command. * - * The event listener method receives a Symfony\Component\Console\Event\ConsoleCommandEvent - * instance. - * - * @Event - * - * @var string + * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent") */ const COMMAND = 'console.command'; @@ -36,26 +31,30 @@ final class ConsoleEvents * The TERMINATE event allows you to attach listeners after a command is * executed by the console. * - * The event listener method receives a Symfony\Component\Console\Event\ConsoleTerminateEvent - * instance. - * - * @Event - * - * @var string + * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent") */ const TERMINATE = 'console.terminate'; /** - * The EXCEPTION event occurs when an uncaught exception appears. + * The EXCEPTION event occurs when an uncaught exception appears + * while executing Command#run(). * * This event allows you to deal with the exception or - * to modify the thrown exception. The event listener method receives - * a Symfony\Component\Console\Event\ConsoleExceptionEvent - * instance. + * to modify the thrown exception. * - * @Event + * @Event("Symfony\Component\Console\Event\ConsoleExceptionEvent") * - * @var string + * @deprecated The console.exception event is deprecated since version 3.3 and will be removed in 4.0. Use the console.error event instead. */ const EXCEPTION = 'console.exception'; + + /** + * The ERROR event occurs when an uncaught exception or error appears. + * + * This event allows you to deal with the exception/error or + * to modify the thrown exception. + * + * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent") + */ + const ERROR = 'console.error'; } diff --git a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php new file mode 100644 index 00000000..39d53ef8 --- /dev/null +++ b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\DependencyInjection; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\TypedReference; + +/** + * Registers console commands. + * + * @author Grégoire Pineau + */ +class AddConsoleCommandPass implements CompilerPassInterface +{ + private $commandLoaderServiceId; + private $commandTag; + + public function __construct($commandLoaderServiceId = 'console.command_loader', $commandTag = 'console.command') + { + $this->commandLoaderServiceId = $commandLoaderServiceId; + $this->commandTag = $commandTag; + } + + public function process(ContainerBuilder $container) + { + $commandServices = $container->findTaggedServiceIds($this->commandTag, true); + $lazyCommandMap = array(); + $lazyCommandRefs = array(); + $serviceIds = array(); + $lazyServiceIds = array(); + + foreach ($commandServices as $id => $tags) { + $definition = $container->getDefinition($id); + $class = $container->getParameterBag()->resolveValue($definition->getClass()); + + $commandId = 'console.command.'.strtolower(str_replace('\\', '_', $class)); + + if (isset($tags[0]['command'])) { + $commandName = $tags[0]['command']; + } else { + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class)); + } + $commandName = $class::getDefaultName(); + } + + if (null === $commandName) { + if (isset($serviceIds[$commandId]) || $container->hasAlias($commandId)) { + $commandId = $commandId.'_'.$id; + } + if (!$definition->isPublic() || $definition->isPrivate()) { + $container->setAlias($commandId, $id)->setPublic(true); + $id = $commandId; + } + $serviceIds[$commandId] = $id; + + continue; + } + + $serviceIds[$commandId] = $id; + $lazyServiceIds[$id] = true; + unset($tags[0]); + $lazyCommandMap[$commandName] = $id; + $lazyCommandRefs[$id] = new TypedReference($id, $class); + $aliases = array(); + + foreach ($tags as $tag) { + if (isset($tag['command'])) { + $aliases[] = $tag['command']; + $lazyCommandMap[$tag['command']] = $id; + } + } + + $definition->addMethodCall('setName', array($commandName)); + + if ($aliases) { + $definition->addMethodCall('setAliases', array($aliases)); + } + } + + $container + ->register($this->commandLoaderServiceId, ContainerCommandLoader::class) + ->setPublic(true) + ->setArguments(array(ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap)); + + $container->setParameter('console.command.ids', $serviceIds); + $container->setParameter('console.lazy_command.ids', $lazyServiceIds); + } +} diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php index 89961b9c..ef4c673b 100644 --- a/vendor/symfony/console/Descriptor/ApplicationDescription.php +++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -24,15 +24,9 @@ class ApplicationDescription { const GLOBAL_NAMESPACE = '_global'; - /** - * @var Application - */ private $application; - - /** - * @var null|string - */ private $namespace; + private $showHidden; /** * @var array @@ -50,15 +44,15 @@ class ApplicationDescription private $aliases; /** - * Constructor. - * * @param Application $application * @param string|null $namespace + * @param bool $showHidden */ - public function __construct(Application $application, $namespace = null) + public function __construct(Application $application, $namespace = null, $showHidden = false) { $this->application = $application; $this->namespace = $namespace; + $this->showHidden = $showHidden; } /** @@ -112,7 +106,7 @@ class ApplicationDescription /** @var Command $command */ foreach ($commands as $name => $command) { - if (!$command->getName()) { + if (!$command->getName() || (!$this->showHidden && $command->isHidden())) { continue; } @@ -130,8 +124,6 @@ class ApplicationDescription } /** - * @param array $commands - * * @return array */ private function sortCommands(array $commands) diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php index 43a7a0a1..fe169cb4 100644 --- a/vendor/symfony/console/Descriptor/Descriptor.php +++ b/vendor/symfony/console/Descriptor/Descriptor.php @@ -29,7 +29,7 @@ abstract class Descriptor implements DescriptorInterface /** * @var OutputInterface */ - private $output; + protected $output; /** * {@inheritdoc} @@ -73,9 +73,6 @@ abstract class Descriptor implements DescriptorInterface /** * Describes an InputArgument instance. * - * @param InputArgument $argument - * @param array $options - * * @return string|mixed */ abstract protected function describeInputArgument(InputArgument $argument, array $options = array()); @@ -83,9 +80,6 @@ abstract class Descriptor implements DescriptorInterface /** * Describes an InputOption instance. * - * @param InputOption $option - * @param array $options - * * @return string|mixed */ abstract protected function describeInputOption(InputOption $option, array $options = array()); @@ -93,9 +87,6 @@ abstract class Descriptor implements DescriptorInterface /** * Describes an InputDefinition instance. * - * @param InputDefinition $definition - * @param array $options - * * @return string|mixed */ abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array()); @@ -103,9 +94,6 @@ abstract class Descriptor implements DescriptorInterface /** * Describes a Command instance. * - * @param Command $command - * @param array $options - * * @return string|mixed */ abstract protected function describeCommand(Command $command, array $options = array()); @@ -113,9 +101,6 @@ abstract class Descriptor implements DescriptorInterface /** * Describes an Application instance. * - * @param Application $application - * @param array $options - * * @return string|mixed */ abstract protected function describeApplication(Application $application, array $options = array()); diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php index 87e38fdb..35c87c22 100644 --- a/vendor/symfony/console/Descriptor/JsonDescriptor.php +++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php @@ -64,16 +64,28 @@ class JsonDescriptor extends Descriptor protected function describeApplication(Application $application, array $options = array()) { $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; - $description = new ApplicationDescription($application, $describedNamespace); + $description = new ApplicationDescription($application, $describedNamespace, true); $commands = array(); foreach ($description->getCommands() as $command) { $commands[] = $this->getCommandData($command); } - $data = $describedNamespace - ? array('commands' => $commands, 'namespace' => $describedNamespace) - : array('commands' => $commands, 'namespaces' => array_values($description->getNamespaces())); + $data = array(); + if ('UNKNOWN' !== $application->getName()) { + $data['application']['name'] = $application->getName(); + if ('UNKNOWN' !== $application->getVersion()) { + $data['application']['version'] = $application->getVersion(); + } + } + + $data['commands'] = $commands; + + if ($describedNamespace) { + $data['namespace'] = $describedNamespace; + } else { + $data['namespaces'] = array_values($description->getNamespaces()); + } $this->writeData($data, $options); } @@ -81,9 +93,6 @@ class JsonDescriptor extends Descriptor /** * Writes data as json. * - * @param array $data - * @param array $options - * * @return array|string */ private function writeData(array $data, array $options) @@ -92,8 +101,6 @@ class JsonDescriptor extends Descriptor } /** - * @param InputArgument $argument - * * @return array */ private function getInputArgumentData(InputArgument $argument) @@ -103,13 +110,11 @@ class JsonDescriptor extends Descriptor 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()), - 'default' => $argument->getDefault(), + 'default' => INF === $argument->getDefault() ? 'INF' : $argument->getDefault(), ); } /** - * @param InputOption $option - * * @return array */ private function getInputOptionData(InputOption $option) @@ -121,13 +126,11 @@ class JsonDescriptor extends Descriptor 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()), - 'default' => $option->getDefault(), + 'default' => INF === $option->getDefault() ? 'INF' : $option->getDefault(), ); } /** - * @param InputDefinition $definition - * * @return array */ private function getInputDefinitionData(InputDefinition $definition) @@ -146,8 +149,6 @@ class JsonDescriptor extends Descriptor } /** - * @param Command $command - * * @return array */ private function getCommandData(Command $command) @@ -161,6 +162,7 @@ class JsonDescriptor extends Descriptor 'description' => $command->getDescription(), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()), + 'hidden' => $command->isHidden(), ); } } diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php index d3d76a42..106bff51 100644 --- a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php +++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php @@ -13,9 +13,11 @@ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; /** * Markdown descriptor. @@ -26,17 +28,37 @@ use Symfony\Component\Console\Input\InputOption; */ class MarkdownDescriptor extends Descriptor { + /** + * {@inheritdoc} + */ + public function describe(OutputInterface $output, $object, array $options = array()) + { + $decorated = $output->isDecorated(); + $output->setDecorated(false); + + parent::describe($output, $object, $options); + + $output->setDecorated($decorated); + } + + /** + * {@inheritdoc} + */ + protected function write($content, $decorated = true) + { + parent::write($content, $decorated); + } + /** * {@inheritdoc} */ protected function describeInputArgument(InputArgument $argument, array $options = array()) { $this->write( - '**'.$argument->getName().':**'."\n\n" - .'* Name: '.($argument->getName() ?: '')."\n" + '#### `'.($argument->getName() ?: '')."`\n\n" + .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n" .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n" - .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n ", $argument->getDescription() ?: '')."\n" .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`' ); } @@ -46,14 +68,17 @@ class MarkdownDescriptor extends Descriptor */ protected function describeInputOption(InputOption $option, array $options = array()) { + $name = '--'.$option->getName(); + if ($option->getShortcut()) { + $name .= '|-'.implode('|-', explode('|', $option->getShortcut())).''; + } + $this->write( - '**'.$option->getName().':**'."\n\n" - .'* Name: `--'.$option->getName().'`'."\n" - .'* Shortcut: '.($option->getShortcut() ? '`-'.implode('|-', explode('|', $option->getShortcut())).'`' : '')."\n" + '#### `'.$name.'`'."\n\n" + .($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '') .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n" .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n" .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n" - .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n ", $option->getDescription() ?: '')."\n" .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`' ); } @@ -64,7 +89,7 @@ class MarkdownDescriptor extends Descriptor protected function describeInputDefinition(InputDefinition $definition, array $options = array()) { if ($showArguments = count($definition->getArguments()) > 0) { - $this->write('### Arguments:'); + $this->write('### Arguments'); foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); $this->write($this->describeInputArgument($argument)); @@ -76,7 +101,7 @@ class MarkdownDescriptor extends Descriptor $this->write("\n\n"); } - $this->write('### Options:'); + $this->write('### Options'); foreach ($definition->getOptions() as $option) { $this->write("\n\n"); $this->write($this->describeInputOption($option)); @@ -93,12 +118,12 @@ class MarkdownDescriptor extends Descriptor $command->mergeApplicationDefinition(false); $this->write( - $command->getName()."\n" - .str_repeat('-', strlen($command->getName()))."\n\n" - .'* Description: '.($command->getDescription() ?: '')."\n" - .'* Usage:'."\n\n" + '`'.$command->getName()."`\n" + .str_repeat('-', Helper::strlen($command->getName()) + 2)."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + .'### Usage'."\n\n" .array_reduce(array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()), function ($carry, $usage) { - return $carry .= ' * `'.$usage.'`'."\n"; + return $carry.'* `'.$usage.'`'."\n"; }) ); @@ -120,8 +145,9 @@ class MarkdownDescriptor extends Descriptor { $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; $description = new ApplicationDescription($application, $describedNamespace); + $title = $this->getApplicationTitle($application); - $this->write($application->getName()."\n".str_repeat('=', strlen($application->getName()))); + $this->write($title."\n".str_repeat('=', Helper::strlen($title))); foreach ($description->getNamespaces() as $namespace) { if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { @@ -130,8 +156,8 @@ class MarkdownDescriptor extends Descriptor } $this->write("\n\n"); - $this->write(implode("\n", array_map(function ($commandName) { - return '* '.$commandName; + $this->write(implode("\n", array_map(function ($commandName) use ($description) { + return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())); }, $namespace['commands']))); } @@ -140,4 +166,17 @@ class MarkdownDescriptor extends Descriptor $this->write($this->describeCommand($command)); } } + + private function getApplicationTitle(Application $application) + { + if ('UNKNOWN' !== $application->getName()) { + if ('UNKNOWN' !== $application->getVersion()) { + return sprintf('%s %s', $application->getName(), $application->getVersion()); + } + + return $application->getName(); + } + + return 'Console Tool'; + } } diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php index 64b53971..a79df7e2 100644 --- a/vendor/symfony/console/Descriptor/TextDescriptor.php +++ b/vendor/symfony/console/Descriptor/TextDescriptor.php @@ -13,6 +13,8 @@ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; @@ -37,14 +39,14 @@ class TextDescriptor extends Descriptor $default = ''; } - $totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName()); - $spacingWidth = $totalWidth - strlen($argument->getName()) + 2; + $totalWidth = isset($options['total_width']) ? $options['total_width'] : Helper::strlen($argument->getName()); + $spacingWidth = $totalWidth - strlen($argument->getName()); - $this->writeText(sprintf(' %s%s%s%s', + $this->writeText(sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), - // + 17 = 2 spaces + + + 2 spaces - preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $argument->getDescription()), + // + 4 = 2 spaces before , 2 spaces after + preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()), $default ), $options); } @@ -75,13 +77,13 @@ class TextDescriptor extends Descriptor sprintf('--%s%s', $option->getName(), $value) ); - $spacingWidth = $totalWidth - strlen($synopsis) + 2; + $spacingWidth = $totalWidth - Helper::strlen($synopsis); - $this->writeText(sprintf(' %s%s%s%s%s', + $this->writeText(sprintf(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), - // + 17 = 2 spaces + + + 2 spaces - preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $option->getDescription()), + // + 4 = 2 spaces before , 2 spaces after + preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()), $default, $option->isArray() ? ' (multiple values allowed)' : '' ), $options); @@ -94,7 +96,7 @@ class TextDescriptor extends Descriptor { $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); foreach ($definition->getArguments() as $argument) { - $totalWidth = max($totalWidth, strlen($argument->getName())); + $totalWidth = max($totalWidth, Helper::strlen($argument->getName())); } if ($definition->getArguments()) { @@ -141,7 +143,7 @@ class TextDescriptor extends Descriptor $this->writeText('Usage:', $options); foreach (array_merge(array($command->getSynopsis(true)), $command->getAliases(), $command->getUsages()) as $usage) { $this->writeText("\n"); - $this->writeText(' '.$usage, $options); + $this->writeText(' '.OutputFormatter::escape($usage), $options); } $this->writeText("\n"); @@ -156,7 +158,7 @@ class TextDescriptor extends Descriptor $this->writeText("\n"); $this->writeText('Help:', $options); $this->writeText("\n"); - $this->writeText(' '.str_replace("\n", "\n ", $help), $options); + $this->writeText(' '.str_replace("\n", "\n ", $help), $options); $this->writeText("\n"); } } @@ -189,7 +191,20 @@ class TextDescriptor extends Descriptor $this->writeText("\n"); $this->writeText("\n"); - $width = $this->getColumnWidth($description->getCommands()); + $commands = $description->getCommands(); + $namespaces = $description->getNamespaces(); + if ($describedNamespace && $namespaces) { + // make sure all alias commands are included when describing a specific namespace + $describedNamespaceInfo = reset($namespaces); + foreach ($describedNamespaceInfo['commands'] as $name) { + $commands[$name] = $description->getCommand($name); + } + } + + // calculate max. width based on available commands per namespace + $width = $this->getColumnWidth(call_user_func_array('array_merge', array_map(function ($namespace) use ($commands) { + return array_intersect($namespace['commands'], array_keys($commands)); + }, $namespaces))); if ($describedNamespace) { $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); @@ -197,8 +212,15 @@ class TextDescriptor extends Descriptor $this->writeText('Available commands:', $options); } - // add commands by namespace - foreach ($description->getNamespaces() as $namespace) { + foreach ($namespaces as $namespace) { + $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) { + return isset($commands[$name]); + }); + + if (!$namespace['commands']) { + continue; + } + if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { $this->writeText("\n"); $this->writeText(' '.$namespace['id'].'', $options); @@ -206,8 +228,10 @@ class TextDescriptor extends Descriptor foreach ($namespace['commands'] as $name) { $this->writeText("\n"); - $spacingWidth = $width - strlen($name); - $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options); + $spacingWidth = $width - Helper::strlen($name); + $command = $commands[$name]; + $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; + $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); } } @@ -226,6 +250,23 @@ class TextDescriptor extends Descriptor ); } + /** + * Formats command aliases to show them in the command description. + * + * @return string + */ + private function getCommandAliasesText(Command $command) + { + $text = ''; + $aliases = $command->getAliases(); + + if ($aliases) { + $text = '['.implode('|', $aliases).'] '; + } + + return $text; + } + /** * Formats input option/argument default value. * @@ -235,15 +276,25 @@ class TextDescriptor extends Descriptor */ private function formatDefaultValue($default) { - if (PHP_VERSION_ID < 50400) { - return str_replace(array('\/', '\\\\'), array('/', '\\'), json_encode($default)); + if (INF === $default) { + return 'INF'; + } + + if (is_string($default)) { + $default = OutputFormatter::escape($default); + } elseif (is_array($default)) { + foreach ($default as $key => $value) { + if (is_string($value)) { + $default[$key] = OutputFormatter::escape($value); + } + } } return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } /** - * @param Command[] $commands + * @param (Command|string)[] $commands * * @return int */ @@ -252,13 +303,17 @@ class TextDescriptor extends Descriptor $widths = array(); foreach ($commands as $command) { - $widths[] = strlen($command->getName()); - foreach ($command->getAliases() as $alias) { - $widths[] = strlen($alias); + if ($command instanceof Command) { + $widths[] = Helper::strlen($command->getName()); + foreach ($command->getAliases() as $alias) { + $widths[] = Helper::strlen($alias); + } + } else { + $widths[] = Helper::strlen($command); } } - return max($widths) + 2; + return $widths ? max($widths) + 2 : 0; } /** @@ -266,15 +321,15 @@ class TextDescriptor extends Descriptor * * @return int */ - private function calculateTotalWidthForOptions($options) + private function calculateTotalWidthForOptions(array $options) { $totalWidth = 0; foreach ($options as $option) { // "-" + shortcut + ", --" + name - $nameLength = 1 + max(strlen($option->getShortcut()), 1) + 4 + strlen($option->getName()); + $nameLength = 1 + max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName()); if ($option->acceptValue()) { - $valueLength = 1 + strlen($option->getName()); // = + value + $valueLength = 1 + Helper::strlen($option->getName()); // = + value $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ] $nameLength += $valueLength; diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php index b5676beb..f05756ca 100644 --- a/vendor/symfony/console/Descriptor/XmlDescriptor.php +++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -27,8 +27,6 @@ use Symfony\Component\Console\Input\InputOption; class XmlDescriptor extends Descriptor { /** - * @param InputDefinition $definition - * * @return \DOMDocument */ public function getInputDefinitionDocument(InputDefinition $definition) @@ -50,8 +48,6 @@ class XmlDescriptor extends Descriptor } /** - * @param Command $command - * * @return \DOMDocument */ public function getCommandDocument(Command $command) @@ -64,6 +60,7 @@ class XmlDescriptor extends Descriptor $commandXML->setAttribute('id', $command->getName()); $commandXML->setAttribute('name', $command->getName()); + $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); $commandXML->appendChild($usagesXML = $dom->createElement('usages')); @@ -94,16 +91,16 @@ class XmlDescriptor extends Descriptor $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($rootXml = $dom->createElement('symfony')); - if ($application->getName() !== 'UNKNOWN') { + if ('UNKNOWN' !== $application->getName()) { $rootXml->setAttribute('name', $application->getName()); - if ($application->getVersion() !== 'UNKNOWN') { + if ('UNKNOWN' !== $application->getVersion()) { $rootXml->setAttribute('version', $application->getVersion()); } } $rootXml->appendChild($commandsXML = $dom->createElement('commands')); - $description = new ApplicationDescription($application, $namespace); + $description = new ApplicationDescription($application, $namespace, true); if ($namespace) { $commandsXML->setAttribute('namespace', $namespace); @@ -172,9 +169,6 @@ class XmlDescriptor extends Descriptor /** * Appends document children to parent node. - * - * @param \DOMNode $parentNode - * @param \DOMNode $importedParent */ private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) { @@ -186,8 +180,6 @@ class XmlDescriptor extends Descriptor /** * Writes DOM document. * - * @param \DOMDocument $dom - * * @return \DOMDocument|string */ private function writeDocument(\DOMDocument $dom) @@ -197,8 +189,6 @@ class XmlDescriptor extends Descriptor } /** - * @param InputArgument $argument - * * @return \DOMDocument */ private function getInputArgumentDocument(InputArgument $argument) @@ -223,8 +213,6 @@ class XmlDescriptor extends Descriptor } /** - * @param InputOption $option - * * @return \DOMDocument */ private function getInputOptionDocument(InputOption $option) diff --git a/vendor/symfony/console/Event/ConsoleCommandEvent.php b/vendor/symfony/console/Event/ConsoleCommandEvent.php index 92adf1ef..2f517c1d 100644 --- a/vendor/symfony/console/Event/ConsoleCommandEvent.php +++ b/vendor/symfony/console/Event/ConsoleCommandEvent.php @@ -25,8 +25,6 @@ class ConsoleCommandEvent extends ConsoleEvent /** * Indicates if the command should be run or skipped. - * - * @var bool */ private $commandShouldRun = true; diff --git a/vendor/symfony/console/Event/ConsoleErrorEvent.php b/vendor/symfony/console/Event/ConsoleErrorEvent.php new file mode 100644 index 00000000..0d05b9da --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleErrorEvent.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Allows to handle throwables thrown while running a command. + * + * @author Wouter de Jong + */ +final class ConsoleErrorEvent extends ConsoleEvent +{ + private $error; + private $exitCode; + + public function __construct(InputInterface $input, OutputInterface $output, $error, Command $command = null) + { + parent::__construct($command, $input, $output); + + $this->setError($error); + } + + /** + * Returns the thrown error/exception. + * + * @return \Throwable + */ + public function getError() + { + return $this->error; + } + + /** + * Replaces the thrown error/exception. + * + * @param \Throwable $error + */ + public function setError($error) + { + if (!$error instanceof \Throwable && !$error instanceof \Exception) { + throw new InvalidArgumentException(sprintf('The error passed to ConsoleErrorEvent must be an instance of \Throwable or \Exception, "%s" was passed instead.', is_object($error) ? get_class($error) : gettype($error))); + } + + $this->error = $error; + } + + /** + * Sets the exit code. + * + * @param int $exitCode The command exit code + */ + public function setExitCode($exitCode) + { + $this->exitCode = (int) $exitCode; + + $r = new \ReflectionProperty($this->error, 'code'); + $r->setAccessible(true); + $r->setValue($this->error, $this->exitCode); + } + + /** + * Gets the exit code. + * + * @return int The command exit code + */ + public function getExitCode() + { + return null !== $this->exitCode ? $this->exitCode : (is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1); + } +} diff --git a/vendor/symfony/console/Event/ConsoleEvent.php b/vendor/symfony/console/Event/ConsoleEvent.php index ab620c46..5440da21 100644 --- a/vendor/symfony/console/Event/ConsoleEvent.php +++ b/vendor/symfony/console/Event/ConsoleEvent.php @@ -28,7 +28,7 @@ class ConsoleEvent extends Event private $input; private $output; - public function __construct(Command $command, InputInterface $input, OutputInterface $output) + public function __construct(Command $command = null, InputInterface $input, OutputInterface $output) { $this->command = $command; $this->input = $input; @@ -38,7 +38,7 @@ class ConsoleEvent extends Event /** * Gets the command that is executed. * - * @return Command A Command instance + * @return Command|null A Command instance */ public function getCommand() { diff --git a/vendor/symfony/console/Event/ConsoleExceptionEvent.php b/vendor/symfony/console/Event/ConsoleExceptionEvent.php index 603b7eed..a31797fa 100644 --- a/vendor/symfony/console/Event/ConsoleExceptionEvent.php +++ b/vendor/symfony/console/Event/ConsoleExceptionEvent.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Console\Event; +@trigger_error(sprintf('The "%s" class is deprecated since version 3.3 and will be removed in 4.0. Use the ConsoleErrorEvent instead.', ConsoleExceptionEvent::class), E_USER_DEPRECATED); + use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -19,6 +21,8 @@ use Symfony\Component\Console\Output\OutputInterface; * Allows to handle exception thrown in a command. * * @author Fabien Potencier + * + * @deprecated since version 3.3, to be removed in 4.0. Use ConsoleErrorEvent instead. */ class ConsoleExceptionEvent extends ConsoleEvent { diff --git a/vendor/symfony/console/EventListener/ErrorListener.php b/vendor/symfony/console/EventListener/ErrorListener.php new file mode 100644 index 00000000..3774f9e6 --- /dev/null +++ b/vendor/symfony/console/EventListener/ErrorListener.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\ConsoleEvents; +use Symfony\Component\Console\Event\ConsoleErrorEvent; +use Symfony\Component\Console\Event\ConsoleEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * @author James Halsall + * @author Robin Chalas + */ +class ErrorListener implements EventSubscriberInterface +{ + private $logger; + + public function __construct(LoggerInterface $logger = null) + { + $this->logger = $logger; + } + + public function onConsoleError(ConsoleErrorEvent $event) + { + if (null === $this->logger) { + return; + } + + $error = $event->getError(); + + if (!$inputString = $this->getInputString($event)) { + return $this->logger->error('An error occurred while using the console. Message: "{message}"', array('error' => $error, 'message' => $error->getMessage())); + } + + $this->logger->error('Error thrown while running command "{command}". Message: "{message}"', array('error' => $error, 'command' => $inputString, 'message' => $error->getMessage())); + } + + public function onConsoleTerminate(ConsoleTerminateEvent $event) + { + if (null === $this->logger) { + return; + } + + $exitCode = $event->getExitCode(); + + if (0 === $exitCode) { + return; + } + + if (!$inputString = $this->getInputString($event)) { + return $this->logger->debug('The console exited with code "{code}"', array('code' => $exitCode)); + } + + $this->logger->debug('Command "{command}" exited with code "{code}"', array('command' => $inputString, 'code' => $exitCode)); + } + + public static function getSubscribedEvents() + { + return array( + ConsoleEvents::ERROR => array('onConsoleError', -128), + ConsoleEvents::TERMINATE => array('onConsoleTerminate', -128), + ); + } + + private static function getInputString(ConsoleEvent $event) + { + $commandName = $event->getCommand() ? $event->getCommand()->getName() : null; + $input = $event->getInput(); + + if (method_exists($input, '__toString')) { + if ($commandName) { + return str_replace(array("'$commandName'", "\"$commandName\""), $commandName, (string) $input); + } + + return (string) $input; + } + + return $commandName; + } +} diff --git a/vendor/symfony/console/Exception/CommandNotFoundException.php b/vendor/symfony/console/Exception/CommandNotFoundException.php index ce6fefe3..cb7d1131 100644 --- a/vendor/symfony/console/Exception/CommandNotFoundException.php +++ b/vendor/symfony/console/Exception/CommandNotFoundException.php @@ -21,10 +21,10 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce private $alternatives; /** - * @param string $message Exception message to throw. - * @param array $alternatives List of similar defined names. - * @param int $code Exception code. - * @param Exception $previous previous exception used for the exception chaining. + * @param string $message Exception message to throw + * @param array $alternatives List of similar defined names + * @param int $code Exception code + * @param \Exception $previous Previous exception used for the exception chaining */ public function __construct($message, array $alternatives = array(), $code = 0, \Exception $previous = null) { @@ -34,7 +34,7 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce } /** - * @return array A list of similar defined names. + * @return array A list of similar defined names */ public function getAlternatives() { diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php index 56cd5e56..3f3ebfbc 100644 --- a/vendor/symfony/console/Formatter/OutputFormatter.php +++ b/vendor/symfony/console/Formatter/OutputFormatter.php @@ -35,10 +35,25 @@ class OutputFormatter implements OutputFormatterInterface { $text = preg_replace('/([^\\\\]?)#ix", $message, $matches, PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { $pos = $match[1]; @@ -174,8 +168,8 @@ class OutputFormatter implements OutputFormatterInterface $output .= $this->applyCurrentStyle(substr($message, $offset)); - if (false !== strpos($output, '<<')) { - return strtr($output, array('\\<' => '<', '<<' => '\\')); + if (false !== strpos($output, "\0")) { + return strtr($output, array("\0" => '\\', '\\<' => '<')); } return str_replace('\\<', '<', $output); @@ -194,7 +188,7 @@ class OutputFormatter implements OutputFormatterInterface * * @param string $string * - * @return OutputFormatterStyle|bool false if string is not format string + * @return OutputFormatterStyle|false false if string is not format string */ private function createStyleFromString($string) { @@ -202,7 +196,7 @@ class OutputFormatter implements OutputFormatterInterface return $this->styles[$string]; } - if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) { + if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, PREG_SET_ORDER)) { return false; } @@ -214,12 +208,20 @@ class OutputFormatter implements OutputFormatterInterface $style->setForeground($match[1]); } elseif ('bg' == $match[0]) { $style->setBackground($match[1]); - } else { - try { - $style->setOption($match[1]); - } catch (\InvalidArgumentException $e) { - return false; + } elseif ('options' === $match[0]) { + preg_match_all('([^,;]+)', $match[1], $options); + $options = array_shift($options); + foreach ($options as $option) { + try { + $style->setOption($option); + } catch (\InvalidArgumentException $e) { + @trigger_error(sprintf('Unknown style options are deprecated since version 3.2 and will be removed in 4.0. Exception "%s".', $e->getMessage()), E_USER_DEPRECATED); + + return false; + } } + } else { + return false; } } diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php index 5a52ba09..281e240c 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterInterface.php +++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php @@ -55,6 +55,8 @@ interface OutputFormatterInterface * @param string $name * * @return OutputFormatterStyleInterface + * + * @throws \InvalidArgumentException When style isn't defined */ public function getStyle($name); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php index c7c6b4a0..7ada54f4 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyle.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -172,9 +172,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface } /** - * Sets multiple style options at once. - * - * @param array $options + * {@inheritdoc} */ public function setOptions(array $options) { diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php index c36fda80..4c7dc413 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -48,8 +48,6 @@ interface OutputFormatterStyleInterface /** * Sets multiple style options at once. - * - * @param array $options */ public function setOptions(array $options); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php index e5d14ea3..bf0beb70 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -23,16 +23,8 @@ class OutputFormatterStyleStack */ private $styles; - /** - * @var OutputFormatterStyleInterface - */ private $emptyStyle; - /** - * Constructor. - * - * @param OutputFormatterStyleInterface|null $emptyStyle - */ public function __construct(OutputFormatterStyleInterface $emptyStyle = null) { $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle(); @@ -49,8 +41,6 @@ class OutputFormatterStyleStack /** * Pushes a style in the stack. - * - * @param OutputFormatterStyleInterface $style */ public function push(OutputFormatterStyleInterface $style) { @@ -60,8 +50,6 @@ class OutputFormatterStyleStack /** * Pops a style from the stack. * - * @param OutputFormatterStyleInterface|null $style - * * @return OutputFormatterStyleInterface * * @throws InvalidArgumentException When style tags incorrectly nested @@ -102,9 +90,7 @@ class OutputFormatterStyleStack } /** - * @param OutputFormatterStyleInterface $emptyStyle - * - * @return OutputFormatterStyleStack + * @return $this */ public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle) { diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php index a53b476b..6f5c8183 100644 --- a/vendor/symfony/console/Helper/DescriptorHelper.php +++ b/vendor/symfony/console/Helper/DescriptorHelper.php @@ -31,9 +31,6 @@ class DescriptorHelper extends Helper */ private $descriptors = array(); - /** - * Constructor. - */ public function __construct() { $this @@ -78,7 +75,7 @@ class DescriptorHelper extends Helper * @param string $format * @param DescriptorInterface $descriptor * - * @return DescriptorHelper + * @return $this */ public function register($format, DescriptorInterface $descriptor) { diff --git a/vendor/symfony/console/Helper/DialogHelper.php b/vendor/symfony/console/Helper/DialogHelper.php deleted file mode 100644 index 9ce9f661..00000000 --- a/vendor/symfony/console/Helper/DialogHelper.php +++ /dev/null @@ -1,502 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Helper; - -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Formatter\OutputFormatterStyle; - -/** - * The Dialog class provides helpers to interact with the user. - * - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0. - * Use {@link \Symfony\Component\Console\Helper\QuestionHelper} instead. - */ -class DialogHelper extends InputAwareHelper -{ - private $inputStream; - private static $shell; - private static $stty; - - public function __construct($triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED); - } - } - - /** - * Asks the user to select a value. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param array $choices List of choices to pick from - * @param bool|string $default The default answer if the user enters nothing - * @param bool|int $attempts Max number of times to ask before giving up (false by default, which means infinite) - * @param string $errorMessage Message which will be shown if invalid value from choice list would be picked - * @param bool $multiselect Select more than one value separated by comma - * - * @return int|string|array The selected value or values (the key of the choices array) - * - * @throws InvalidArgumentException - */ - public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $width = max(array_map('strlen', array_keys($choices))); - - $messages = (array) $question; - foreach ($choices as $key => $value) { - $messages[] = sprintf(" [%-{$width}s] %s", $key, $value); - } - - $output->writeln($messages); - - $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) { - // Collapse all spaces. - $selectedChoices = str_replace(' ', '', $picked); - - if ($multiselect) { - // Check for a separated comma values - if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) { - throw new InvalidArgumentException(sprintf($errorMessage, $picked)); - } - $selectedChoices = explode(',', $selectedChoices); - } else { - $selectedChoices = array($picked); - } - - $multiselectChoices = array(); - - foreach ($selectedChoices as $value) { - if (empty($choices[$value])) { - throw new InvalidArgumentException(sprintf($errorMessage, $value)); - } - $multiselectChoices[] = $value; - } - - if ($multiselect) { - return $multiselectChoices; - } - - return $picked; - }, $attempts, $default); - - return $result; - } - - /** - * Asks a question to the user. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param string $default The default answer if none is given by the user - * @param array $autocomplete List of values to autocomplete - * - * @return string The user answer - * - * @throws RuntimeException If there is no data to read in the input stream - */ - public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null) - { - if ($this->input && !$this->input->isInteractive()) { - return $default; - } - - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $output->write($question); - - $inputStream = $this->inputStream ?: STDIN; - - if (null === $autocomplete || !$this->hasSttyAvailable()) { - $ret = fgets($inputStream, 4096); - if (false === $ret) { - throw new RuntimeException('Aborted'); - } - $ret = trim($ret); - } else { - $ret = ''; - - $i = 0; - $ofs = -1; - $matches = $autocomplete; - $numMatches = count($matches); - - $sttyMode = shell_exec('stty -g'); - - // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) - shell_exec('stty -icanon -echo'); - - // Add highlighted text style - $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); - - // Read a keypress - while (!feof($inputStream)) { - $c = fread($inputStream, 1); - - // Backspace Character - if ("\177" === $c) { - if (0 === $numMatches && 0 !== $i) { - --$i; - // Move cursor backwards - $output->write("\033[1D"); - } - - if ($i === 0) { - $ofs = -1; - $matches = $autocomplete; - $numMatches = count($matches); - } else { - $numMatches = 0; - } - - // Pop the last character off the end of our string - $ret = substr($ret, 0, $i); - } elseif ("\033" === $c) { - // Did we read an escape sequence? - $c .= fread($inputStream, 2); - - // A = Up Arrow. B = Down Arrow - if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { - if ('A' === $c[2] && -1 === $ofs) { - $ofs = 0; - } - - if (0 === $numMatches) { - continue; - } - - $ofs += ('A' === $c[2]) ? -1 : 1; - $ofs = ($numMatches + $ofs) % $numMatches; - } - } elseif (ord($c) < 32) { - if ("\t" === $c || "\n" === $c) { - if ($numMatches > 0 && -1 !== $ofs) { - $ret = $matches[$ofs]; - // Echo out remaining chars for current match - $output->write(substr($ret, $i)); - $i = strlen($ret); - } - - if ("\n" === $c) { - $output->write($c); - break; - } - - $numMatches = 0; - } - - continue; - } else { - $output->write($c); - $ret .= $c; - ++$i; - - $numMatches = 0; - $ofs = 0; - - foreach ($autocomplete as $value) { - // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) - if (0 === strpos($value, $ret) && $i !== strlen($value)) { - $matches[$numMatches++] = $value; - } - } - } - - // Erase characters from cursor to end of line - $output->write("\033[K"); - - if ($numMatches > 0 && -1 !== $ofs) { - // Save cursor position - $output->write("\0337"); - // Write highlighted text - $output->write(''.substr($matches[$ofs], $i).''); - // Restore cursor position - $output->write("\0338"); - } - } - - // Reset stty so it behaves normally again - shell_exec(sprintf('stty %s', $sttyMode)); - } - - return strlen($ret) > 0 ? $ret : $default; - } - - /** - * Asks a confirmation to the user. - * - * The question will be asked until the user answers by nothing, yes, or no. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param bool $default The default answer if the user enters nothing - * - * @return bool true if the user has confirmed, false otherwise - */ - public function askConfirmation(OutputInterface $output, $question, $default = true) - { - $answer = 'z'; - while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) { - $answer = $this->ask($output, $question); - } - - if (false === $default) { - return $answer && 'y' == strtolower($answer[0]); - } - - return !$answer || 'y' == strtolower($answer[0]); - } - - /** - * Asks a question to the user, the response is hidden. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question - * @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not - * - * @return string The answer - * - * @throws RuntimeException In case the fallback is deactivated and the response can not be hidden - */ - public function askHiddenResponse(OutputInterface $output, $question, $fallback = true) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - if ('\\' === DIRECTORY_SEPARATOR) { - $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; - - // handle code running from a phar - if ('phar:' === substr(__FILE__, 0, 5)) { - $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; - copy($exe, $tmpExe); - $exe = $tmpExe; - } - - $output->write($question); - $value = rtrim(shell_exec($exe)); - $output->writeln(''); - - if (isset($tmpExe)) { - unlink($tmpExe); - } - - return $value; - } - - if ($this->hasSttyAvailable()) { - $output->write($question); - - $sttyMode = shell_exec('stty -g'); - - shell_exec('stty -echo'); - $value = fgets($this->inputStream ?: STDIN, 4096); - shell_exec(sprintf('stty %s', $sttyMode)); - - if (false === $value) { - throw new RuntimeException('Aborted'); - } - - $value = trim($value); - $output->writeln(''); - - return $value; - } - - if (false !== $shell = $this->getShell()) { - $output->write($question); - $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword'; - $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); - $value = rtrim(shell_exec($command)); - $output->writeln(''); - - return $value; - } - - if ($fallback) { - return $this->ask($output, $question); - } - - throw new RuntimeException('Unable to hide the response'); - } - - /** - * Asks for a value and validates the response. - * - * The validator receives the data to validate. It must return the - * validated data when the data is valid and throw an exception - * otherwise. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param callable $validator A PHP callback - * @param int|false $attempts Max number of times to ask before giving up (false by default, which means infinite) - * @param string $default The default answer if none is given by the user - * @param array $autocomplete List of values to autocomplete - * - * @return mixed - * - * @throws \Exception When any of the validators return an error - */ - public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null) - { - $that = $this; - - $interviewer = function () use ($output, $question, $default, $autocomplete, $that) { - return $that->ask($output, $question, $default, $autocomplete); - }; - - return $this->validateAttempts($interviewer, $output, $validator, $attempts); - } - - /** - * Asks for a value, hide and validates the response. - * - * The validator receives the data to validate. It must return the - * validated data when the data is valid and throw an exception - * otherwise. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param callable $validator A PHP callback - * @param int|false $attempts Max number of times to ask before giving up (false by default, which means infinite) - * @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not - * - * @return string The response - * - * @throws \Exception When any of the validators return an error - * @throws RuntimeException In case the fallback is deactivated and the response can not be hidden - */ - public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true) - { - $that = $this; - - $interviewer = function () use ($output, $question, $fallback, $that) { - return $that->askHiddenResponse($output, $question, $fallback); - }; - - return $this->validateAttempts($interviewer, $output, $validator, $attempts); - } - - /** - * Sets the input stream to read from when interacting with the user. - * - * This is mainly useful for testing purpose. - * - * @param resource $stream The input stream - */ - public function setInputStream($stream) - { - $this->inputStream = $stream; - } - - /** - * Returns the helper's input stream. - * - * @return resource|null The input stream or null if the default STDIN is used - */ - public function getInputStream() - { - return $this->inputStream; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'dialog'; - } - - /** - * Return a valid Unix shell. - * - * @return string|bool The valid shell name, false in case no valid shell is found - */ - private function getShell() - { - if (null !== self::$shell) { - return self::$shell; - } - - self::$shell = false; - - if (file_exists('/usr/bin/env')) { - // handle other OSs with bash/zsh/ksh/csh if available to hide the answer - $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; - foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) { - if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { - self::$shell = $sh; - break; - } - } - } - - return self::$shell; - } - - private function hasSttyAvailable() - { - if (null !== self::$stty) { - return self::$stty; - } - - exec('stty 2>&1', $output, $exitcode); - - return self::$stty = $exitcode === 0; - } - - /** - * Validate an attempt. - * - * @param callable $interviewer A callable that will ask for a question and return the result - * @param OutputInterface $output An Output instance - * @param callable $validator A PHP callback - * @param int|false $attempts Max number of times to ask before giving up; false will ask infinitely - * - * @return string The validated response - * - * @throws \Exception In case the max number of attempts has been reached and no valid response has been given - */ - private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $e = null; - while (false === $attempts || $attempts--) { - if (null !== $e) { - $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error')); - } - - try { - return call_user_func($validator, $interviewer()); - } catch (\Exception $e) { - } - } - - throw $e; - } -} diff --git a/vendor/symfony/console/Helper/FormatterHelper.php b/vendor/symfony/console/Helper/FormatterHelper.php index ac736f98..6a48a77f 100644 --- a/vendor/symfony/console/Helper/FormatterHelper.php +++ b/vendor/symfony/console/Helper/FormatterHelper.php @@ -72,6 +72,30 @@ class FormatterHelper extends Helper return implode("\n", $messages); } + /** + * Truncates a message to the given length. + * + * @param string $message + * @param int $length + * @param string $suffix + * + * @return string + */ + public function truncate($message, $length, $suffix = '...') + { + $computedLength = $length - $this->strlen($suffix); + + if ($computedLength > $this->strlen($message)) { + return $message; + } + + if (false === $encoding = mb_detect_encoding($message, null, true)) { + return substr($message, 0, $length).$suffix; + } + + return mb_substr($message, 0, $length, $encoding).$suffix; + } + /** * {@inheritdoc} */ diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php index 43f9a169..0954bad6 100644 --- a/vendor/symfony/console/Helper/Helper.php +++ b/vendor/symfony/console/Helper/Helper.php @@ -23,9 +23,7 @@ abstract class Helper implements HelperInterface protected $helperSet = null; /** - * Sets the helper set associated with this helper. - * - * @param HelperSet $helperSet A HelperSet instance + * {@inheritdoc} */ public function setHelperSet(HelperSet $helperSet = null) { @@ -33,9 +31,7 @@ abstract class Helper implements HelperInterface } /** - * Gets the helper set associated with this helper. - * - * @return HelperSet A HelperSet instance + * {@inheritdoc} */ public function getHelperSet() { @@ -58,6 +54,24 @@ abstract class Helper implements HelperInterface return mb_strwidth($string, $encoding); } + /** + * Returns the subset of a string, using mb_substr if it is available. + * + * @param string $string String to subset + * @param int $from Start offset + * @param int|null $length Length to read + * + * @return string The string subset + */ + public static function substr($string, $from, $length = null) + { + if (false === $encoding = mb_detect_encoding($string, null, true)) { + return substr($string, $from, $length); + } + + return mb_substr($string, $from, $length, $encoding); + } + public static function formatTime($secs) { static $timeFormats = array( @@ -105,6 +119,11 @@ abstract class Helper implements HelperInterface } public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string) + { + return self::strlen(self::removeDecoration($formatter, $string)); + } + + public static function removeDecoration(OutputFormatterInterface $formatter, $string) { $isDecorated = $formatter->isDecorated(); $formatter->setDecorated(false); @@ -114,6 +133,6 @@ abstract class Helper implements HelperInterface $string = preg_replace("/\033\[[^m]*m/", '', $string); $formatter->setDecorated($isDecorated); - return self::strlen($string); + return $string; } } diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php index 5a923e0a..1ce82358 100644 --- a/vendor/symfony/console/Helper/HelperInterface.php +++ b/vendor/symfony/console/Helper/HelperInterface.php @@ -20,8 +20,6 @@ interface HelperInterface { /** * Sets the helper set associated with this helper. - * - * @param HelperSet $helperSet A HelperSet instance */ public function setHelperSet(HelperSet $helperSet = null); diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php index 27fedcf7..24ce18fb 100644 --- a/vendor/symfony/console/Helper/HelperSet.php +++ b/vendor/symfony/console/Helper/HelperSet.php @@ -21,13 +21,14 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; */ class HelperSet implements \IteratorAggregate { + /** + * @var Helper[] + */ private $helpers = array(); private $command; /** - * Constructor. - * - * @param Helper[] $helpers An array of helper. + * @param Helper[] $helpers An array of helper */ public function __construct(array $helpers = array()) { @@ -79,22 +80,9 @@ class HelperSet implements \IteratorAggregate throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); } - if ('dialog' === $name && $this->helpers[$name] instanceof DialogHelper) { - @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED); - } elseif ('progress' === $name && $this->helpers[$name] instanceof ProgressHelper) { - @trigger_error('"Symfony\Component\Console\Helper\ProgressHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\ProgressBar" instead.', E_USER_DEPRECATED); - } elseif ('table' === $name && $this->helpers[$name] instanceof TableHelper) { - @trigger_error('"Symfony\Component\Console\Helper\TableHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\Table" instead.', E_USER_DEPRECATED); - } - return $this->helpers[$name]; } - /** - * Sets the command associated with this helper set. - * - * @param Command $command A Command instance - */ public function setCommand(Command $command = null) { $this->command = $command; @@ -110,6 +98,9 @@ class HelperSet implements \IteratorAggregate return $this->command; } + /** + * @return Helper[] + */ public function getIterator() { return new \ArrayIterator($this->helpers); diff --git a/vendor/symfony/console/Helper/ProcessHelper.php b/vendor/symfony/console/Helper/ProcessHelper.php index a811eb48..82935bae 100644 --- a/vendor/symfony/console/Helper/ProcessHelper.php +++ b/vendor/symfony/console/Helper/ProcessHelper.php @@ -15,7 +15,6 @@ use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Process; -use Symfony\Component\Process\ProcessBuilder; /** * The ProcessHelper class provides helpers to run external processes. @@ -36,7 +35,7 @@ class ProcessHelper extends Helper * * @return Process The process that ran */ - public function run(OutputInterface $output, $cmd, $error = null, $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) + public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); @@ -44,9 +43,7 @@ class ProcessHelper extends Helper $formatter = $this->getHelperSet()->get('debug_formatter'); - if (is_array($cmd)) { - $process = ProcessBuilder::create($cmd)->getProcess(); - } elseif ($cmd instanceof Process) { + if ($cmd instanceof Process) { $process = $cmd; } else { $process = new Process($cmd); @@ -92,7 +89,7 @@ class ProcessHelper extends Helper * * @see run() */ - public function mustRun(OutputInterface $output, $cmd, $error = null, $callback = null) + public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null) { $process = $this->run($output, $cmd, $error, $callback); @@ -112,7 +109,7 @@ class ProcessHelper extends Helper * * @return callable */ - public function wrapCallback(OutputInterface $output, Process $process, $callback = null) + public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); @@ -120,10 +117,8 @@ class ProcessHelper extends Helper $formatter = $this->getHelperSet()->get('debug_formatter'); - $that = $this; - - return function ($type, $buffer) use ($output, $process, $callback, $formatter, $that) { - $output->write($formatter->progress(spl_object_hash($process), $that->escapeString($buffer), Process::ERR === $type)); + return function ($type, $buffer) use ($output, $process, $callback, $formatter) { + $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); if (null !== $callback) { call_user_func($callback, $type, $buffer); @@ -131,12 +126,7 @@ class ProcessHelper extends Helper }; } - /** - * This method is public for PHP 5.3 compatibility, it should be private. - * - * @internal - */ - public function escapeString($str) + private function escapeString($str) { return str_replace('<', '\\<', $str); } diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php index e7717a52..247b5913 100644 --- a/vendor/symfony/console/Helper/ProgressBar.php +++ b/vendor/symfony/console/Helper/ProgressBar.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Terminal; /** * The ProgressBar provides helpers to display progress output. @@ -21,9 +22,8 @@ use Symfony\Component\Console\Exception\LogicException; * @author Fabien Potencier * @author Chris Jones */ -class ProgressBar +final class ProgressBar { - // options private $barWidth = 28; private $barChar; private $emptyBarChar = '-'; @@ -31,10 +31,6 @@ class ProgressBar private $format; private $internalFormat; private $redrawFreq = 1; - - /** - * @var OutputInterface - */ private $output; private $step = 0; private $max; @@ -42,15 +38,15 @@ class ProgressBar private $stepWidth; private $percent = 0.0; private $formatLineCount; - private $messages; + private $messages = array(); private $overwrite = true; + private $terminal; + private $firstRun = true; private static $formatters; private static $formats; /** - * Constructor. - * * @param OutputInterface $output An OutputInterface instance * @param int $max Maximum steps (0 if unknown) */ @@ -62,6 +58,7 @@ class ProgressBar $this->output = $output; $this->setMaxSteps($max); + $this->terminal = new Terminal(); if (!$this->output->isDecorated()) { // disable overwrite when output does not support ANSI codes. @@ -82,7 +79,7 @@ class ProgressBar * @param string $name The placeholder name (including the delimiter char like %) * @param callable $callable A PHP callable */ - public static function setPlaceholderFormatterDefinition($name, $callable) + public static function setPlaceholderFormatterDefinition($name, callable $callable) { if (!self::$formatters) { self::$formatters = self::initPlaceholderFormatters(); @@ -140,6 +137,16 @@ class ProgressBar return isset(self::$formats[$name]) ? self::$formats[$name] : null; } + /** + * Associates a text with a named placeholder. + * + * The text is displayed when the progress bar is rendered but only + * when the corresponding placeholder is part of the custom format line + * (by wrapping the name with %). + * + * @param string $message The text to associate with the placeholder + * @param string $name The name of the placeholder + */ public function setMessage($message, $name = 'message') { $this->messages[$name] = $message; @@ -170,20 +177,6 @@ class ProgressBar return $this->max; } - /** - * Gets the progress bar step. - * - * @deprecated since version 2.6, to be removed in 3.0. Use {@link getProgress()} instead. - * - * @return int The progress bar step - */ - public function getStep() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the getProgress() method instead.', E_USER_DEPRECATED); - - return $this->getProgress(); - } - /** * Gets the current step position. * @@ -197,11 +190,9 @@ class ProgressBar /** * Gets the progress bar step width. * - * @internal This method is public for PHP 5.3 compatibility, it should not be used. - * * @return int The progress bar step width */ - public function getStepWidth() + private function getStepWidth() { return $this->stepWidth; } @@ -223,7 +214,7 @@ class ProgressBar */ public function setBarWidth($size) { - $this->barWidth = (int) $size; + $this->barWidth = max(1, (int) $size); } /** @@ -343,30 +334,12 @@ class ProgressBar * Advances the progress output X steps. * * @param int $step Number of steps to advance - * - * @throws LogicException */ public function advance($step = 1) { $this->setProgress($this->step + $step); } - /** - * Sets the current progress. - * - * @deprecated since version 2.6, to be removed in 3.0. Use {@link setProgress()} instead. - * - * @param int $step The current progress - * - * @throws LogicException - */ - public function setCurrent($step) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the setProgress() method instead.', E_USER_DEPRECATED); - - $this->setProgress($step); - } - /** * Sets whether to overwrite the progressbar, false for new line. * @@ -381,18 +354,15 @@ class ProgressBar * Sets the current progress. * * @param int $step The current progress - * - * @throws LogicException */ public function setProgress($step) { $step = (int) $step; - if ($step < $this->step) { - throw new LogicException('You can\'t regress the progress bar.'); - } if ($this->max && $step > $this->max) { $this->max = $step; + } elseif ($step < 0) { + $step = 0; } $prevPeriod = (int) ($this->step / $this->redrawFreq); @@ -434,25 +404,7 @@ class ProgressBar $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } - // these 3 variables can be removed in favor of using $this in the closure when support for PHP 5.3 will be dropped. - $self = $this; - $output = $this->output; - $messages = $this->messages; - $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) { - if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) { - $text = call_user_func($formatter, $self, $output); - } elseif (isset($messages[$matches[1]])) { - $text = $messages[$matches[1]]; - } else { - return $matches[0]; - } - - if (isset($matches[2])) { - $text = sprintf('%'.$matches[2], $text); - } - - return $text; - }, $this->format)); + $this->overwrite($this->buildLine()); } /** @@ -513,20 +465,24 @@ class ProgressBar private function overwrite($message) { if ($this->overwrite) { - // Move the cursor to the beginning of the line - $this->output->write("\x0D"); + if (!$this->firstRun) { + // Move the cursor to the beginning of the line + $this->output->write("\x0D"); - // Erase the line - $this->output->write("\x1B[2K"); + // Erase the line + $this->output->write("\x1B[2K"); - // Erase previous lines - if ($this->formatLineCount > 0) { - $this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount)); + // Erase previous lines + if ($this->formatLineCount > 0) { + $this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount)); + } } } elseif ($this->step > 0) { $this->output->writeln(''); } + $this->firstRun = false; + $this->output->write($message); } @@ -618,4 +574,44 @@ class ProgressBar 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%', ); } + + /** + * @return string + */ + private function buildLine() + { + $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; + $callback = function ($matches) { + if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { + $text = call_user_func($formatter, $this, $this->output); + } elseif (isset($this->messages[$matches[1]])) { + $text = $this->messages[$matches[1]]; + } else { + return $matches[0]; + } + + if (isset($matches[2])) { + $text = sprintf('%'.$matches[2], $text); + } + + return $text; + }; + $line = preg_replace_callback($regex, $callback, $this->format); + + // gets string length for each sub line with multiline format + $linesLength = array_map(function ($subLine) { + return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r")); + }, explode("\n", $line)); + + $linesWidth = max($linesLength); + + $terminalWidth = $this->terminal->getWidth(); + if ($linesWidth <= $terminalWidth) { + return $line; + } + + $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth); + + return preg_replace_callback($regex, $callback, $this->format); + } } diff --git a/vendor/symfony/console/Helper/ProgressHelper.php b/vendor/symfony/console/Helper/ProgressHelper.php deleted file mode 100644 index 96b6202c..00000000 --- a/vendor/symfony/console/Helper/ProgressHelper.php +++ /dev/null @@ -1,471 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Helper; - -use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Exception\LogicException; - -/** - * The Progress class provides helpers to display progress output. - * - * @author Chris Jones - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0 - * Use {@link ProgressBar} instead. - */ -class ProgressHelper extends Helper -{ - const FORMAT_QUIET = ' %percent%%'; - const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%'; - const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%'; - const FORMAT_QUIET_NOMAX = ' %current%'; - const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]'; - const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%'; - - // options - private $barWidth = 28; - private $barChar = '='; - private $emptyBarChar = '-'; - private $progressChar = '>'; - private $format = null; - private $redrawFreq = 1; - - private $lastMessagesLength; - private $barCharOriginal; - - /** - * @var OutputInterface - */ - private $output; - - /** - * Current step. - * - * @var int - */ - private $current; - - /** - * Maximum number of steps. - * - * @var int - */ - private $max; - - /** - * Start time of the progress bar. - * - * @var int - */ - private $startTime; - - /** - * List of formatting variables. - * - * @var array - */ - private $defaultFormatVars = array( - 'current', - 'max', - 'bar', - 'percent', - 'elapsed', - ); - - /** - * Available formatting variables. - * - * @var array - */ - private $formatVars; - - /** - * Stored format part widths (used for padding). - * - * @var array - */ - private $widths = array( - 'current' => 4, - 'max' => 4, - 'percent' => 3, - 'elapsed' => 6, - ); - - /** - * Various time formats. - * - * @var array - */ - private $timeFormats = array( - array(0, '???'), - array(2, '1 sec'), - array(59, 'secs', 1), - array(60, '1 min'), - array(3600, 'mins', 60), - array(5400, '1 hr'), - array(86400, 'hrs', 3600), - array(129600, '1 day'), - array(604800, 'days', 86400), - ); - - public function __construct($triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\ProgressBar class instead.', E_USER_DEPRECATED); - } - } - - /** - * Sets the progress bar width. - * - * @param int $size The progress bar size - */ - public function setBarWidth($size) - { - $this->barWidth = (int) $size; - } - - /** - * Sets the bar character. - * - * @param string $char A character - */ - public function setBarCharacter($char) - { - $this->barChar = $char; - } - - /** - * Sets the empty bar character. - * - * @param string $char A character - */ - public function setEmptyBarCharacter($char) - { - $this->emptyBarChar = $char; - } - - /** - * Sets the progress bar character. - * - * @param string $char A character - */ - public function setProgressCharacter($char) - { - $this->progressChar = $char; - } - - /** - * Sets the progress bar format. - * - * @param string $format The format - */ - public function setFormat($format) - { - $this->format = $format; - } - - /** - * Sets the redraw frequency. - * - * @param int $freq The frequency in steps - */ - public function setRedrawFrequency($freq) - { - $this->redrawFreq = (int) $freq; - } - - /** - * Starts the progress output. - * - * @param OutputInterface $output An Output instance - * @param int|null $max Maximum steps - */ - public function start(OutputInterface $output, $max = null) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $this->startTime = time(); - $this->current = 0; - $this->max = (int) $max; - - // Disabling output when it does not support ANSI codes as it would result in a broken display anyway. - $this->output = $output->isDecorated() ? $output : new NullOutput(); - $this->lastMessagesLength = 0; - $this->barCharOriginal = ''; - - if (null === $this->format) { - switch ($output->getVerbosity()) { - case OutputInterface::VERBOSITY_QUIET: - $this->format = self::FORMAT_QUIET_NOMAX; - if ($this->max > 0) { - $this->format = self::FORMAT_QUIET; - } - break; - case OutputInterface::VERBOSITY_VERBOSE: - case OutputInterface::VERBOSITY_VERY_VERBOSE: - case OutputInterface::VERBOSITY_DEBUG: - $this->format = self::FORMAT_VERBOSE_NOMAX; - if ($this->max > 0) { - $this->format = self::FORMAT_VERBOSE; - } - break; - default: - $this->format = self::FORMAT_NORMAL_NOMAX; - if ($this->max > 0) { - $this->format = self::FORMAT_NORMAL; - } - break; - } - } - - $this->initialize(); - } - - /** - * Advances the progress output X steps. - * - * @param int $step Number of steps to advance - * @param bool $redraw Whether to redraw or not - * - * @throws LogicException - */ - public function advance($step = 1, $redraw = false) - { - $this->setCurrent($this->current + $step, $redraw); - } - - /** - * Sets the current progress. - * - * @param int $current The current progress - * @param bool $redraw Whether to redraw or not - * - * @throws LogicException - */ - public function setCurrent($current, $redraw = false) - { - if (null === $this->startTime) { - throw new LogicException('You must start the progress bar before calling setCurrent().'); - } - - $current = (int) $current; - - if ($current < $this->current) { - throw new LogicException('You can\'t regress the progress bar'); - } - - if (0 === $this->current) { - $redraw = true; - } - - $prevPeriod = (int) ($this->current / $this->redrawFreq); - - $this->current = $current; - - $currPeriod = (int) ($this->current / $this->redrawFreq); - if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) { - $this->display(); - } - } - - /** - * Outputs the current progress string. - * - * @param bool $finish Forces the end result - * - * @throws LogicException - */ - public function display($finish = false) - { - if (null === $this->startTime) { - throw new LogicException('You must start the progress bar before calling display().'); - } - - $message = $this->format; - foreach ($this->generate($finish) as $name => $value) { - $message = str_replace("%{$name}%", $value, $message); - } - $this->overwrite($this->output, $message); - } - - /** - * Removes the progress bar from the current line. - * - * This is useful if you wish to write some output - * while a progress bar is running. - * Call display() to show the progress bar again. - */ - public function clear() - { - $this->overwrite($this->output, ''); - } - - /** - * Finishes the progress output. - */ - public function finish() - { - if (null === $this->startTime) { - throw new LogicException('You must start the progress bar before calling finish().'); - } - - if (null !== $this->startTime) { - if (!$this->max) { - $this->barChar = $this->barCharOriginal; - $this->display(true); - } - $this->startTime = null; - $this->output->writeln(''); - $this->output = null; - } - } - - /** - * Initializes the progress helper. - */ - private function initialize() - { - $this->formatVars = array(); - foreach ($this->defaultFormatVars as $var) { - if (false !== strpos($this->format, "%{$var}%")) { - $this->formatVars[$var] = true; - } - } - - if ($this->max > 0) { - $this->widths['max'] = $this->strlen($this->max); - $this->widths['current'] = $this->widths['max']; - } else { - $this->barCharOriginal = $this->barChar; - $this->barChar = $this->emptyBarChar; - } - } - - /** - * Generates the array map of format variables to values. - * - * @param bool $finish Forces the end result - * - * @return array Array of format vars and values - */ - private function generate($finish = false) - { - $vars = array(); - $percent = 0; - if ($this->max > 0) { - $percent = (float) $this->current / $this->max; - } - - if (isset($this->formatVars['bar'])) { - $completeBars = 0; - - if ($this->max > 0) { - $completeBars = floor($percent * $this->barWidth); - } else { - if (!$finish) { - $completeBars = floor($this->current % $this->barWidth); - } else { - $completeBars = $this->barWidth; - } - } - - $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar); - $bar = str_repeat($this->barChar, $completeBars); - if ($completeBars < $this->barWidth) { - $bar .= $this->progressChar; - $bar .= str_repeat($this->emptyBarChar, $emptyBars); - } - - $vars['bar'] = $bar; - } - - if (isset($this->formatVars['elapsed'])) { - $elapsed = time() - $this->startTime; - $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT); - } - - if (isset($this->formatVars['current'])) { - $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT); - } - - if (isset($this->formatVars['max'])) { - $vars['max'] = $this->max; - } - - if (isset($this->formatVars['percent'])) { - $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT); - } - - return $vars; - } - - /** - * Converts seconds into human-readable format. - * - * @param int $secs Number of seconds - * - * @return string Time in readable format - */ - private function humaneTime($secs) - { - $text = ''; - foreach ($this->timeFormats as $format) { - if ($secs < $format[0]) { - if (count($format) == 2) { - $text = $format[1]; - break; - } else { - $text = ceil($secs / $format[2]).' '.$format[1]; - break; - } - } - } - - return $text; - } - - /** - * Overwrites a previous message to the output. - * - * @param OutputInterface $output An Output instance - * @param string $message The message - */ - private function overwrite(OutputInterface $output, $message) - { - $length = $this->strlen($message); - - // append whitespace to match the last line's length - if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) { - $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); - } - - // carriage return - $output->write("\x0D"); - $output->write($message); - - $this->lastMessagesLength = $this->strlen($message); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'progress'; - } -} diff --git a/vendor/symfony/console/Helper/ProgressIndicator.php b/vendor/symfony/console/Helper/ProgressIndicator.php index ccf9771b..d441accd 100644 --- a/vendor/symfony/console/Helper/ProgressIndicator.php +++ b/vendor/symfony/console/Helper/ProgressIndicator.php @@ -28,7 +28,6 @@ class ProgressIndicator private $indicatorCurrent; private $indicatorChangeInterval; private $indicatorUpdateTime; - private $lastMessagesLength; private $started = false; private static $formatters; @@ -76,42 +75,6 @@ class ProgressIndicator $this->display(); } - /** - * Gets the current indicator message. - * - * @return string|null - * - * @internal for PHP 5.3 compatibility - */ - public function getMessage() - { - return $this->message; - } - - /** - * Gets the progress bar start time. - * - * @return int The progress bar start time - * - * @internal for PHP 5.3 compatibility - */ - public function getStartTime() - { - return $this->startTime; - } - - /** - * Gets the current animated indicator character. - * - * @return string - * - * @internal for PHP 5.3 compatibility - */ - public function getCurrentValue() - { - return $this->indicatorValues[$this->indicatorCurrent % count($this->indicatorValues)]; - } - /** * Starts the indicator output. * @@ -125,7 +88,6 @@ class ProgressIndicator $this->message = $message; $this->started = true; - $this->lastMessagesLength = 0; $this->startTime = time(); $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; $this->indicatorCurrent = 0; @@ -262,27 +224,12 @@ class ProgressIndicator */ private function overwrite($message) { - // append whitespace to match the line's length - if (null !== $this->lastMessagesLength) { - if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $message)) { - $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); - } - } - if ($this->output->isDecorated()) { - $this->output->write("\x0D"); + $this->output->write("\x0D\x1B[2K"); $this->output->write($message); } else { $this->output->writeln($message); } - - $this->lastMessagesLength = 0; - - $len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $message); - - if ($len > $this->lastMessagesLength) { - $this->lastMessagesLength = $len; - } } private function getCurrentTimeInMilliseconds() @@ -294,13 +241,13 @@ class ProgressIndicator { return array( 'indicator' => function (ProgressIndicator $indicator) { - return $indicator->getCurrentValue(); + return $indicator->indicatorValues[$indicator->indicatorCurrent % count($indicator->indicatorValues)]; }, 'message' => function (ProgressIndicator $indicator) { - return $indicator->getMessage(); + return $indicator->message; }, 'elapsed' => function (ProgressIndicator $indicator) { - return Helper::formatTime(time() - $indicator->getStartTime()); + return Helper::formatTime(time() - $indicator->startTime); }, 'memory' => function () { return Helper::formatMemory(memory_get_usage(true)); diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php index 5bb30df8..f0f37a09 100644 --- a/vendor/symfony/console/Helper/QuestionHelper.php +++ b/vendor/symfony/console/Helper/QuestionHelper.php @@ -13,10 +13,12 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StreamableInputInterface; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\ChoiceQuestion; @@ -34,11 +36,7 @@ class QuestionHelper extends Helper /** * Asks a question to the user. * - * @param InputInterface $input An InputInterface instance - * @param OutputInterface $output An OutputInterface instance - * @param Question $question The question to ask - * - * @return string The user answer + * @return mixed The user answer * * @throws RuntimeException If there is no data to read in the input stream */ @@ -52,14 +50,16 @@ class QuestionHelper extends Helper return $question->getDefault(); } + if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { + $this->inputStream = $stream; + } + if (!$question->getValidator()) { return $this->doAsk($output, $question); } - $that = $this; - - $interviewer = function () use ($output, $question, $that) { - return $that->doAsk($output, $question); + $interviewer = function () use ($output, $question) { + return $this->doAsk($output, $question); }; return $this->validateAttempts($interviewer, $output, $question); @@ -70,12 +70,17 @@ class QuestionHelper extends Helper * * This is mainly useful for testing purpose. * + * @deprecated since version 3.2, to be removed in 4.0. Use + * StreamableInputInterface::setStream() instead. + * * @param resource $stream The input stream * * @throws InvalidArgumentException In case the stream is not a resource */ public function setInputStream($stream) { + @trigger_error(sprintf('The %s() method is deprecated since version 3.2 and will be removed in 4.0. Use %s::setStream() instead.', __METHOD__, StreamableInputInterface::class), E_USER_DEPRECATED); + if (!is_resource($stream)) { throw new InvalidArgumentException('Input stream must be a valid resource.'); } @@ -86,10 +91,17 @@ class QuestionHelper extends Helper /** * Returns the helper's input stream. * + * @deprecated since version 3.2, to be removed in 4.0. Use + * StreamableInputInterface::getStream() instead. + * * @return resource */ public function getInputStream() { + if (0 === func_num_args() || func_get_arg(0)) { + @trigger_error(sprintf('The %s() method is deprecated since version 3.2 and will be removed in 4.0. Use %s::getStream() instead.', __METHOD__, StreamableInputInterface::class), E_USER_DEPRECATED); + } + return $this->inputStream; } @@ -101,20 +113,22 @@ class QuestionHelper extends Helper return 'question'; } + /** + * Prevents usage of stty. + */ + public static function disableStty() + { + self::$stty = false; + } + /** * Asks the question to the user. * - * This method is public for PHP 5.3 compatibility, it should be private. - * - * @param OutputInterface $output - * @param Question $question - * * @return bool|mixed|null|string * - * @throws \Exception - * @throws \RuntimeException + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ - public function doAsk(OutputInterface $output, Question $question) + private function doAsk(OutputInterface $output, Question $question) { $this->writePrompt($output, $question); @@ -126,7 +140,7 @@ class QuestionHelper extends Helper if ($question->isHidden()) { try { $ret = trim($this->getHiddenResponse($output, $inputStream)); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { if (!$question->isHiddenFallback()) { throw $e; } @@ -136,12 +150,12 @@ class QuestionHelper extends Helper if (false === $ret) { $ret = fgets($inputStream, 4096); if (false === $ret) { - throw new \RuntimeException('Aborted'); + throw new RuntimeException('Aborted'); } $ret = trim($ret); } } else { - $ret = trim($this->autocomplete($output, $question, $inputStream)); + $ret = trim($this->autocomplete($output, $question, $inputStream, is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false))); } $ret = strlen($ret) > 0 ? $ret : $question->getDefault(); @@ -155,9 +169,6 @@ class QuestionHelper extends Helper /** * Outputs the question prompt. - * - * @param OutputInterface $output - * @param Question $question */ protected function writePrompt(OutputInterface $output, Question $question) { @@ -182,9 +193,6 @@ class QuestionHelper extends Helper /** * Outputs an error message. - * - * @param OutputInterface $output - * @param \Exception $error */ protected function writeError(OutputInterface $output, \Exception $error) { @@ -202,12 +210,13 @@ class QuestionHelper extends Helper * * @param OutputInterface $output * @param Question $question + * @param resource $inputStream + * @param array $autocomplete * * @return string */ - private function autocomplete(OutputInterface $output, Question $question, $inputStream) + private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete) { - $autocomplete = $question->getAutocompleterValues(); $ret = ''; $i = 0; @@ -235,7 +244,7 @@ class QuestionHelper extends Helper $output->write("\033[1D"); } - if ($i === 0) { + if (0 === $i) { $ofs = -1; $matches = $autocomplete; $numMatches = count($matches); @@ -303,7 +312,7 @@ class QuestionHelper extends Helper // Save cursor position $output->write("\0337"); // Write highlighted text - $output->write(''.substr($matches[$ofs], $i).''); + $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).''); // Restore cursor position $output->write("\0338"); } @@ -318,7 +327,8 @@ class QuestionHelper extends Helper /** * Gets a hidden response from user. * - * @param OutputInterface $output An Output instance + * @param OutputInterface $output An Output instance + * @param resource $inputStream The handler resource * * @return string The answer * @@ -364,7 +374,7 @@ class QuestionHelper extends Helper } if (false !== $shell = $this->getShell()) { - $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword'; + $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword'; $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); $value = rtrim(shell_exec($command)); $output->writeln(''); @@ -382,11 +392,11 @@ class QuestionHelper extends Helper * @param OutputInterface $output An Output instance * @param Question $question A Question instance * - * @return string The validated response + * @return mixed The validated response * * @throws \Exception In case the max number of attempts has been reached and no valid response has been given */ - private function validateAttempts($interviewer, OutputInterface $output, Question $question) + private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question) { $error = null; $attempts = $question->getMaxAttempts(); @@ -397,6 +407,8 @@ class QuestionHelper extends Helper try { return call_user_func($question->getValidator(), $interviewer()); + } catch (RuntimeException $e) { + throw $e; } catch (\Exception $error) { } } @@ -444,6 +456,6 @@ class QuestionHelper extends Helper exec('stty 2>&1', $output, $exitcode); - return self::$stty = $exitcode === 0; + return self::$stty = 0 === $exitcode; } } diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php index 942278bd..cf071d59 100644 --- a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php @@ -18,6 +18,7 @@ use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Console\Formatter\OutputFormatter; /** * Symfony Style Guide compliant question helper. @@ -28,6 +29,8 @@ class SymfonyQuestionHelper extends QuestionHelper { /** * {@inheritdoc} + * + * To be removed in 4.0 */ public function ask(InputInterface $input, OutputInterface $output, Question $question) { @@ -35,11 +38,13 @@ class SymfonyQuestionHelper extends QuestionHelper $question->setValidator(function ($value) use ($validator) { if (null !== $validator) { $value = $validator($value); - } + } else { + // make required + if (!is_array($value) && !is_bool($value) && 0 === strlen($value)) { + @trigger_error('The default question validator is deprecated since Symfony 3.3 and will not be used anymore in version 4.0. Set a custom question validator if needed.', E_USER_DEPRECATED); - // make required - if (!is_array($value) && !is_bool($value) && 0 === strlen($value)) { - throw new LogicException('A value is required.'); + throw new LogicException('A value is required.'); + } } return $value; @@ -53,7 +58,7 @@ class SymfonyQuestionHelper extends QuestionHelper */ protected function writePrompt(OutputInterface $output, Question $question) { - $text = $question->getQuestion(); + $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); $default = $question->getDefault(); switch (true) { @@ -67,14 +72,26 @@ class SymfonyQuestionHelper extends QuestionHelper break; + case $question instanceof ChoiceQuestion && $question->isMultiselect(): + $choices = $question->getChoices(); + $default = explode(',', $default); + + foreach ($default as $key => $value) { + $default[$key] = $choices[trim($value)]; + } + + $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); + + break; + case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); - $text = sprintf(' %s [%s]:', $text, $choices[$default]); + $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default])); break; default: - $text = sprintf(' %s [%s]:', $text, $default); + $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php index 13e4c3cf..905f7b87 100644 --- a/vendor/symfony/console/Helper/Table.php +++ b/vendor/symfony/console/Helper/Table.php @@ -26,29 +26,23 @@ class Table { /** * Table headers. - * - * @var array */ private $headers = array(); /** * Table rows. - * - * @var array */ private $rows = array(); /** * Column widths cache. - * - * @var array */ - private $columnWidths = array(); + private $effectiveColumnWidths = array(); /** * Number of columns cache. * - * @var array + * @var int */ private $numberOfColumns; @@ -67,6 +61,13 @@ class Table */ private $columnStyles = array(); + /** + * User set column widths. + * + * @var array + */ + private $columnWidths = array(); + private static $styles; public function __construct(OutputInterface $output) @@ -100,7 +101,7 @@ class Table * * @param string $name The style name * - * @return TableStyle A TableStyle instance + * @return TableStyle */ public static function getStyleDefinition($name) { @@ -108,11 +109,11 @@ class Table self::$styles = self::initStyles(); } - if (!self::$styles[$name]) { - throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + if (isset(self::$styles[$name])) { + return self::$styles[$name]; } - return self::$styles[$name]; + throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); } /** @@ -120,17 +121,11 @@ class Table * * @param TableStyle|string $name The style name or a TableStyle instance * - * @return Table + * @return $this */ public function setStyle($name) { - if ($name instanceof TableStyle) { - $this->style = $name; - } elseif (isset(self::$styles[$name])) { - $this->style = self::$styles[$name]; - } else { - throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); - } + $this->style = $this->resolveStyle($name); return $this; } @@ -151,19 +146,13 @@ class Table * @param int $columnIndex Column index * @param TableStyle|string $name The style name or a TableStyle instance * - * @return Table + * @return $this */ public function setColumnStyle($columnIndex, $name) { - $columnIndex = intval($columnIndex); + $columnIndex = (int) $columnIndex; - if ($name instanceof TableStyle) { - $this->columnStyles[$columnIndex] = $name; - } elseif (isset(self::$styles[$name])) { - $this->columnStyles[$columnIndex] = self::$styles[$name]; - } else { - throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); - } + $this->columnStyles[$columnIndex] = $this->resolveStyle($name); return $this; } @@ -186,6 +175,38 @@ class Table return $this->getStyle(); } + /** + * Sets the minimum width of a column. + * + * @param int $columnIndex Column index + * @param int $width Minimum column width in characters + * + * @return $this + */ + public function setColumnWidth($columnIndex, $width) + { + $this->columnWidths[(int) $columnIndex] = (int) $width; + + return $this; + } + + /** + * Sets the minimum width of all columns. + * + * @param array $widths + * + * @return $this + */ + public function setColumnWidths(array $widths) + { + $this->columnWidths = array(); + foreach ($widths as $index => $width) { + $this->setColumnWidth($index, $width); + } + + return $this; + } + public function setHeaders(array $headers) { $headers = array_values($headers); @@ -242,6 +263,7 @@ class Table * Renders table to output. * * Example: + * * +---------------+-----------------------+------------------+ * | ISBN | Title | Author | * +---------------+-----------------------+------------------+ @@ -249,6 +271,7 @@ class Table * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ + * */ public function render() { @@ -282,7 +305,7 @@ class Table /** * Renders horizontal header separator. * - * Example: +-----+-----------+-------+ + * Example: +-----+-----------+-------+ */ private function renderRowSeparator() { @@ -296,7 +319,7 @@ class Table $markup = $this->style->getCrossingChar(); for ($column = 0; $column < $count; ++$column) { - $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar(); + $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->effectiveColumnWidths[$column]).$this->style->getCrossingChar(); } $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); @@ -313,7 +336,7 @@ class Table /** * Renders table row. * - * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * * @param array $row * @param string $cellFormat @@ -342,11 +365,11 @@ class Table private function renderCell(array $row, $column, $cellFormat) { $cell = isset($row[$column]) ? $row[$column] : ''; - $width = $this->columnWidths[$column]; + $width = $this->effectiveColumnWidths[$column]; if ($cell instanceof TableCell && $cell->getColspan() > 1) { // add the width of the following columns(numbers of colspan). foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { - $width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn]; + $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; } } @@ -399,7 +422,7 @@ class Table if (!strstr($cell, "\n")) { continue; } - $lines = explode("\n", $cell); + $lines = explode("\n", str_replace("\n", "\n", $cell)); foreach ($lines as $lineKey => $line) { if ($cell instanceof TableCell) { $line = new TableCell($line, array('colspan' => $cell->getColspan())); @@ -432,7 +455,7 @@ class Table * * @return array */ - private function fillNextRows($rows, $line) + private function fillNextRows(array $rows, $line) { $unmergedRows = array(); foreach ($rows[$line] as $column => $cell) { @@ -440,7 +463,7 @@ class Table $nbLines = $cell->getRowspan() - 1; $lines = array($cell); if (strstr($cell, "\n")) { - $lines = explode("\n", $cell); + $lines = explode("\n", str_replace("\n", "\n", $cell)); $nbLines = count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; $rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan())); @@ -448,10 +471,13 @@ class Table } // create a two dimensional array (rowspan x colspan) - $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, ''), $unmergedRows); + $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, array()), $unmergedRows); foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : ''; $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan())); + if ($nbLines === $unmergedRowKey - $line) { + break; + } } } } @@ -480,8 +506,6 @@ class Table /** * fill cells for a row that contains colspan > 1. * - * @param array $row - * * @return array */ private function fillCells($row) @@ -506,7 +530,7 @@ class Table * * @return array */ - private function copyRow($rows, $line) + private function copyRow(array $rows, $line) { $row = $rows[$line]; foreach ($row as $cellKey => $cellValue) { @@ -522,8 +546,6 @@ class Table /** * Gets number of columns by row. * - * @param array $row - * * @return int */ private function getNumberOfColumns(array $row) @@ -539,11 +561,9 @@ class Table /** * Gets list of columns for the given row. * - * @param array $row - * * @return array */ - private function getRowColumns($row) + private function getRowColumns(array $row) { $columns = range(0, $this->numberOfColumns - 1); foreach ($row as $cellKey => $cell) { @@ -558,10 +578,8 @@ class Table /** * Calculates columns widths. - * - * @param array $rows */ - private function calculateColumnsWidth($rows) + private function calculateColumnsWidth(array $rows) { for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = array(); @@ -572,9 +590,10 @@ class Table foreach ($row as $i => $cell) { if ($cell instanceof TableCell) { - $textLength = strlen($cell); + $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); + $textLength = Helper::strlen($textContent); if ($textLength > 0) { - $contentColumns = str_split($cell, ceil($textLength / $cell->getColspan())); + $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } @@ -585,7 +604,7 @@ class Table $lengths[] = $this->getCellWidth($row, $column); } - $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2; + $this->effectiveColumnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2; } } @@ -609,14 +628,16 @@ class Table */ private function getCellWidth(array $row, $column) { + $cellWidth = 0; + if (isset($row[$column])) { $cell = $row[$column]; $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); - - return $cellWidth; } - return 0; + $columnWidth = isset($this->columnWidths[$column]) ? $this->columnWidths[$column] : 0; + + return max($cellWidth, $columnWidth); } /** @@ -624,7 +645,7 @@ class Table */ private function cleanup() { - $this->columnWidths = array(); + $this->effectiveColumnWidths = array(); $this->numberOfColumns = null; } @@ -660,4 +681,17 @@ class Table 'symfony-style-guide' => $styleGuide, ); } + + private function resolveStyle($name) + { + if ($name instanceof TableStyle) { + return $name; + } + + if (isset(self::$styles[$name])) { + return self::$styles[$name]; + } + + throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + } } diff --git a/vendor/symfony/console/Helper/TableCell.php b/vendor/symfony/console/Helper/TableCell.php index 69442d42..6fc7d3b9 100644 --- a/vendor/symfony/console/Helper/TableCell.php +++ b/vendor/symfony/console/Helper/TableCell.php @@ -18,14 +18,7 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; */ class TableCell { - /** - * @var string - */ private $value; - - /** - * @var array - */ private $options = array( 'rowspan' => 1, 'colspan' => 1, @@ -37,6 +30,10 @@ class TableCell */ public function __construct($value = '', array $options = array()) { + if (is_numeric($value) && !is_string($value)) { + $value = (string) $value; + } + $this->value = $value; // check option names diff --git a/vendor/symfony/console/Helper/TableHelper.php b/vendor/symfony/console/Helper/TableHelper.php deleted file mode 100644 index 3c7a1a78..00000000 --- a/vendor/symfony/console/Helper/TableHelper.php +++ /dev/null @@ -1,269 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Helper; - -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\Console\Exception\InvalidArgumentException; - -/** - * Provides helpers to display table output. - * - * @author Саша Стаменковић - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0 - * Use {@link Table} instead. - */ -class TableHelper extends Helper -{ - const LAYOUT_DEFAULT = 0; - const LAYOUT_BORDERLESS = 1; - const LAYOUT_COMPACT = 2; - - /** - * @var Table - */ - private $table; - - public function __construct($triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\Table class instead.', E_USER_DEPRECATED); - } - - $this->table = new Table(new NullOutput()); - } - - /** - * Sets table layout type. - * - * @param int $layout self::LAYOUT_* - * - * @return TableHelper - * - * @throws InvalidArgumentException when the table layout is not known - */ - public function setLayout($layout) - { - switch ($layout) { - case self::LAYOUT_BORDERLESS: - $this->table->setStyle('borderless'); - break; - - case self::LAYOUT_COMPACT: - $this->table->setStyle('compact'); - break; - - case self::LAYOUT_DEFAULT: - $this->table->setStyle('default'); - break; - - default: - throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout)); - } - - return $this; - } - - public function setHeaders(array $headers) - { - $this->table->setHeaders($headers); - - return $this; - } - - public function setRows(array $rows) - { - $this->table->setRows($rows); - - return $this; - } - - public function addRows(array $rows) - { - $this->table->addRows($rows); - - return $this; - } - - public function addRow(array $row) - { - $this->table->addRow($row); - - return $this; - } - - public function setRow($column, array $row) - { - $this->table->setRow($column, $row); - - return $this; - } - - /** - * Sets padding character, used for cell padding. - * - * @param string $paddingChar - * - * @return TableHelper - */ - public function setPaddingChar($paddingChar) - { - $this->table->getStyle()->setPaddingChar($paddingChar); - - return $this; - } - - /** - * Sets horizontal border character. - * - * @param string $horizontalBorderChar - * - * @return TableHelper - */ - public function setHorizontalBorderChar($horizontalBorderChar) - { - $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar); - - return $this; - } - - /** - * Sets vertical border character. - * - * @param string $verticalBorderChar - * - * @return TableHelper - */ - public function setVerticalBorderChar($verticalBorderChar) - { - $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar); - - return $this; - } - - /** - * Sets crossing character. - * - * @param string $crossingChar - * - * @return TableHelper - */ - public function setCrossingChar($crossingChar) - { - $this->table->getStyle()->setCrossingChar($crossingChar); - - return $this; - } - - /** - * Sets header cell format. - * - * @param string $cellHeaderFormat - * - * @return TableHelper - */ - public function setCellHeaderFormat($cellHeaderFormat) - { - $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat); - - return $this; - } - - /** - * Sets row cell format. - * - * @param string $cellRowFormat - * - * @return TableHelper - */ - public function setCellRowFormat($cellRowFormat) - { - $this->table->getStyle()->setCellHeaderFormat($cellRowFormat); - - return $this; - } - - /** - * Sets row cell content format. - * - * @param string $cellRowContentFormat - * - * @return TableHelper - */ - public function setCellRowContentFormat($cellRowContentFormat) - { - $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat); - - return $this; - } - - /** - * Sets table border format. - * - * @param string $borderFormat - * - * @return TableHelper - */ - public function setBorderFormat($borderFormat) - { - $this->table->getStyle()->setBorderFormat($borderFormat); - - return $this; - } - - /** - * Sets cell padding type. - * - * @param int $padType STR_PAD_* - * - * @return TableHelper - */ - public function setPadType($padType) - { - $this->table->getStyle()->setPadType($padType); - - return $this; - } - - /** - * Renders table to output. - * - * Example: - * +---------------+-----------------------+------------------+ - * | ISBN | Title | Author | - * +---------------+-----------------------+------------------+ - * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | - * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | - * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | - * +---------------+-----------------------+------------------+ - * - * @param OutputInterface $output - */ - public function render(OutputInterface $output) - { - $p = new \ReflectionProperty($this->table, 'output'); - $p->setAccessible(true); - $p->setValue($this->table, $output); - - $this->table->render(); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'table'; - } -} diff --git a/vendor/symfony/console/Helper/TableSeparator.php b/vendor/symfony/console/Helper/TableSeparator.php index 8cbbc661..c7b8dc9c 100644 --- a/vendor/symfony/console/Helper/TableSeparator.php +++ b/vendor/symfony/console/Helper/TableSeparator.php @@ -18,10 +18,6 @@ namespace Symfony\Component\Console\Helper; */ class TableSeparator extends TableCell { - /** - * @param string $value - * @param array $options - */ public function __construct(array $options = array()) { parent::__construct('', $options); diff --git a/vendor/symfony/console/Helper/TableStyle.php b/vendor/symfony/console/Helper/TableStyle.php index d7e28ff2..2999c76f 100644 --- a/vendor/symfony/console/Helper/TableStyle.php +++ b/vendor/symfony/console/Helper/TableStyle.php @@ -37,7 +37,7 @@ class TableStyle * * @param string $paddingChar * - * @return TableStyle + * @return $this */ public function setPaddingChar($paddingChar) { @@ -65,7 +65,7 @@ class TableStyle * * @param string $horizontalBorderChar * - * @return TableStyle + * @return $this */ public function setHorizontalBorderChar($horizontalBorderChar) { @@ -89,7 +89,7 @@ class TableStyle * * @param string $verticalBorderChar * - * @return TableStyle + * @return $this */ public function setVerticalBorderChar($verticalBorderChar) { @@ -113,7 +113,7 @@ class TableStyle * * @param string $crossingChar * - * @return TableStyle + * @return $this */ public function setCrossingChar($crossingChar) { @@ -137,7 +137,7 @@ class TableStyle * * @param string $cellHeaderFormat * - * @return TableStyle + * @return $this */ public function setCellHeaderFormat($cellHeaderFormat) { @@ -161,7 +161,7 @@ class TableStyle * * @param string $cellRowFormat * - * @return TableStyle + * @return $this */ public function setCellRowFormat($cellRowFormat) { @@ -185,7 +185,7 @@ class TableStyle * * @param string $cellRowContentFormat * - * @return TableStyle + * @return $this */ public function setCellRowContentFormat($cellRowContentFormat) { @@ -209,7 +209,7 @@ class TableStyle * * @param string $borderFormat * - * @return TableStyle + * @return $this */ public function setBorderFormat($borderFormat) { @@ -233,7 +233,7 @@ class TableStyle * * @param int $padType STR_PAD_* * - * @return TableStyle + * @return $this */ public function setPadType($padType) { diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php index 02d4cdb3..b576cf42 100644 --- a/vendor/symfony/console/Input/ArgvInput.php +++ b/vendor/symfony/console/Input/ArgvInput.php @@ -44,10 +44,8 @@ class ArgvInput extends Input private $parsed; /** - * Constructor. - * - * @param array $argv An array of parameters from the CLI (in the argv format) - * @param InputDefinition $definition A InputDefinition instance + * @param array|null $argv An array of parameters from the CLI (in the argv format) + * @param InputDefinition|null $definition A InputDefinition instance */ public function __construct(array $argv = null, InputDefinition $definition = null) { @@ -69,7 +67,7 @@ class ArgvInput extends Input } /** - * Processes command line arguments. + * {@inheritdoc} */ protected function parse() { @@ -93,7 +91,7 @@ class ArgvInput extends Input /** * Parses a short option. * - * @param string $token The current token. + * @param string $token The current token */ private function parseShortOption($token) { @@ -147,7 +145,15 @@ class ArgvInput extends Input $name = substr($token, 2); if (false !== $pos = strpos($name, '=')) { - $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1)); + if (0 === strlen($value = substr($name, $pos + 1))) { + // if no value after "=" then substr() returns "" since php7 only, false before + // see http://php.net/manual/fr/migration70.incompatible.php#119151 + if (\PHP_VERSION_ID < 70000 && false === $value) { + $value = ''; + } + array_unshift($this->parsed, $value); + } + $this->addLongOption(substr($name, 0, $pos), $value); } else { $this->addLongOption($name, null); } @@ -176,7 +182,12 @@ class ArgvInput extends Input // unexpected argument } else { - throw new RuntimeException('Too many arguments.'); + $all = $this->definition->getArguments(); + if (count($all)) { + throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all)))); + } + + throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token)); } } @@ -213,23 +224,16 @@ class ArgvInput extends Input $option = $this->definition->getOption($name); - // Convert empty values to null - if (!isset($value[0])) { - $value = null; - } - if (null !== $value && !$option->acceptValue()) { throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); } - if (null === $value && $option->acceptValue() && count($this->parsed)) { + if (in_array($value, array('', null), true) && $option->acceptValue() && count($this->parsed)) { // if option accepts an optional or mandatory argument // let's see if there is one provided $next = array_shift($this->parsed); - if (isset($next[0]) && '-' !== $next[0]) { + if ((isset($next[0]) && '-' !== $next[0]) || in_array($next, array('', null), true)) { $value = $next; - } elseif (empty($next)) { - $value = ''; } else { array_unshift($this->parsed, $next); } @@ -240,8 +244,8 @@ class ArgvInput extends Input throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); } - if (!$option->isArray()) { - $value = $option->isValueOptional() ? $option->getDefault() : true; + if (!$option->isArray() && !$option->isValueOptional()) { + $value = true; } } @@ -253,9 +257,7 @@ class ArgvInput extends Input } /** - * Returns the first argument from the raw parameters (not parsed). - * - * @return string The value of the first argument or null otherwise + * {@inheritdoc} */ public function getFirstArgument() { @@ -269,24 +271,30 @@ class ArgvInput extends Input } /** - * Returns true if the raw parameters (not parsed) contain a value. - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * - * @return bool true if the value is contained in the raw parameters + * {@inheritdoc} */ - public function hasParameterOption($values) + public function hasParameterOption($values, $onlyParams = false) { $values = (array) $values; foreach ($this->tokens as $token) { + if ($onlyParams && '--' === $token) { + return false; + } foreach ($values as $value) { if ($token === $value || 0 === strpos($token, $value.'=')) { return true; } + + if (0 === strpos($token, '-') && 0 !== strpos($token, '--')) { + $noValue = explode('=', $token); + $token = $noValue[0]; + $searchableToken = str_replace('-', '', $token); + $searchableValue = str_replace('-', '', $value); + if ('' !== $searchableToken && '' !== $searchableValue && false !== strpos($searchableToken, $searchableValue)) { + return true; + } + } } } @@ -294,23 +302,18 @@ class ArgvInput extends Input } /** - * Returns the value of a raw option (not parsed). - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * @param mixed $default The default value to return if no result is found - * - * @return mixed The option value + * {@inheritdoc} */ - public function getParameterOption($values, $default = false) + public function getParameterOption($values, $default = false, $onlyParams = false) { $values = (array) $values; $tokens = $this->tokens; while (0 < count($tokens)) { $token = array_shift($tokens); + if ($onlyParams && '--' === $token) { + return false; + } foreach ($values as $value) { if ($token === $value || 0 === strpos($token, $value.'=')) { @@ -333,14 +336,13 @@ class ArgvInput extends Input */ public function __toString() { - $self = $this; - $tokens = array_map(function ($token) use ($self) { + $tokens = array_map(function ($token) { if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { - return $match[1].$self->escapeToken($match[2]); + return $match[1].$this->escapeToken($match[2]); } - if ($token && $token[0] !== '-') { - return $self->escapeToken($token); + if ($token && '-' !== $token[0]) { + return $this->escapeToken($token); } return $token; diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php index 8cedbb37..e6c28de9 100644 --- a/vendor/symfony/console/Input/ArrayInput.php +++ b/vendor/symfony/console/Input/ArrayInput.php @@ -27,12 +27,6 @@ class ArrayInput extends Input { private $parameters; - /** - * Constructor. - * - * @param array $parameters An array of parameters - * @param InputDefinition $definition A InputDefinition instance - */ public function __construct(array $parameters, InputDefinition $definition = null) { $this->parameters = $parameters; @@ -41,9 +35,7 @@ class ArrayInput extends Input } /** - * Returns the first argument from the raw parameters (not parsed). - * - * @return string The value of the first argument or null otherwise + * {@inheritdoc} */ public function getFirstArgument() { @@ -57,16 +49,9 @@ class ArrayInput extends Input } /** - * Returns true if the raw parameters (not parsed) contain a value. - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The values to look for in the raw parameters (can be an array) - * - * @return bool true if the value is contained in the raw parameters + * {@inheritdoc} */ - public function hasParameterOption($values) + public function hasParameterOption($values, $onlyParams = false) { $values = (array) $values; @@ -75,6 +60,10 @@ class ArrayInput extends Input $v = $k; } + if ($onlyParams && '--' === $v) { + return false; + } + if (in_array($v, $values)) { return true; } @@ -84,21 +73,17 @@ class ArrayInput extends Input } /** - * Returns the value of a raw option (not parsed). - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * @param mixed $default The default value to return if no result is found - * - * @return mixed The option value + * {@inheritdoc} */ - public function getParameterOption($values, $default = false) + public function getParameterOption($values, $default = false, $onlyParams = false) { $values = (array) $values; foreach ($this->parameters as $k => $v) { + if ($onlyParams && ('--' === $k || (is_int($k) && '--' === $v))) { + return false; + } + if (is_int($k)) { if (in_array($v, $values)) { return true; @@ -121,9 +106,15 @@ class ArrayInput extends Input $params = array(); foreach ($this->parameters as $param => $val) { if ($param && '-' === $param[0]) { - $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : ''); + if (is_array($val)) { + foreach ($val as $v) { + $params[] = $param.('' != $v ? '='.$this->escapeToken($v) : ''); + } + } else { + $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : ''); + } } else { - $params[] = $this->escapeToken($val); + $params[] = is_array($val) ? array_map(array($this, 'escapeToken'), $val) : $this->escapeToken($val); } } @@ -131,11 +122,14 @@ class ArrayInput extends Input } /** - * Processes command line arguments. + * {@inheritdoc} */ protected function parse() { foreach ($this->parameters as $key => $value) { + if ('--' === $key) { + return; + } if (0 === strpos($key, '--')) { $this->addLongOption(substr($key, 2), $value); } elseif ('-' === $key[0]) { @@ -185,7 +179,9 @@ class ArrayInput extends Input throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); } - $value = $option->isValueOptional() ? $option->getDefault() : true; + if (!$option->isValueOptional()) { + $value = true; + } } $this->options[$name] = $value; diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php index 85499fc4..41413252 100644 --- a/vendor/symfony/console/Input/Input.php +++ b/vendor/symfony/console/Input/Input.php @@ -25,21 +25,14 @@ use Symfony\Component\Console\Exception\RuntimeException; * * @author Fabien Potencier */ -abstract class Input implements InputInterface +abstract class Input implements InputInterface, StreamableInputInterface { - /** - * @var InputDefinition - */ protected $definition; + protected $stream; protected $options = array(); protected $arguments = array(); protected $interactive = true; - /** - * Constructor. - * - * @param InputDefinition $definition A InputDefinition instance - */ public function __construct(InputDefinition $definition = null) { if (null === $definition) { @@ -51,9 +44,7 @@ abstract class Input implements InputInterface } /** - * Binds the current Input instance with the given arguments and options. - * - * @param InputDefinition $definition A InputDefinition instance + * {@inheritdoc} */ public function bind(InputDefinition $definition) { @@ -70,9 +61,7 @@ abstract class Input implements InputInterface abstract protected function parse(); /** - * Validates the input. - * - * @throws RuntimeException When not enough arguments are given + * {@inheritdoc} */ public function validate() { @@ -89,9 +78,7 @@ abstract class Input implements InputInterface } /** - * Checks if the input is interactive. - * - * @return bool Returns true if the input is interactive + * {@inheritdoc} */ public function isInteractive() { @@ -99,9 +86,7 @@ abstract class Input implements InputInterface } /** - * Sets the input interactivity. - * - * @param bool $interactive If the input should be interactive + * {@inheritdoc} */ public function setInteractive($interactive) { @@ -109,9 +94,7 @@ abstract class Input implements InputInterface } /** - * Returns the argument values. - * - * @return array An array of argument values + * {@inheritdoc} */ public function getArguments() { @@ -119,13 +102,7 @@ abstract class Input implements InputInterface } /** - * Returns the argument value for a given argument name. - * - * @param string $name The argument name - * - * @return mixed The argument value - * - * @throws InvalidArgumentException When argument given doesn't exist + * {@inheritdoc} */ public function getArgument($name) { @@ -137,12 +114,7 @@ abstract class Input implements InputInterface } /** - * Sets an argument value by name. - * - * @param string $name The argument name - * @param string $value The argument value - * - * @throws InvalidArgumentException When argument given doesn't exist + * {@inheritdoc} */ public function setArgument($name, $value) { @@ -154,11 +126,7 @@ abstract class Input implements InputInterface } /** - * Returns true if an InputArgument object exists by name or position. - * - * @param string|int $name The InputArgument name or position - * - * @return bool true if the InputArgument object exists, false otherwise + * {@inheritdoc} */ public function hasArgument($name) { @@ -166,9 +134,7 @@ abstract class Input implements InputInterface } /** - * Returns the options values. - * - * @return array An array of option values + * {@inheritdoc} */ public function getOptions() { @@ -176,13 +142,7 @@ abstract class Input implements InputInterface } /** - * Returns the option value for a given option name. - * - * @param string $name The option name - * - * @return mixed The option value - * - * @throws InvalidArgumentException When option given doesn't exist + * {@inheritdoc} */ public function getOption($name) { @@ -190,16 +150,11 @@ abstract class Input implements InputInterface throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); } - return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + return array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } /** - * Sets an option value by name. - * - * @param string $name The option name - * @param string|bool $value The option value - * - * @throws InvalidArgumentException When option given doesn't exist + * {@inheritdoc} */ public function setOption($name, $value) { @@ -211,11 +166,7 @@ abstract class Input implements InputInterface } /** - * Returns true if an InputOption object exists by name. - * - * @param string $name The InputOption name - * - * @return bool true if the InputOption object exists, false otherwise + * {@inheritdoc} */ public function hasOption($name) { @@ -233,4 +184,20 @@ abstract class Input implements InputInterface { return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); } + + /** + * {@inheritdoc} + */ + public function setStream($stream) + { + $this->stream = $stream; + } + + /** + * {@inheritdoc} + */ + public function getStream() + { + return $this->stream; + } } diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php index 048ee4ff..a969d2c5 100644 --- a/vendor/symfony/console/Input/InputArgument.php +++ b/vendor/symfony/console/Input/InputArgument.php @@ -31,8 +31,6 @@ class InputArgument private $description; /** - * Constructor. - * * @param string $name The argument name * @param int $mode The argument mode: self::REQUIRED or self::OPTIONAL * @param string $description A description text diff --git a/vendor/symfony/console/Input/InputDefinition.php b/vendor/symfony/console/Input/InputDefinition.php index bd64163b..d5b99ab3 100644 --- a/vendor/symfony/console/Input/InputDefinition.php +++ b/vendor/symfony/console/Input/InputDefinition.php @@ -11,9 +11,6 @@ namespace Symfony\Component\Console\Input; -use Symfony\Component\Console\Descriptor\TextDescriptor; -use Symfony\Component\Console\Descriptor\XmlDescriptor; -use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; @@ -39,8 +36,6 @@ class InputDefinition private $shortcuts; /** - * Constructor. - * * @param array $definition An array of InputArgument and InputOption instance */ public function __construct(array $definition = array()) @@ -50,8 +45,6 @@ class InputDefinition /** * Sets the definition of the input. - * - * @param array $definition The definition array */ public function setDefinition(array $definition) { @@ -98,10 +91,6 @@ class InputDefinition } /** - * Adds an InputArgument object. - * - * @param InputArgument $argument An InputArgument object - * * @throws LogicException When incorrect argument is given */ public function addArgument(InputArgument $argument) @@ -235,10 +224,6 @@ class InputDefinition } /** - * Adds an InputOption object. - * - * @param InputOption $option An InputOption object - * * @throws LogicException When option given already exist */ public function addOption(InputOption $option) @@ -284,6 +269,9 @@ class InputDefinition /** * Returns true if an InputOption object exists by name. * + * This method can't be used to check if the user included the option when + * executing the command (use getOption() instead). + * * @param string $name The InputOption name * * @return bool true if the InputOption object exists, false otherwise @@ -318,7 +306,7 @@ class InputDefinition /** * Gets an InputOption by shortcut. * - * @param string $shortcut the Shortcut name + * @param string $shortcut The Shortcut name * * @return InputOption An InputOption object */ @@ -411,47 +399,4 @@ class InputDefinition return implode(' ', $elements); } - - /** - * Returns a textual representation of the InputDefinition. - * - * @return string A string representing the InputDefinition - * - * @deprecated since version 2.3, to be removed in 3.0. - */ - public function asText() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); - - $descriptor = new TextDescriptor(); - $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); - $descriptor->describe($output, $this, array('raw_output' => true)); - - return $output->fetch(); - } - - /** - * Returns an XML representation of the InputDefinition. - * - * @param bool $asDom Whether to return a DOM or an XML string - * - * @return string|\DOMDocument An XML string representing the InputDefinition - * - * @deprecated since version 2.3, to be removed in 3.0. - */ - public function asXml($asDom = false) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); - - $descriptor = new XmlDescriptor(); - - if ($asDom) { - return $descriptor->getInputDefinitionDocument($this); - } - - $output = new BufferedOutput(); - $descriptor->describe($output, $this); - - return $output->fetch(); - } } diff --git a/vendor/symfony/console/Input/InputInterface.php b/vendor/symfony/console/Input/InputInterface.php index f83b8856..e2412d71 100644 --- a/vendor/symfony/console/Input/InputInterface.php +++ b/vendor/symfony/console/Input/InputInterface.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Console\Input; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\RuntimeException; + /** * InputInterface is the interface implemented by all input classes. * @@ -31,11 +34,12 @@ interface InputInterface * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * - * @param string|array $values The values to look for in the raw parameters (can be an array) + * @param string|array $values The values to look for in the raw parameters (can be an array) + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal * * @return bool true if the value is contained in the raw parameters */ - public function hasParameterOption($values); + public function hasParameterOption($values, $onlyParams = false); /** * Returns the value of a raw option (not parsed). @@ -43,26 +47,23 @@ interface InputInterface * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * @param mixed $default The default value to return if no result is found + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal * * @return mixed The option value */ - public function getParameterOption($values, $default = false); + public function getParameterOption($values, $default = false, $onlyParams = false); /** * Binds the current Input instance with the given arguments and options. - * - * @param InputDefinition $definition A InputDefinition instance */ public function bind(InputDefinition $definition); /** - * Validates if arguments given are correct. + * Validates the input. * - * Throws an exception when not enough arguments are given. - * - * @throws \RuntimeException + * @throws RuntimeException When not enough arguments are given */ public function validate(); @@ -74,11 +75,13 @@ interface InputInterface public function getArguments(); /** - * Gets argument by name. + * Returns the argument value for a given argument name. + * + * @param string $name The argument name * - * @param string $name The name of the argument + * @return mixed The argument value * - * @return mixed + * @throws InvalidArgumentException When argument given doesn't exist */ public function getArgument($name); @@ -109,11 +112,13 @@ interface InputInterface public function getOptions(); /** - * Gets an option by name. + * Returns the option value for a given option name. + * + * @param string $name The option name * - * @param string $name The name of the option + * @return mixed The option value * - * @return mixed + * @throws InvalidArgumentException When option given doesn't exist */ public function getOption($name); diff --git a/vendor/symfony/console/Input/InputOption.php b/vendor/symfony/console/Input/InputOption.php index f08c5f26..3af8077c 100644 --- a/vendor/symfony/console/Input/InputOption.php +++ b/vendor/symfony/console/Input/InputOption.php @@ -33,8 +33,6 @@ class InputOption private $description; /** - * Constructor. - * * @param string $name The option name * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int $mode The option mode: One of the VALUE_* constants @@ -195,8 +193,6 @@ class InputOption /** * Checks whether the given option equals this one. * - * @param InputOption $option option to compare - * * @return bool */ public function equals(InputOption $option) diff --git a/vendor/symfony/console/Input/StreamableInputInterface.php b/vendor/symfony/console/Input/StreamableInputInterface.php new file mode 100644 index 00000000..d7e462f2 --- /dev/null +++ b/vendor/symfony/console/Input/StreamableInputInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * StreamableInputInterface is the interface implemented by all input classes + * that have an input stream. + * + * @author Robin Chalas + */ +interface StreamableInputInterface extends InputInterface +{ + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + */ + public function setStream($stream); + + /** + * Returns the input stream. + * + * @return resource|null + */ + public function getStream(); +} diff --git a/vendor/symfony/console/Input/StringInput.php b/vendor/symfony/console/Input/StringInput.php index a40ddba3..d3630fc0 100644 --- a/vendor/symfony/console/Input/StringInput.php +++ b/vendor/symfony/console/Input/StringInput.php @@ -28,26 +28,13 @@ class StringInput extends ArgvInput const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')'; /** - * Constructor. - * - * @param string $input An array of parameters from the CLI (in the argv format) - * @param InputDefinition $definition A InputDefinition instance - * - * @deprecated The second argument is deprecated as it does not work (will be removed in 3.0), use 'bind' method instead + * @param string $input An array of parameters from the CLI (in the argv format) */ - public function __construct($input, InputDefinition $definition = null) + public function __construct($input) { - if ($definition) { - @trigger_error('The $definition argument of the '.__METHOD__.' method is deprecated and will be removed in 3.0. Set this parameter with the bind() method instead.', E_USER_DEPRECATED); - } - - parent::__construct(array(), null); + parent::__construct(array()); $this->setTokens($this->tokenize($input)); - - if (null !== $definition) { - $this->bind($definition); - } } /** diff --git a/vendor/symfony/console/LICENSE b/vendor/symfony/console/LICENSE index 12a74531..17d16a13 100644 --- a/vendor/symfony/console/LICENSE +++ b/vendor/symfony/console/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2016 Fabien Potencier +Copyright (c) 2004-2017 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/console/Logger/ConsoleLogger.php b/vendor/symfony/console/Logger/ConsoleLogger.php index 1f7417ea..05dd3b96 100644 --- a/vendor/symfony/console/Logger/ConsoleLogger.php +++ b/vendor/symfony/console/Logger/ConsoleLogger.php @@ -22,20 +22,14 @@ use Symfony\Component\Console\Output\ConsoleOutputInterface; * * @author Kévin Dunglas * - * @link http://www.php-fig.org/psr/psr-3/ + * @see http://www.php-fig.org/psr/psr-3/ */ class ConsoleLogger extends AbstractLogger { const INFO = 'info'; const ERROR = 'error'; - /** - * @var OutputInterface - */ private $output; - /** - * @var array - */ private $verbosityLevelMap = array( LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, @@ -46,9 +40,6 @@ class ConsoleLogger extends AbstractLogger LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG, ); - /** - * @var array - */ private $formatLevelMap = array( LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, @@ -59,12 +50,8 @@ class ConsoleLogger extends AbstractLogger LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO, ); + private $errored = false; - /** - * @param OutputInterface $output - * @param array $verbosityLevelMap - * @param array $formatLevelMap - */ public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array()) { $this->output = $output; @@ -81,18 +68,33 @@ class ConsoleLogger extends AbstractLogger throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); } + $output = $this->output; + // Write to the error output if necessary and available - if ($this->formatLevelMap[$level] === self::ERROR && $this->output instanceof ConsoleOutputInterface) { - $output = $this->output->getErrorOutput(); - } else { - $output = $this->output; + if (self::ERROR === $this->formatLevelMap[$level]) { + if ($this->output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $this->errored = true; } + // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. + // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { - $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context))); + $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } + /** + * Returns true when any messages have been logged at error levels. + * + * @return bool + */ + public function hasErrored() + { + return $this->errored; + } + /** * Interpolates context values into the message placeholders. * @@ -105,15 +107,23 @@ class ConsoleLogger extends AbstractLogger */ private function interpolate($message, array $context) { - // build a replacement array with braces around the context keys - $replace = array(); + if (false === strpos($message, '{')) { + return $message; + } + + $replacements = array(); foreach ($context as $key => $val) { - if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) { - $replace[sprintf('{%s}', $key)] = $val; + if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) { + $replacements["{{$key}}"] = $val; + } elseif ($val instanceof \DateTimeInterface) { + $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339); + } elseif (\is_object($val)) { + $replacements["{{$key}}"] = '[object '.\get_class($val).']'; + } else { + $replacements["{{$key}}"] = '['.\gettype($val).']'; } } - // interpolate replacement values into the message and return - return strtr($message, $replace); + return strtr($message, $replacements); } } diff --git a/vendor/symfony/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php index 5682fc24..8afc8931 100644 --- a/vendor/symfony/console/Output/BufferedOutput.php +++ b/vendor/symfony/console/Output/BufferedOutput.php @@ -16,9 +16,6 @@ namespace Symfony\Component\Console\Output; */ class BufferedOutput extends Output { - /** - * @var string - */ private $buffer = ''; /** @@ -42,7 +39,7 @@ class BufferedOutput extends Output $this->buffer .= $message; if ($newline) { - $this->buffer .= "\n"; + $this->buffer .= PHP_EOL; } } } diff --git a/vendor/symfony/console/Output/ConsoleOutput.php b/vendor/symfony/console/Output/ConsoleOutput.php index f666c793..edef356c 100644 --- a/vendor/symfony/console/Output/ConsoleOutput.php +++ b/vendor/symfony/console/Output/ConsoleOutput.php @@ -14,28 +14,24 @@ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** - * ConsoleOutput is the default class for all CLI output. It uses STDOUT. + * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. * - * This class is a convenient wrapper around `StreamOutput`. + * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. * * $output = new ConsoleOutput(); * * This is equivalent to: * * $output = new StreamOutput(fopen('php://stdout', 'w')); + * $stdErr = new StreamOutput(fopen('php://stderr', 'w')); * * @author Fabien Potencier */ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface { - /** - * @var StreamOutput - */ private $stderr; /** - * Constructor. - * * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) @@ -139,9 +135,11 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface */ private function openOutputStream() { - $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output'; + if (!$this->hasStdoutSupport()) { + return fopen('php://output', 'w'); + } - return @fopen($outputStream, 'w') ?: fopen('php://output', 'w'); + return @fopen('php://stdout', 'w') ?: fopen('php://output', 'w'); } /** @@ -149,8 +147,6 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface */ private function openErrorStream() { - $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output'; - - return fopen($errorStream, 'w'); + return fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w'); } } diff --git a/vendor/symfony/console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Output/ConsoleOutputInterface.php index 5eb4fc7a..b44ea7e0 100644 --- a/vendor/symfony/console/Output/ConsoleOutputInterface.php +++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php @@ -26,10 +26,5 @@ interface ConsoleOutputInterface extends OutputInterface */ public function getErrorOutput(); - /** - * Sets the OutputInterface used for errors. - * - * @param OutputInterface $error - */ public function setErrorOutput(OutputInterface $error); } diff --git a/vendor/symfony/console/Output/NullOutput.php b/vendor/symfony/console/Output/NullOutput.php index 682f9a4d..218f285b 100644 --- a/vendor/symfony/console/Output/NullOutput.php +++ b/vendor/symfony/console/Output/NullOutput.php @@ -73,21 +73,33 @@ class NullOutput implements OutputInterface return self::VERBOSITY_QUIET; } + /** + * {@inheritdoc} + */ public function isQuiet() { return true; } + /** + * {@inheritdoc} + */ public function isVerbose() { return false; } + /** + * {@inheritdoc} + */ public function isVeryVerbose() { return false; } + /** + * {@inheritdoc} + */ public function isDebug() { return false; diff --git a/vendor/symfony/console/Output/Output.php b/vendor/symfony/console/Output/Output.php index 4476ffb5..371735e1 100644 --- a/vendor/symfony/console/Output/Output.php +++ b/vendor/symfony/console/Output/Output.php @@ -33,8 +33,6 @@ abstract class Output implements OutputInterface private $formatter; /** - * Constructor. - * * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool $decorated Whether to decorate messages * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) @@ -94,21 +92,33 @@ abstract class Output implements OutputInterface return $this->verbosity; } + /** + * {@inheritdoc} + */ public function isQuiet() { return self::VERBOSITY_QUIET === $this->verbosity; } + /** + * {@inheritdoc} + */ public function isVerbose() { return self::VERBOSITY_VERBOSE <= $this->verbosity; } + /** + * {@inheritdoc} + */ public function isVeryVerbose() { return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; } + /** + * {@inheritdoc} + */ public function isDebug() { return self::VERBOSITY_DEBUG <= $this->verbosity; diff --git a/vendor/symfony/console/Output/OutputInterface.php b/vendor/symfony/console/Output/OutputInterface.php index 9a8290bd..cddfbb49 100644 --- a/vendor/symfony/console/Output/OutputInterface.php +++ b/vendor/symfony/console/Output/OutputInterface.php @@ -61,6 +61,34 @@ interface OutputInterface */ public function getVerbosity(); + /** + * Returns whether verbosity is quiet (-q). + * + * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise + */ + public function isQuiet(); + + /** + * Returns whether verbosity is verbose (-v). + * + * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise + */ + public function isVerbose(); + + /** + * Returns whether verbosity is very verbose (-vv). + * + * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise + */ + public function isVeryVerbose(); + + /** + * Returns whether verbosity is debug (-vvv). + * + * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise + */ + public function isDebug(); + /** * Sets the decorated flag. * @@ -75,11 +103,6 @@ interface OutputInterface */ public function isDecorated(); - /** - * Sets output formatter. - * - * @param OutputFormatterInterface $formatter - */ public function setFormatter(OutputFormatterInterface $formatter); /** diff --git a/vendor/symfony/console/Output/StreamOutput.php b/vendor/symfony/console/Output/StreamOutput.php index 9e6b7481..51cad9b1 100644 --- a/vendor/symfony/console/Output/StreamOutput.php +++ b/vendor/symfony/console/Output/StreamOutput.php @@ -33,8 +33,6 @@ class StreamOutput extends Output private $stream; /** - * Constructor. - * * @param resource $stream A stream resource * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) @@ -85,7 +83,7 @@ class StreamOutput extends Output * * Colorization is disabled if not supported by the stream: * - * - Windows before 10.0.10586 without Ansicon, ConEmu or Mintty + * - Windows != 10.0.10586 without Ansicon, ConEmu or Mintty * - non tty consoles * * @return bool true if the stream supports colorization, false otherwise @@ -94,7 +92,7 @@ class StreamOutput extends Output { if (DIRECTORY_SEPARATOR === '\\') { return - 0 >= version_compare('10.0.10586', PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD) + '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); diff --git a/vendor/symfony/console/Question/ChoiceQuestion.php b/vendor/symfony/console/Question/ChoiceQuestion.php index 2c40638d..46cc72a3 100644 --- a/vendor/symfony/console/Question/ChoiceQuestion.php +++ b/vendor/symfony/console/Question/ChoiceQuestion.php @@ -26,14 +26,16 @@ class ChoiceQuestion extends Question private $errorMessage = 'Value "%s" is invalid'; /** - * Constructor. - * * @param string $question The question to ask to the user * @param array $choices The list of available choices * @param mixed $default The default answer to return */ public function __construct($question, array $choices, $default = null) { + if (!$choices) { + throw new \LogicException('Choice question must have at least 1 choice available.'); + } + parent::__construct($question, $default); $this->choices = $choices; @@ -58,7 +60,7 @@ class ChoiceQuestion extends Question * * @param bool $multiselect * - * @return ChoiceQuestion The current instance + * @return $this */ public function setMultiselect($multiselect) { @@ -68,6 +70,16 @@ class ChoiceQuestion extends Question return $this; } + /** + * Returns whether the choices are multiselect. + * + * @return bool + */ + public function isMultiselect() + { + return $this->multiselect; + } + /** * Gets the prompt for choices. * @@ -83,7 +95,7 @@ class ChoiceQuestion extends Question * * @param string $prompt * - * @return ChoiceQuestion The current instance + * @return $this */ public function setPrompt($prompt) { @@ -99,7 +111,7 @@ class ChoiceQuestion extends Question * * @param string $errorMessage * - * @return ChoiceQuestion The current instance + * @return $this */ public function setErrorMessage($errorMessage) { @@ -127,7 +139,7 @@ class ChoiceQuestion extends Question if ($multiselect) { // Check for a separated comma values - if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) { + if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selectedChoices, $matches)) { throw new InvalidArgumentException(sprintf($errorMessage, $selected)); } $selectedChoices = explode(',', $selectedChoices); diff --git a/vendor/symfony/console/Question/ConfirmationQuestion.php b/vendor/symfony/console/Question/ConfirmationQuestion.php index 29d98879..40f54b4e 100644 --- a/vendor/symfony/console/Question/ConfirmationQuestion.php +++ b/vendor/symfony/console/Question/ConfirmationQuestion.php @@ -21,8 +21,6 @@ class ConfirmationQuestion extends Question private $trueAnswerRegex; /** - * Constructor. - * * @param string $question The question to ask to the user * @param bool $default The default answer to return, true or false * @param string $trueAnswerRegex A regex to match the "yes" answer diff --git a/vendor/symfony/console/Question/Question.php b/vendor/symfony/console/Question/Question.php index ab415c26..63afbc4c 100644 --- a/vendor/symfony/console/Question/Question.php +++ b/vendor/symfony/console/Question/Question.php @@ -31,8 +31,6 @@ class Question private $normalizer; /** - * Constructor. - * * @param string $question The question to ask to the user * @param mixed $default The default answer to return if the user enters nothing */ @@ -77,7 +75,7 @@ class Question * * @param bool $hidden * - * @return Question The current instance + * @return $this * * @throws LogicException In case the autocompleter is also used */ @@ -107,7 +105,7 @@ class Question * * @param bool $fallback * - * @return Question The current instance + * @return $this */ public function setHiddenFallback($fallback) { @@ -119,7 +117,7 @@ class Question /** * Gets values for the autocompleter. * - * @return null|array|\Traversable + * @return null|iterable */ public function getAutocompleterValues() { @@ -129,9 +127,9 @@ class Question /** * Sets values for the autocompleter. * - * @param null|array|\Traversable $values + * @param null|iterable $values * - * @return Question The current instance + * @return $this * * @throws InvalidArgumentException * @throws LogicException @@ -142,10 +140,8 @@ class Question $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values); } - if (null !== $values && !is_array($values)) { - if (!$values instanceof \Traversable || !$values instanceof \Countable) { - throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.'); - } + if (null !== $values && !is_array($values) && !$values instanceof \Traversable) { + throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or a `Traversable` object.'); } if ($this->hidden) { @@ -162,9 +158,9 @@ class Question * * @param null|callable $validator * - * @return Question The current instance + * @return $this */ - public function setValidator($validator) + public function setValidator(callable $validator = null) { $this->validator = $validator; @@ -188,9 +184,9 @@ class Question * * @param null|int $attempts * - * @return Question The current instance + * @return $this * - * @throws InvalidArgumentException In case the number of attempts is invalid. + * @throws InvalidArgumentException in case the number of attempts is invalid */ public function setMaxAttempts($attempts) { @@ -222,9 +218,9 @@ class Question * * @param callable $normalizer * - * @return Question The current instance + * @return $this */ - public function setNormalizer($normalizer) + public function setNormalizer(callable $normalizer) { $this->normalizer = $normalizer; diff --git a/vendor/symfony/console/Shell.php b/vendor/symfony/console/Shell.php deleted file mode 100644 index dacdf223..00000000 --- a/vendor/symfony/console/Shell.php +++ /dev/null @@ -1,233 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console; - -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Input\StringInput; -use Symfony\Component\Console\Output\ConsoleOutput; -use Symfony\Component\Process\ProcessBuilder; -use Symfony\Component\Process\PhpExecutableFinder; - -/** - * A Shell wraps an Application to add shell capabilities to it. - * - * Support for history and completion only works with a PHP compiled - * with readline support (either --with-readline or --with-libedit) - * - * @deprecated since version 2.8, to be removed in 3.0. - * - * @author Fabien Potencier - * @author Martin Hasoň - */ -class Shell -{ - private $application; - private $history; - private $output; - private $hasReadline; - private $processIsolation = false; - - /** - * Constructor. - * - * If there is no readline support for the current PHP executable - * a \RuntimeException exception is thrown. - * - * @param Application $application An application instance - */ - public function __construct(Application $application) - { - @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - - $this->hasReadline = function_exists('readline'); - $this->application = $application; - $this->history = getenv('HOME').'/.history_'.$application->getName(); - $this->output = new ConsoleOutput(); - } - - /** - * Runs the shell. - */ - public function run() - { - $this->application->setAutoExit(false); - $this->application->setCatchExceptions(true); - - if ($this->hasReadline) { - readline_read_history($this->history); - readline_completion_function(array($this, 'autocompleter')); - } - - $this->output->writeln($this->getHeader()); - $php = null; - if ($this->processIsolation) { - $finder = new PhpExecutableFinder(); - $php = $finder->find(); - $this->output->writeln(<<<'EOF' -Running with process isolation, you should consider this: - * each command is executed as separate process, - * commands don't support interactivity, all params must be passed explicitly, - * commands output is not colorized. - -EOF - ); - } - - while (true) { - $command = $this->readline(); - - if (false === $command) { - $this->output->writeln("\n"); - - break; - } - - if ($this->hasReadline) { - readline_add_history($command); - readline_write_history($this->history); - } - - if ($this->processIsolation) { - $pb = new ProcessBuilder(); - - $process = $pb - ->add($php) - ->add($_SERVER['argv'][0]) - ->add($command) - ->inheritEnvironmentVariables(true) - ->getProcess() - ; - - $output = $this->output; - $process->run(function ($type, $data) use ($output) { - $output->writeln($data); - }); - - $ret = $process->getExitCode(); - } else { - $ret = $this->application->run(new StringInput($command), $this->output); - } - - if (0 !== $ret) { - $this->output->writeln(sprintf('The command terminated with an error status (%s)', $ret)); - } - } - } - - /** - * Returns the shell header. - * - * @return string The header string - */ - protected function getHeader() - { - return <<{$this->application->getName()} shell ({$this->application->getVersion()}). - -At the prompt, type help for some help, -or list to get a list of available commands. - -To exit the shell, type ^D. - -EOF; - } - - /** - * Renders a prompt. - * - * @return string The prompt - */ - protected function getPrompt() - { - // using the formatter here is required when using readline - return $this->output->getFormatter()->format($this->application->getName().' > '); - } - - protected function getOutput() - { - return $this->output; - } - - protected function getApplication() - { - return $this->application; - } - - /** - * Tries to return autocompletion for the current entered text. - * - * @param string $text The last segment of the entered text - * - * @return bool|array A list of guessed strings or true - */ - private function autocompleter($text) - { - $info = readline_info(); - $text = substr($info['line_buffer'], 0, $info['end']); - - if ($info['point'] !== $info['end']) { - return true; - } - - // task name? - if (false === strpos($text, ' ') || !$text) { - return array_keys($this->application->all()); - } - - // options and arguments? - try { - $command = $this->application->find(substr($text, 0, strpos($text, ' '))); - } catch (\Exception $e) { - return true; - } - - $list = array('--help'); - foreach ($command->getDefinition()->getOptions() as $option) { - $list[] = '--'.$option->getName(); - } - - return $list; - } - - /** - * Reads a single line from standard input. - * - * @return string The single line from standard input - */ - private function readline() - { - if ($this->hasReadline) { - $line = readline($this->getPrompt()); - } else { - $this->output->write($this->getPrompt()); - $line = fgets(STDIN, 1024); - $line = (false === $line || '' === $line) ? false : rtrim($line); - } - - return $line; - } - - public function getProcessIsolation() - { - return $this->processIsolation; - } - - public function setProcessIsolation($processIsolation) - { - $this->processIsolation = (bool) $processIsolation; - - if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) { - throw new RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.'); - } - } -} diff --git a/vendor/symfony/console/Style/OutputStyle.php b/vendor/symfony/console/Style/OutputStyle.php index 8371bb53..ad886411 100644 --- a/vendor/symfony/console/Style/OutputStyle.php +++ b/vendor/symfony/console/Style/OutputStyle.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Style; use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; /** * Decorates output to add console style guide helpers. @@ -24,9 +25,6 @@ abstract class OutputStyle implements OutputInterface, StyleInterface { private $output; - /** - * @param OutputInterface $output - */ public function __construct(OutputInterface $output) { $this->output = $output; @@ -113,4 +111,45 @@ abstract class OutputStyle implements OutputInterface, StyleInterface { return $this->output->getFormatter(); } + + /** + * {@inheritdoc} + */ + public function isQuiet() + { + return $this->output->isQuiet(); + } + + /** + * {@inheritdoc} + */ + public function isVerbose() + { + return $this->output->isVerbose(); + } + + /** + * {@inheritdoc} + */ + public function isVeryVerbose() + { + return $this->output->isVeryVerbose(); + } + + /** + * {@inheritdoc} + */ + public function isDebug() + { + return $this->output->isDebug(); + } + + protected function getErrorOutput() + { + if (!$this->output instanceof ConsoleOutputInterface) { + return $this->output; + } + + return $this->output->getErrorOutput(); + } } diff --git a/vendor/symfony/console/Style/StyleInterface.php b/vendor/symfony/console/Style/StyleInterface.php index 2448547f..a9205e5a 100644 --- a/vendor/symfony/console/Style/StyleInterface.php +++ b/vendor/symfony/console/Style/StyleInterface.php @@ -34,8 +34,6 @@ interface StyleInterface /** * Formats a list. - * - * @param array $elements */ public function listing(array $elements); @@ -83,9 +81,6 @@ interface StyleInterface /** * Formats a table. - * - * @param array $headers - * @param array $rows */ public function table(array $headers, array $rows); diff --git a/vendor/symfony/console/Style/SymfonyStyle.php b/vendor/symfony/console/Style/SymfonyStyle.php index 53a7951e..3717f880 100644 --- a/vendor/symfony/console/Style/SymfonyStyle.php +++ b/vendor/symfony/console/Style/SymfonyStyle.php @@ -11,20 +11,19 @@ namespace Symfony\Component\Console\Style; -use Symfony\Component\Console\Application; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\SymfonyQuestionHelper; use Symfony\Component\Console\Helper\Table; -use Symfony\Component\Console\Helper\TableCell; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Terminal; /** * Output decorator helpers for the Symfony Style Guide. @@ -41,16 +40,13 @@ class SymfonyStyle extends OutputStyle private $lineLength; private $bufferedOutput; - /** - * @param InputInterface $input - * @param OutputInterface $output - */ public function __construct(InputInterface $input, OutputInterface $output) { $this->input = $input; $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. - $this->lineLength = min($this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); + $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; + $this->lineLength = min($width - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); parent::__construct($output); } @@ -63,56 +59,14 @@ class SymfonyStyle extends OutputStyle * @param string|null $style The style to apply to the whole block * @param string $prefix The prefix for the block * @param bool $padding Whether to add vertical padding + * @param bool $escape Whether to escape the message */ - public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) + public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = true) { - $this->autoPrependBlock(); $messages = is_array($messages) ? array_values($messages) : array($messages); - $indentLength = 0; - $lines = array(); - - if (null !== $type) { - $typePrefix = sprintf('[%s] ', $type); - $indentLength = strlen($typePrefix); - $lineIndentation = str_repeat(' ', $indentLength); - } - - // wrap and add newlines for each element - foreach ($messages as $key => $message) { - $message = OutputFormatter::escape($message); - $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix) - $indentLength, PHP_EOL, true))); - - // prefix each line with a number of spaces equivalent to the type length - if (null !== $type) { - foreach ($lines as &$line) { - $line = $lineIndentation === substr($line, 0, $indentLength) ? $line : $lineIndentation.$line; - } - } - if (count($messages) > 1 && $key < count($messages) - 1) { - $lines[] = ''; - } - } - - if (null !== $type) { - $lines[0] = substr_replace($lines[0], $typePrefix, 0, $indentLength); - } - - if ($padding && $this->isDecorated()) { - array_unshift($lines, ''); - $lines[] = ''; - } - - foreach ($lines as &$line) { - $line = sprintf('%s%s', $prefix, $line); - $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line)); - - if ($style) { - $line = sprintf('<%s>%s', $style, $line); - } - } - - $this->writeln($lines); + $this->autoPrependBlock(); + $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape)); $this->newLine(); } @@ -123,7 +77,7 @@ class SymfonyStyle extends OutputStyle { $this->autoPrependBlock(); $this->writeln(array( - sprintf('%s', $message), + sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), sprintf('%s', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))), )); $this->newLine(); @@ -136,7 +90,7 @@ class SymfonyStyle extends OutputStyle { $this->autoPrependBlock(); $this->writeln(array( - sprintf('%s', $message), + sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), sprintf('%s', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))), )); $this->newLine(); @@ -176,12 +130,7 @@ class SymfonyStyle extends OutputStyle */ public function comment($message) { - $messages = is_array($message) ? array_values($message) : array($message); - foreach ($messages as &$message) { - $message = $this->getFormatter()->format($message); - } - - $this->block($messages, null, null, ' // '); + $this->block($message, null, null, ' // ', false, false); } /** @@ -229,21 +178,13 @@ class SymfonyStyle extends OutputStyle */ public function table(array $headers, array $rows) { - array_walk_recursive($headers, function (&$value) { - if ($value instanceof TableCell) { - $value = new TableCell(sprintf('%s', $value), array( - 'colspan' => $value->getColspan(), - 'rowspan' => $value->getRowspan(), - )); - } else { - $value = sprintf('%s', $value); - } - }); + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); $table = new Table($this); $table->setHeaders($headers); $table->setRows($rows); - $table->setStyle('symfony-style-guide'); + $table->setStyle($style); $table->render(); $this->newLine(); @@ -338,8 +279,6 @@ class SymfonyStyle extends OutputStyle } /** - * @param Question $question - * * @return string */ public function askQuestion(Question $question) @@ -389,6 +328,16 @@ class SymfonyStyle extends OutputStyle $this->bufferedOutput->write(str_repeat("\n", $count)); } + /** + * Returns a new instance which makes use of stderr if available. + * + * @return self + */ + public function getErrorStyle() + { + return new self($this->input, $this->getErrorOutput()); + } + /** * @return ProgressBar */ @@ -401,14 +350,6 @@ class SymfonyStyle extends OutputStyle return $this->progressBar; } - private function getTerminalWidth() - { - $application = new Application(); - $dimensions = $application->getTerminalDimensions(); - - return $dimensions[0] ?: self::MAX_LINE_LENGTH; - } - private function autoPrependBlock() { $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); @@ -437,4 +378,52 @@ class SymfonyStyle extends OutputStyle return substr($value, -4); }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages)); } + + private function createBlock($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = false) + { + $indentLength = 0; + $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix); + $lines = array(); + + if (null !== $type) { + $type = sprintf('[%s] ', $type); + $indentLength = strlen($type); + $lineIndentation = str_repeat(' ', $indentLength); + } + + // wrap and add newlines for each element + foreach ($messages as $key => $message) { + if ($escape) { + $message = OutputFormatter::escape($message); + } + + $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true))); + + if (count($messages) > 1 && $key < count($messages) - 1) { + $lines[] = ''; + } + } + + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + array_unshift($lines, ''); + $lines[] = ''; + } + + foreach ($lines as $i => &$line) { + if (null !== $type) { + $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; + } + + $line = $prefix.$line; + $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line)); + + if ($style) { + $line = sprintf('<%s>%s', $style, $line); + } + } + + return $lines; + } } diff --git a/vendor/symfony/console/Terminal.php b/vendor/symfony/console/Terminal.php new file mode 100644 index 00000000..927dfc4d --- /dev/null +++ b/vendor/symfony/console/Terminal.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +class Terminal +{ + private static $width; + private static $height; + + /** + * Gets the terminal width. + * + * @return int + */ + public function getWidth() + { + $width = getenv('COLUMNS'); + if (false !== $width) { + return (int) trim($width); + } + + if (null === self::$width) { + self::initDimensions(); + } + + return self::$width ?: 80; + } + + /** + * Gets the terminal height. + * + * @return int + */ + public function getHeight() + { + $height = getenv('LINES'); + if (false !== $height) { + return (int) trim($height); + } + + if (null === self::$height) { + self::initDimensions(); + } + + return self::$height ?: 50; + } + + private static function initDimensions() + { + if ('\\' === DIRECTORY_SEPARATOR) { + if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) { + // extract [w, H] from "wxh (WxH)" + // or [w, h] from "wxh" + self::$width = (int) $matches[1]; + self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; + } elseif (null !== $dimensions = self::getConsoleMode()) { + // extract [w, h] from "wxh" + self::$width = (int) $dimensions[0]; + self::$height = (int) $dimensions[1]; + } + } elseif ($sttyString = self::getSttyColumns()) { + if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { + // extract [w, h] from "rows h; columns w;" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { + // extract [w, h] from "; h rows; w columns" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } + } + } + + /** + * Runs and parses mode CON if it's available, suppressing any error output. + * + * @return int[]|null An array composed of the width and the height or null if it could not be parsed + */ + private static function getConsoleMode() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array( + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ); + $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { + return array((int) $matches[2], (int) $matches[1]); + } + } + } + + /** + * Runs and parses stty -a if it's available, suppressing any error output. + * + * @return string|null + */ + private static function getSttyColumns() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array( + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ); + + $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + return $info; + } + } +} diff --git a/vendor/symfony/console/Tester/ApplicationTester.php b/vendor/symfony/console/Tester/ApplicationTester.php index da8a19ce..c0f8c720 100644 --- a/vendor/symfony/console/Tester/ApplicationTester.php +++ b/vendor/symfony/console/Tester/ApplicationTester.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Tester; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\StreamOutput; @@ -31,14 +32,13 @@ class ApplicationTester { private $application; private $input; - private $output; private $statusCode; - /** - * Constructor. - * - * @param Application $application An Application instance to test. + * @var OutputInterface */ + private $output; + private $captureStreamsIndependently = false; + public function __construct(Application $application) { $this->application = $application; @@ -49,9 +49,10 @@ class ApplicationTester * * Available options: * - * * interactive: Sets the input interactive flag - * * decorated: Sets the output decorated flag - * * verbosity: Sets the output verbosity flag + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available * * @param array $input An array of arguments and options * @param array $options An array of options @@ -65,12 +66,35 @@ class ApplicationTester $this->input->setInteractive($options['interactive']); } - $this->output = new StreamOutput(fopen('php://memory', 'w', false)); - if (isset($options['decorated'])) { - $this->output->setDecorated($options['decorated']); - } - if (isset($options['verbosity'])) { - $this->output->setVerbosity($options['verbosity']); + $this->captureStreamsIndependently = array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; + if (!$this->captureStreamsIndependently) { + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + } else { + $this->output = new ConsoleOutput( + isset($options['verbosity']) ? $options['verbosity'] : ConsoleOutput::VERBOSITY_NORMAL, + isset($options['decorated']) ? $options['decorated'] : null + ); + + $errorOutput = new StreamOutput(fopen('php://memory', 'w', false)); + $errorOutput->setFormatter($this->output->getFormatter()); + $errorOutput->setVerbosity($this->output->getVerbosity()); + $errorOutput->setDecorated($this->output->isDecorated()); + + $reflectedOutput = new \ReflectionObject($this->output); + $strErrProperty = $reflectedOutput->getProperty('stderr'); + $strErrProperty->setAccessible(true); + $strErrProperty->setValue($this->output, $errorOutput); + + $reflectedParent = $reflectedOutput->getParentClass(); + $streamProperty = $reflectedParent->getProperty('stream'); + $streamProperty->setAccessible(true); + $streamProperty->setValue($this->output, fopen('php://memory', 'w', false)); } return $this->statusCode = $this->application->run($this->input, $this->output); @@ -96,6 +120,30 @@ class ApplicationTester return $display; } + /** + * Gets the output written to STDERR by the application. + * + * @param bool $normalize Whether to normalize end of lines to \n or not + * + * @return string + */ + public function getErrorOutput($normalize = false) + { + if (!$this->captureStreamsIndependently) { + throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.'); + } + + rewind($this->output->getErrorOutput()->getStream()); + + $display = stream_get_contents($this->output->getErrorOutput()->getStream()); + + if ($normalize) { + $display = str_replace(PHP_EOL, "\n", $display); + } + + return $display; + } + /** * Gets the input instance used by the last execution of the application. * diff --git a/vendor/symfony/console/Tester/CommandTester.php b/vendor/symfony/console/Tester/CommandTester.php index 8d6486e1..39723b26 100644 --- a/vendor/symfony/console/Tester/CommandTester.php +++ b/vendor/symfony/console/Tester/CommandTester.php @@ -21,19 +21,16 @@ use Symfony\Component\Console\Output\OutputInterface; * Eases the testing of console commands. * * @author Fabien Potencier + * @author Robin Chalas */ class CommandTester { private $command; private $input; private $output; + private $inputs = array(); private $statusCode; - /** - * Constructor. - * - * @param Command $command A Command instance to test. - */ public function __construct(Command $command) { $this->command = $command; @@ -65,14 +62,16 @@ class CommandTester } $this->input = new ArrayInput($input); + if ($this->inputs) { + $this->input->setStream(self::createStream($this->inputs)); + } + if (isset($options['interactive'])) { $this->input->setInteractive($options['interactive']); } $this->output = new StreamOutput(fopen('php://memory', 'w', false)); - if (isset($options['decorated'])) { - $this->output->setDecorated($options['decorated']); - } + $this->output->setDecorated(isset($options['decorated']) ? $options['decorated'] : false); if (isset($options['verbosity'])) { $this->output->setVerbosity($options['verbosity']); } @@ -129,4 +128,29 @@ class CommandTester { return $this->statusCode; } + + /** + * Sets the user inputs. + * + * @param array $inputs An array of strings representing each input + * passed to the command input stream + * + * @return CommandTester + */ + public function setInputs(array $inputs) + { + $this->inputs = $inputs; + + return $this; + } + + private static function createStream(array $inputs) + { + $stream = fopen('php://memory', 'r+', false); + + fwrite($stream, implode(PHP_EOL, $inputs)); + rewind($stream); + + return $stream; + } } diff --git a/vendor/symfony/console/Tests/ApplicationTest.php b/vendor/symfony/console/Tests/ApplicationTest.php index 927fa0bd..4e1f8811 100644 --- a/vendor/symfony/console/Tests/ApplicationTest.php +++ b/vendor/symfony/console/Tests/ApplicationTest.php @@ -11,7 +11,11 @@ namespace Symfony\Component\Console\Tests; +use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\CommandLoader\FactoryCommandLoader; +use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\FormatterHelper; use Symfony\Component\Console\Input\ArgvInput; @@ -26,11 +30,14 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Console\Tester\ApplicationTester; use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\Console\Exception\CommandNotFoundException; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\EventDispatcher\EventDispatcher; -class ApplicationTest extends \PHPUnit_Framework_TestCase +class ApplicationTest extends TestCase { protected static $fixturesPath; @@ -38,11 +45,14 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase { self::$fixturesPath = realpath(__DIR__.'/Fixtures/'); require_once self::$fixturesPath.'/FooCommand.php'; + require_once self::$fixturesPath.'/FooOptCommand.php'; require_once self::$fixturesPath.'/Foo1Command.php'; require_once self::$fixturesPath.'/Foo2Command.php'; require_once self::$fixturesPath.'/Foo3Command.php'; require_once self::$fixturesPath.'/Foo4Command.php'; require_once self::$fixturesPath.'/Foo5Command.php'; + require_once self::$fixturesPath.'/FooSameCaseUppercaseCommand.php'; + require_once self::$fixturesPath.'/FooSameCaseLowercaseCommand.php'; require_once self::$fixturesPath.'/FoobarCommand.php'; require_once self::$fixturesPath.'/BarBucCommand.php'; require_once self::$fixturesPath.'/FooSubnamespaced1Command.php'; @@ -91,7 +101,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function testGetLongVersion() { $application = new Application('foo', 'bar'); - $this->assertEquals('foo version bar', $application->getLongVersion(), '->getLongVersion() returns the long version of the application'); + $this->assertEquals('foo bar', $application->getLongVersion(), '->getLongVersion() returns the long version of the application'); } public function testHelp() @@ -111,6 +121,25 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $commands, '->all() takes a namespace as its first argument'); } + public function testAllWithCommandLoader() + { + $application = new Application(); + $commands = $application->all(); + $this->assertInstanceOf('Symfony\\Component\\Console\\Command\\HelpCommand', $commands['help'], '->all() returns the registered commands'); + + $application->add(new \FooCommand()); + $commands = $application->all('foo'); + $this->assertCount(1, $commands, '->all() takes a namespace as its first argument'); + + $application->setCommandLoader(new FactoryCommandLoader(array( + 'foo:bar1' => function () { return new \Foo1Command(); }, + ))); + $commands = $application->all('foo'); + $this->assertCount(2, $commands, '->all() takes a namespace as its first argument'); + $this->assertInstanceOf(\FooCommand::class, $commands['foo:bar'], '->all() returns the registered commands'); + $this->assertInstanceOf(\Foo1Command::class, $commands['foo:bar1'], '->all() returns the registered commands'); + } + public function testRegister() { $application = new Application(); @@ -163,6 +192,30 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $command, '->get() returns the help command if --help is provided as the input'); } + public function testHasGetWithCommandLoader() + { + $application = new Application(); + $this->assertTrue($application->has('list'), '->has() returns true if a named command is registered'); + $this->assertFalse($application->has('afoobar'), '->has() returns false if a named command is not registered'); + + $application->add($foo = new \FooCommand()); + $this->assertTrue($application->has('afoobar'), '->has() returns true if an alias is registered'); + $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns a command by name'); + $this->assertEquals($foo, $application->get('afoobar'), '->get() returns a command by alias'); + + $application->setCommandLoader(new FactoryCommandLoader(array( + 'foo:bar1' => function () { return new \Foo1Command(); }, + ))); + + $this->assertTrue($application->has('afoobar'), '->has() returns true if an instance is registered for an alias even with command loader'); + $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns an instance by name even with command loader'); + $this->assertEquals($foo, $application->get('afoobar'), '->get() returns an instance by alias even with command loader'); + $this->assertTrue($application->has('foo:bar1'), '->has() returns true for commands registered in the loader'); + $this->assertInstanceOf(\Foo1Command::class, $foo1 = $application->get('foo:bar1'), '->get() returns a command by name from the command loader'); + $this->assertTrue($application->has('afoobar1'), '->has() returns true for commands registered in the loader'); + $this->assertEquals($foo1, $application->get('afoobar1'), '->get() returns a command by name from the command loader'); + } + public function testSilentHelp() { $application = new Application(); @@ -176,7 +229,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException Symfony\Component\Console\Exception\CommandNotFoundException + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException * @expectedExceptionMessage The command "foofoo" does not exist. */ public function testGetInvalidCommand() @@ -211,21 +264,27 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns commands even if the commands are only contained in subnamespaces'); } - /** - * @expectedException Symfony\Component\Console\Exception\CommandNotFoundException - * @expectedExceptionMessage The namespace "f" is ambiguous (foo, foo1). - */ public function testFindAmbiguousNamespace() { $application = new Application(); $application->add(new \BarBucCommand()); $application->add(new \FooCommand()); $application->add(new \Foo2Command()); + + $expectedMsg = "The namespace \"f\" is ambiguous.\nDid you mean one of these?\n foo\n foo1"; + + if (method_exists($this, 'expectException')) { + $this->expectException(CommandNotFoundException::class); + $this->expectExceptionMessage($expectedMsg); + } else { + $this->setExpectedException(CommandNotFoundException::class, $expectedMsg); + } + $application->findNamespace('f'); } /** - * @expectedException Symfony\Component\Console\Exception\CommandNotFoundException + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException * @expectedExceptionMessage There are no commands defined in the "bar" namespace. */ public function testFindInvalidNamespace() @@ -235,7 +294,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException Symfony\Component\Console\Exception\CommandNotFoundException + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException * @expectedExceptionMessage Command "foo1" is not defined */ public function testFindUniqueNameButNamespaceName() @@ -260,12 +319,66 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('FooCommand', $application->find('a'), '->find() returns a command if the abbreviation exists for an alias'); } + public function testFindCaseSensitiveFirst() + { + $application = new Application(); + $application->add(new \FooSameCaseUppercaseCommand()); + $application->add(new \FooSameCaseLowercaseCommand()); + + $this->assertInstanceOf('FooSameCaseUppercaseCommand', $application->find('f:B'), '->find() returns a command if the abbreviation is the correct case'); + $this->assertInstanceOf('FooSameCaseUppercaseCommand', $application->find('f:BAR'), '->find() returns a command if the abbreviation is the correct case'); + $this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:b'), '->find() returns a command if the abbreviation is the correct case'); + $this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:bar'), '->find() returns a command if the abbreviation is the correct case'); + } + + public function testFindCaseInsensitiveAsFallback() + { + $application = new Application(); + $application->add(new \FooSameCaseLowercaseCommand()); + + $this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:b'), '->find() returns a command if the abbreviation is the correct case'); + $this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:B'), '->find() will fallback to case insensitivity'); + $this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('FoO:BaR'), '->find() will fallback to case insensitivity'); + } + + /** + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException + * @expectedExceptionMessage Command "FoO:BaR" is ambiguous + */ + public function testFindCaseInsensitiveSuggestions() + { + $application = new Application(); + $application->add(new \FooSameCaseLowercaseCommand()); + $application->add(new \FooSameCaseUppercaseCommand()); + + $this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('FoO:BaR'), '->find() will find two suggestions with case insensitivity'); + } + + public function testFindWithCommandLoader() + { + $application = new Application(); + $application->setCommandLoader(new FactoryCommandLoader(array( + 'foo:bar' => $f = function () { return new \FooCommand(); }, + ))); + + $this->assertInstanceOf('FooCommand', $application->find('foo:bar'), '->find() returns a command if its name exists'); + $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $application->find('h'), '->find() returns a command if its name exists'); + $this->assertInstanceOf('FooCommand', $application->find('f:bar'), '->find() returns a command if the abbreviation for the namespace exists'); + $this->assertInstanceOf('FooCommand', $application->find('f:b'), '->find() returns a command if the abbreviation for the namespace and the command name exist'); + $this->assertInstanceOf('FooCommand', $application->find('a'), '->find() returns a command if the abbreviation exists for an alias'); + } + /** * @dataProvider provideAmbiguousAbbreviations */ public function testFindWithAmbiguousAbbreviations($abbreviation, $expectedExceptionMessage) { - $this->setExpectedException('Symfony\Component\Console\Exception\CommandNotFoundException', $expectedExceptionMessage); + if (method_exists($this, 'expectException')) { + $this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException'); + $this->expectExceptionMessage($expectedExceptionMessage); + } else { + $this->setExpectedException('Symfony\Component\Console\Exception\CommandNotFoundException', $expectedExceptionMessage); + } $application = new Application(); $application->add(new \FooCommand()); @@ -279,8 +392,20 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase { return array( array('f', 'Command "f" is not defined.'), - array('a', 'Command "a" is ambiguous (afoobar, afoobar1 and 1 more).'), - array('foo:b', 'Command "foo:b" is ambiguous (foo:bar, foo:bar1 and 1 more).'), + array( + 'a', + "Command \"a\" is ambiguous.\nDid you mean one of these?\n". + " afoobar The foo:bar command\n". + " afoobar1 The foo:bar1 command\n". + ' afoobar2 The foo1:bar command', + ), + array( + 'foo:b', + "Command \"foo:b\" is ambiguous.\nDid you mean one of these?\n". + " foo:bar The foo:bar command\n". + " foo:bar1 The foo:bar1 command\n". + ' foo1:bar The foo1:bar command', + ), ); } @@ -313,7 +438,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase /** * @dataProvider provideInvalidCommandNamesSingle - * @expectedException Symfony\Component\Console\Exception\CommandNotFoundException + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException * @expectedExceptionMessage Did you mean this */ public function testFindAlternativeExceptionMessageSingle($name) @@ -326,8 +451,8 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function provideInvalidCommandNamesSingle() { return array( - array('foo3:baR'), - array('foO3:bar'), + array('foo3:barr'), + array('fooo3:bar'), ); } @@ -425,7 +550,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $application->add(new \FooCommand()); $application->add(new \Foo1Command()); $application->add(new \Foo2Command()); - $application->add(new \foo3Command()); + $application->add(new \Foo3Command()); try { $application->find('Unknown-namespace:Unknown-command'); @@ -452,9 +577,39 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase } } + public function testFindAlternativesOutput() + { + $application = new Application(); + + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + $application->add(new \Foo3Command()); + + $expectedAlternatives = array( + 'afoobar', + 'afoobar1', + 'afoobar2', + 'foo1:bar', + 'foo3:bar', + 'foo:bar', + 'foo:bar1', + ); + + try { + $application->find('foo'); + $this->fail('->find() throws a CommandNotFoundException if command is not defined'); + } catch (\Exception $e) { + $this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command is not defined'); + $this->assertSame($expectedAlternatives, $e->getAlternatives()); + + $this->assertRegExp('/Command "foo" is not defined\..*Did you mean one of these\?.*/Ums', $e->getMessage()); + } + } + public function testFindNamespaceDoesNotFailOnDeepSimilarNamespaces() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getNamespaces')); + $application = $this->getMockBuilder('Symfony\Component\Console\Application')->setMethods(array('getNamespaces'))->getMock(); $application->expects($this->once()) ->method('getNamespaces') ->will($this->returnValue(array('foo:sublong', 'bar:sub'))); @@ -463,7 +618,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException Symfony\Component\Console\Exception\CommandNotFoundException + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException * @expectedExceptionMessage Command "foo::bar" is not defined. */ public function testFindWithDoubleColonInNameThrowsException() @@ -476,17 +631,21 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function testSetCatchExceptions() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(120)); + putenv('COLUMNS=120'); $tester = new ApplicationTester($application); $application->setCatchExceptions(true); + $this->assertTrue($application->areExceptionsCaught()); + $tester->run(array('command' => 'foo'), array('decorated' => false)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getDisplay(true), '->setCatchExceptions() sets the catch exception flag'); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getErrorOutput(true), '->setCatchExceptions() sets the catch exception flag'); + $this->assertSame('', $tester->getDisplay(true)); + $application->setCatchExceptions(false); try { $tester->run(array('command' => 'foo'), array('decorated' => false)); @@ -497,96 +656,114 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase } } - /** - * @group legacy - */ - public function testLegacyAsText() + public function testAutoExitSetting() { $application = new Application(); - $application->add(new \FooCommand()); - $this->ensureStaticCommandHelp($application); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext1.txt', $this->normalizeLineBreaks($application->asText()), '->asText() returns a text representation of the application'); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext2.txt', $this->normalizeLineBreaks($application->asText('foo')), '->asText() returns a text representation of the application'); - } + $this->assertTrue($application->isAutoExitEnabled()); - /** - * @group legacy - */ - public function testLegacyAsXml() - { - $application = new Application(); - $application->add(new \FooCommand()); - $this->ensureStaticCommandHelp($application); - $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml1.txt', $application->asXml(), '->asXml() returns an XML representation of the application'); - $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml2.txt', $application->asXml('foo'), '->asXml() returns an XML representation of the application'); + $application->setAutoExit(false); + $this->assertFalse($application->isAutoExitEnabled()); } public function testRenderException() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(120)); + putenv('COLUMNS=120'); $tester = new ApplicationTester($application); - $tester->run(array('command' => 'foo'), array('decorated' => false)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getDisplay(true), '->renderException() renders a pretty exception'); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exception'); - $tester->run(array('command' => 'foo'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); - $this->assertContains('Exception trace', $tester->getDisplay(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose'); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE, 'capture_stderr_separately' => true)); + $this->assertContains('Exception trace', $tester->getErrorOutput(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose'); - $tester->run(array('command' => 'list', '--foo' => true), array('decorated' => false)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getDisplay(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command'); + $tester->run(array('command' => 'list', '--foo' => true), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getErrorOutput(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command'); $application->add(new \Foo3Command()); $tester = new ApplicationTester($application); - $tester->run(array('command' => 'foo3:bar'), array('decorated' => false)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + $tester->run(array('command' => 'foo3:bar'), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $tester->run(array('command' => 'foo3:bar'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + $this->assertRegExp('/\[Exception\]\s*First exception/', $tester->getDisplay(), '->renderException() renders a pretty exception without code exception when code exception is default and verbosity is verbose'); + $this->assertRegExp('/\[Exception\]\s*Second exception/', $tester->getDisplay(), '->renderException() renders a pretty exception without code exception when code exception is 0 and verbosity is verbose'); + $this->assertRegExp('/\[Exception \(404\)\]\s*Third exception/', $tester->getDisplay(), '->renderException() renders a pretty exception with code exception when code exception is 404 and verbosity is verbose'); $tester->run(array('command' => 'foo3:bar'), array('decorated' => true)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $tester->run(array('command' => 'foo3:bar'), array('decorated' => true, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(32)); + putenv('COLUMNS=32'); $tester = new ApplicationTester($application); - $tester->run(array('command' => 'foo'), array('decorated' => false)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal'); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $tester->getErrorOutput(true), '->renderException() wraps messages when they are bigger than the terminal'); + putenv('COLUMNS=120'); } public function testRenderExceptionWithDoubleWidthCharacters() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(120)); + putenv('COLUMNS=120'); $application->register('foo')->setCode(function () { throw new \Exception('エラーメッセージ'); }); $tester = new ApplicationTester($application); - $tester->run(array('command' => 'foo'), array('decorated' => false)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $tester->run(array('command' => 'foo'), array('decorated' => true, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1decorated.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $application = new Application(); + $application->setAutoExit(false); + putenv('COLUMNS=32'); + $application->register('foo')->setCode(function () { + throw new \Exception('コマンドの実行中にエラーが発生しました。'); + }); + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getErrorOutput(true), '->renderException() wraps messages when they are bigger than the terminal'); + putenv('COLUMNS=120'); + } + + public function testRenderExceptionEscapesLines() + { + $application = new Application(); + $application->setAutoExit(false); + putenv('COLUMNS=22'); + $application->register('foo')->setCode(function () { + throw new \Exception('dont break here !'); + }); + $tester = new ApplicationTester($application); - $tester->run(array('command' => 'foo'), array('decorated' => true)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_escapeslines.txt', $tester->getDisplay(true), '->renderException() escapes lines containing formatting'); + putenv('COLUMNS=120'); + } - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + public function testRenderExceptionLineBreaks() + { + $application = $this->getMockBuilder('Symfony\Component\Console\Application')->setMethods(array('getTerminalWidth'))->getMock(); $application->setAutoExit(false); $application->expects($this->any()) ->method('getTerminalWidth') - ->will($this->returnValue(32)); + ->will($this->returnValue(120)); $application->register('foo')->setCode(function () { - throw new \Exception('コマンドの実行中にエラーが発生しました。'); + throw new \InvalidArgumentException("\n\nline 1 with extra spaces \nline 2\n\nline 4\n"); }); $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo'), array('decorated' => false)); - $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal'); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks'); } public function testRun() @@ -640,9 +817,11 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $tester->run(array('command' => 'list', '--quiet' => true)); $this->assertSame('', $tester->getDisplay(), '->run() removes all output if --quiet is passed'); + $this->assertFalse($tester->getInput()->isInteractive(), '->run() sets off the interactive mode if --quiet is passed'); $tester->run(array('command' => 'list', '-q' => true)); $this->assertSame('', $tester->getDisplay(), '->run() removes all output if -q is passed'); + $this->assertFalse($tester->getInput()->isInteractive(), '->run() sets off the interactive mode if -q is passed'); $tester->run(array('command' => 'list', '--verbose' => true)); $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose is passed'); @@ -700,19 +879,23 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $input = new ArgvInput(array('cli.php', '-v', 'foo:bar')); $application->run($input, $output); + $this->addToAssertionCount(1); + $input = new ArgvInput(array('cli.php', '--verbose', 'foo:bar')); $application->run($input, $output); + + $this->addToAssertionCount(1); } public function testRunReturnsIntegerExitCode() { $exception = new \Exception('', 4); - $application = $this->getMock('Symfony\Component\Console\Application', array('doRun')); + $application = $this->getMockBuilder('Symfony\Component\Console\Application')->setMethods(array('doRun'))->getMock(); $application->setAutoExit(false); $application->expects($this->once()) - ->method('doRun') - ->will($this->throwException($exception)); + ->method('doRun') + ->will($this->throwException($exception)); $exitCode = $application->run(new ArrayInput(array()), new NullOutput()); @@ -723,11 +906,11 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase { $exception = new \Exception('', 0); - $application = $this->getMock('Symfony\Component\Console\Application', array('doRun')); + $application = $this->getMockBuilder('Symfony\Component\Console\Application')->setMethods(array('doRun'))->getMock(); $application->setAutoExit(false); $application->expects($this->once()) - ->method('doRun') - ->will($this->throwException($exception)); + ->method('doRun') + ->will($this->throwException($exception)); $exitCode = $application->run(new ArrayInput(array()), new NullOutput()); @@ -799,8 +982,6 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $helperSet = $application->getHelperSet(); $this->assertTrue($helperSet->has('formatter')); - $this->assertTrue($helperSet->has('dialog')); - $this->assertTrue($helperSet->has('progress')); } public function testAddingSingleHelperSetOverwritesDefaultValues() @@ -919,7 +1100,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase /** * @expectedException \LogicException - * @expectedExceptionMessage caught + * @expectedExceptionMessage error */ public function testRunWithExceptionAndDispatcher() { @@ -950,7 +1131,212 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo')); - $this->assertContains('before.foo.caught.after.', $tester->getDisplay()); + $this->assertContains('before.foo.error.after.', $tester->getDisplay()); + } + + public function testRunDispatchesAllEventsWithExceptionInListener() + { + $dispatcher = $this->getDispatcher(); + $dispatcher->addListener('console.command', function () { + throw new \RuntimeException('foo'); + }); + + $application = new Application(); + $application->setDispatcher($dispatcher); + $application->setAutoExit(false); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('foo.'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + $this->assertContains('before.error.after.', $tester->getDisplay()); + } + + /** + * @requires PHP 7 + */ + public function testRunWithError() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + + try { + $tester->run(array('command' => 'dym')); + $this->fail('Error expected.'); + } catch (\Error $e) { + $this->assertSame('dymerr', $e->getMessage()); + } + } + + public function testRunAllowsErrorListenersToSilenceTheException() + { + $dispatcher = $this->getDispatcher(); + $dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) { + $event->getOutput()->write('silenced.'); + + $event->setExitCode(0); + }); + + $dispatcher->addListener('console.command', function () { + throw new \RuntimeException('foo'); + }); + + $application = new Application(); + $application->setDispatcher($dispatcher); + $application->setAutoExit(false); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('foo.'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + $this->assertContains('before.error.silenced.after.', $tester->getDisplay()); + $this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $tester->getStatusCode()); + } + + public function testConsoleErrorEventIsTriggeredOnCommandNotFound() + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) { + $this->assertNull($event->getCommand()); + $this->assertInstanceOf(CommandNotFoundException::class, $event->getError()); + $event->getOutput()->write('silenced command not found'); + }); + + $application = new Application(); + $application->setDispatcher($dispatcher); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'unknown')); + $this->assertContains('silenced command not found', $tester->getDisplay()); + $this->assertEquals(1, $tester->getStatusCode()); + } + + /** + * @group legacy + * @expectedDeprecation The "ConsoleEvents::EXCEPTION" event is deprecated since Symfony 3.3 and will be removed in 4.0. Listen to the "ConsoleEvents::ERROR" event instead. + */ + public function testLegacyExceptionListenersAreStillTriggered() + { + $dispatcher = $this->getDispatcher(); + $dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) { + $event->getOutput()->write('caught.'); + + $event->setException(new \RuntimeException('replaced in caught.')); + }); + + $application = new Application(); + $application->setDispatcher($dispatcher); + $application->setAutoExit(false); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + throw new \RuntimeException('foo'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + $this->assertContains('before.caught.error.after.', $tester->getDisplay()); + $this->assertContains('replaced in caught.', $tester->getDisplay()); + } + + /** + * @requires PHP 7 + */ + public function testErrorIsRethrownIfNotHandledByConsoleErrorEvent() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->setDispatcher(new EventDispatcher()); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + new \UnknownClass(); + }); + + $tester = new ApplicationTester($application); + + try { + $tester->run(array('command' => 'dym')); + $this->fail('->run() should rethrow PHP errors if not handled via ConsoleErrorEvent.'); + } catch (\Error $e) { + $this->assertSame($e->getMessage(), 'Class \'UnknownClass\' not found'); + } + } + + /** + * @requires PHP 7 + * @expectedException \LogicException + * @expectedExceptionMessage error + */ + public function testRunWithErrorAndDispatcher() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dym')); + $this->assertContains('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events'); + } + + /** + * @requires PHP 7 + */ + public function testRunDispatchesAllEventsWithError() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dym')); + $this->assertContains('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events'); + } + + /** + * @requires PHP 7 + */ + public function testRunWithErrorFailingStatusCode() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('dus')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dus.'); + + throw new \Error('duserr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dus')); + $this->assertSame(1, $tester->getStatusCode(), 'Status code should be 1'); } public function testRunWithDispatcherSkippingCommand() @@ -1026,6 +1412,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertEquals('some test value', $extraValue); } + /** + * @group legacy + */ public function testTerminalDimensions() { $application = new Application(); @@ -1041,35 +1430,31 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertSame(array($width, 80), $application->getTerminalDimensions()); } - protected function getDispatcher($skipCommand = false) + public function testSetRunCustomDefaultCommand() { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) { - $event->getOutput()->write('before.'); + $command = new \FooCommand(); - if ($skipCommand) { - $event->disableCommand(); - } - }); - $dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) { - $event->getOutput()->writeln('after.'); + $application = new Application(); + $application->setAutoExit(false); + $application->add($command); + $application->setDefaultCommand($command->getName()); - if (!$skipCommand) { - $event->setExitCode(113); - } - }); - $dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) { - $event->getOutput()->write('caught.'); + $tester = new ApplicationTester($application); + $tester->run(array(), array('interactive' => false)); + $this->assertEquals('called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); - $event->setException(new \LogicException('caught.', $event->getExitCode(), $event->getException())); - }); + $application = new CustomDefaultCommandApplication(); + $application->setAutoExit(false); - return $dispatcher; + $tester = new ApplicationTester($application); + $tester->run(array(), array('interactive' => false)); + + $this->assertEquals('called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); } - public function testSetRunCustomDefaultCommand() + public function testSetRunCustomDefaultCommandWithOption() { - $command = new \FooCommand(); + $command = new \FooOptCommand(); $application = new Application(); $application->setAutoExit(false); @@ -1077,16 +1462,27 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $application->setDefaultCommand($command->getName()); $tester = new ApplicationTester($application); - $tester->run(array()); - $this->assertEquals('interact called'.PHP_EOL.'called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); + $tester->run(array('--fooopt' => 'opt'), array('interactive' => false)); - $application = new CustomDefaultCommandApplication(); + $this->assertEquals('called'.PHP_EOL.'opt'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); + } + + public function testSetRunCustomSingleCommand() + { + $command = new \FooCommand(); + + $application = new Application(); $application->setAutoExit(false); + $application->add($command); + $application->setDefaultCommand($command->getName(), true); $tester = new ApplicationTester($application); + $tester->run(array()); + $this->assertContains('called', $tester->getDisplay()); - $this->assertEquals('interact called'.PHP_EOL.'called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); + $tester->run(array('--help' => true)); + $this->assertContains('The foo:bar command', $tester->getDisplay()); } /** @@ -1102,9 +1498,119 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertFalse($tester->getInput()->hasParameterOption(array('--no-interaction', '-n'))); - $inputStream = $application->getHelperSet()->get('question')->getInputStream(); + $inputStream = $tester->getInput()->getStream(); $this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream)); } + + public function testRunLazyCommandService() + { + $container = new ContainerBuilder(); + $container->addCompilerPass(new AddConsoleCommandPass()); + $container + ->register('lazy-command', LazyCommand::class) + ->addTag('console.command', array('command' => 'lazy:command')) + ->addTag('console.command', array('command' => 'lazy:alias')) + ->addTag('console.command', array('command' => 'lazy:alias2')); + $container->compile(); + + $application = new Application(); + $application->setCommandLoader($container->get('console.command_loader')); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'lazy:command')); + $this->assertSame("lazy-command called\n", $tester->getDisplay(true)); + + $tester->run(array('command' => 'lazy:alias')); + $this->assertSame("lazy-command called\n", $tester->getDisplay(true)); + + $tester->run(array('command' => 'lazy:alias2')); + $this->assertSame("lazy-command called\n", $tester->getDisplay(true)); + + $command = $application->get('lazy:command'); + $this->assertSame(array('lazy:alias', 'lazy:alias2'), $command->getAliases()); + } + + /** + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException + */ + public function testGetDisabledLazyCommand() + { + $application = new Application(); + $application->setCommandLoader(new FactoryCommandLoader(array('disabled' => function () { return new DisabledCommand(); }))); + $application->get('disabled'); + } + + public function testHasReturnsFalseForDisabledLazyCommand() + { + $application = new Application(); + $application->setCommandLoader(new FactoryCommandLoader(array('disabled' => function () { return new DisabledCommand(); }))); + $this->assertFalse($application->has('disabled')); + } + + public function testAllExcludesDisabledLazyCommand() + { + $application = new Application(); + $application->setCommandLoader(new FactoryCommandLoader(array('disabled' => function () { return new DisabledCommand(); }))); + $this->assertArrayNotHasKey('disabled', $application->all()); + } + + protected function getDispatcher($skipCommand = false) + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) { + $event->getOutput()->write('before.'); + + if ($skipCommand) { + $event->disableCommand(); + } + }); + $dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) { + $event->getOutput()->writeln('after.'); + + if (!$skipCommand) { + $event->setExitCode(ConsoleCommandEvent::RETURN_CODE_DISABLED); + } + }); + $dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) { + $event->getOutput()->write('error.'); + + $event->setError(new \LogicException('error.', $event->getExitCode(), $event->getError())); + }); + + return $dispatcher; + } + + /** + * @requires PHP 7 + */ + public function testErrorIsRethrownIfNotHandledByConsoleErrorEventWithCatchingEnabled() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setDispatcher(new EventDispatcher()); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + new \UnknownClass(); + }); + + $tester = new ApplicationTester($application); + + try { + $tester->run(array('command' => 'dym')); + $this->fail('->run() should rethrow PHP errors if not handled via ConsoleErrorEvent.'); + } catch (\Error $e) { + $this->assertSame($e->getMessage(), 'Class \'UnknownClass\' not found'); + } + } + + protected function tearDown() + { + putenv('SHELL_VERBOSITY'); + unset($_ENV['SHELL_VERBOSITY']); + unset($_SERVER['SHELL_VERBOSITY']); + } } class CustomApplication extends Application @@ -1144,3 +1650,19 @@ class CustomDefaultCommandApplication extends Application $this->setDefaultCommand($command->getName()); } } + +class LazyCommand extends Command +{ + public function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln('lazy-command called'); + } +} + +class DisabledCommand extends Command +{ + public function isEnabled() + { + return false; + } +} diff --git a/vendor/symfony/console/Tests/Command/CommandTest.php b/vendor/symfony/console/Tests/Command/CommandTest.php index e8836d8c..4fcbf957 100644 --- a/vendor/symfony/console/Tests/Command/CommandTest.php +++ b/vendor/symfony/console/Tests/Command/CommandTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Tests\Command; +use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\FormatterHelper; use Symfony\Component\Console\Application; @@ -23,7 +24,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Tester\CommandTester; -class CommandTest extends \PHPUnit_Framework_TestCase +class CommandTest extends TestCase { protected static $fixturesPath; @@ -45,7 +46,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase */ public function testCommandNameCannotBeEmpty() { - new Command(); + (new Application())->add(new Command()); } public function testSetApplication() @@ -54,6 +55,14 @@ class CommandTest extends \PHPUnit_Framework_TestCase $command = new \TestCommand(); $command->setApplication($application); $this->assertEquals($application, $command->getApplication(), '->setApplication() sets the current application'); + $this->assertEquals($application->getHelperSet(), $command->getHelperSet()); + } + + public function testSetApplicationNull() + { + $command = new \TestCommand(); + $command->setApplication(null); + $this->assertNull($command->getHelperSet()); } public function testSetGetDefinition() @@ -84,6 +93,13 @@ class CommandTest extends \PHPUnit_Framework_TestCase $this->assertTrue($command->getDefinition()->hasOption('foo'), '->addOption() adds an option to the command'); } + public function testSetHidden() + { + $command = new \TestCommand(); + $command->setHidden(true); + $this->assertTrue($command->isHidden()); + } + public function testGetNamespaceGetNameSetName() { $command = new \TestCommand(); @@ -101,7 +117,12 @@ class CommandTest extends \PHPUnit_Framework_TestCase */ public function testInvalidCommandNames($name) { - $this->setExpectedException('InvalidArgumentException', sprintf('Command name "%s" is invalid.', $name)); + if (method_exists($this, 'expectException')) { + $this->expectException('InvalidArgumentException'); + $this->expectExceptionMessage(sprintf('Command name "%s" is invalid.', $name)); + } else { + $this->setExpectedException('InvalidArgumentException', sprintf('Command name "%s" is invalid.', $name)); + } $command = new \TestCommand(); $command->setName($name); @@ -156,6 +177,13 @@ class CommandTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array('name1'), $command->getAliases(), '->setAliases() sets the aliases'); } + public function testSetAliasesNull() + { + $command = new \TestCommand(); + $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $command->setAliases(null); + } + public function testGetSynopsis() { $command = new \TestCommand(); @@ -164,6 +192,15 @@ class CommandTest extends \PHPUnit_Framework_TestCase $this->assertEquals('namespace:name [--foo] [--] []', $command->getSynopsis(), '->getSynopsis() returns the synopsis'); } + public function testAddGetUsages() + { + $command = new \TestCommand(); + $command->addUsage('foo1'); + $command->addUsage('foo2'); + $this->assertContains('namespace:name foo1', $command->getUsages()); + $this->assertContains('namespace:name foo2', $command->getUsages()); + } + public function testGetHelper() { $application = new Application(); @@ -257,7 +294,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException Symfony\Component\Console\Exception\InvalidOptionException + * @expectedException \Symfony\Component\Console\Exception\InvalidOptionException * @expectedExceptionMessage The "--bar" option does not exist. */ public function testRunWithInvalidOption() @@ -273,10 +310,10 @@ class CommandTest extends \PHPUnit_Framework_TestCase $exitCode = $command->run(new StringInput(''), new NullOutput()); $this->assertSame(0, $exitCode, '->run() returns integer exit code (treats null as 0)'); - $command = $this->getMock('TestCommand', array('execute')); + $command = $this->getMockBuilder('TestCommand')->setMethods(array('execute'))->getMock(); $command->expects($this->once()) - ->method('execute') - ->will($this->returnValue('2.3')); + ->method('execute') + ->will($this->returnValue('2.3')); $exitCode = $command->run(new StringInput(''), new NullOutput()); $this->assertSame(2, $exitCode, '->run() returns integer exit code (casts numeric to int)'); } @@ -297,6 +334,20 @@ class CommandTest extends \PHPUnit_Framework_TestCase $this->assertSame(0, $command->run(new StringInput(''), new NullOutput())); } + public function testRunWithProcessTitle() + { + $command = new \TestCommand(); + $command->setApplication(new Application()); + $command->setProcessTitle('foo'); + $this->assertSame(0, $command->run(new StringInput(''), new NullOutput())); + if (function_exists('cli_set_process_title')) { + if (null === @cli_get_process_title() && 'Darwin' === PHP_OS) { + $this->markTestSkipped('Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.'); + } + $this->assertEquals('foo', cli_get_process_title()); + } + } + public function testSetCode() { $command = new \TestCommand(); @@ -319,7 +370,6 @@ class CommandTest extends \PHPUnit_Framework_TestCase /** * @dataProvider getSetCodeBindToClosureTests - * @requires PHP 5.4 */ public function testSetCodeBindToClosure($previouslyBound, $expected) { @@ -335,53 +385,42 @@ class CommandTest extends \PHPUnit_Framework_TestCase $this->assertEquals('interact called'.PHP_EOL.$expected.PHP_EOL, $tester->getDisplay()); } - public function testSetCodeWithNonClosureCallable() + public function testSetCodeWithStaticClosure() { $command = new \TestCommand(); - $ret = $command->setCode(array($this, 'callableMethodCommand')); - $this->assertEquals($command, $ret, '->setCode() implements a fluent interface'); + $command->setCode(self::createClosure()); $tester = new CommandTester($command); $tester->execute(array()); - $this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay()); - } - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid callable provided to Command::setCode. - */ - public function testSetCodeWithNonCallable() - { - $command = new \TestCommand(); - $command->setCode(array($this, 'nonExistentMethod')); + if (\PHP_VERSION_ID < 70000) { + // Cannot bind static closures in PHP 5 + $this->assertEquals('interact called'.PHP_EOL.'not bound'.PHP_EOL, $tester->getDisplay()); + } else { + // Can bind static closures in PHP 7 + $this->assertEquals('interact called'.PHP_EOL.'bound'.PHP_EOL, $tester->getDisplay()); + } } - public function callableMethodCommand(InputInterface $input, OutputInterface $output) + private static function createClosure() { - $output->writeln('from the code...'); + return function (InputInterface $input, OutputInterface $output) { + $output->writeln(isset($this) ? 'bound' : 'not bound'); + }; } - /** - * @group legacy - */ - public function testLegacyAsText() + public function testSetCodeWithNonClosureCallable() { $command = new \TestCommand(); - $command->setApplication(new Application()); + $ret = $command->setCode(array($this, 'callableMethodCommand')); + $this->assertEquals($command, $ret, '->setCode() implements a fluent interface'); $tester = new CommandTester($command); - $tester->execute(array('command' => $command->getName())); - $this->assertStringEqualsFile(self::$fixturesPath.'/command_astext.txt', $command->asText(), '->asText() returns a text representation of the command'); + $tester->execute(array()); + $this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay()); } - /** - * @group legacy - */ - public function testLegacyAsXml() + public function callableMethodCommand(InputInterface $input, OutputInterface $output) { - $command = new \TestCommand(); - $command->setApplication(new Application()); - $tester = new CommandTester($command); - $tester->execute(array('command' => $command->getName())); - $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/command_asxml.txt', $command->asXml(), '->asXml() returns an XML representation of the command'); + $output->writeln('from the code...'); } } diff --git a/vendor/symfony/console/Tests/Command/HelpCommandTest.php b/vendor/symfony/console/Tests/Command/HelpCommandTest.php index 9e068587..4d618ac1 100644 --- a/vendor/symfony/console/Tests/Command/HelpCommandTest.php +++ b/vendor/symfony/console/Tests/Command/HelpCommandTest.php @@ -11,12 +11,13 @@ namespace Symfony\Component\Console\Tests\Command; +use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Console\Command\HelpCommand; use Symfony\Component\Console\Command\ListCommand; use Symfony\Component\Console\Application; -class HelpCommandTest extends \PHPUnit_Framework_TestCase +class HelpCommandTest extends TestCase { public function testExecuteForCommandAlias() { @@ -64,7 +65,7 @@ class HelpCommandTest extends \PHPUnit_Framework_TestCase $application = new Application(); $commandTester = new CommandTester($application->get('help')); $commandTester->execute(array('command_name' => 'list', '--format' => 'xml')); - $this->assertContains('list [--xml] [--raw] [--format FORMAT] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + $this->assertContains('list [--raw] [--format FORMAT] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); $this->assertContains('getDisplay(), '->execute() returns an XML help text if --format=xml is passed'); } } diff --git a/vendor/symfony/console/Tests/Command/ListCommandTest.php b/vendor/symfony/console/Tests/Command/ListCommandTest.php index a166a040..64478ecc 100644 --- a/vendor/symfony/console/Tests/Command/ListCommandTest.php +++ b/vendor/symfony/console/Tests/Command/ListCommandTest.php @@ -11,10 +11,11 @@ namespace Symfony\Component\Console\Tests\Command; +use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Console\Application; -class ListCommandTest extends \PHPUnit_Framework_TestCase +class ListCommandTest extends TestCase { public function testExecuteListsCommands() { @@ -30,7 +31,7 @@ class ListCommandTest extends \PHPUnit_Framework_TestCase $application = new Application(); $commandTester = new CommandTester($command = $application->get('list')); $commandTester->execute(array('command' => $command->getName(), '--format' => 'xml')); - $this->assertRegExp('//', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed'); + $this->assertRegExp('/