├── .composer-auth.json ├── .gitattributes ├── .gitignore ├── .styleci.yml ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── appveyor.yml ├── composer.json ├── phpunit.xml.dist ├── src ├── Adapter │ ├── ApplicationAdapter.php │ ├── ArgsFormatInputDefinition.php │ ├── ArgsInput.php │ ├── CommandAdapter.php │ ├── FormatterAdapter.php │ ├── IOOutput.php │ └── StyleConverter.php ├── Api │ ├── Application │ │ └── Application.php │ ├── Args │ │ ├── Args.php │ │ ├── ArgsParser.php │ │ ├── CannotAddArgumentException.php │ │ ├── CannotAddOptionException.php │ │ ├── CannotParseArgsException.php │ │ ├── Format │ │ │ ├── AbstractOption.php │ │ │ ├── ArgsFormat.php │ │ │ ├── ArgsFormatBuilder.php │ │ │ ├── Argument.php │ │ │ ├── CommandName.php │ │ │ ├── CommandOption.php │ │ │ ├── InvalidValueException.php │ │ │ └── Option.php │ │ ├── NoSuchArgumentException.php │ │ ├── NoSuchOptionException.php │ │ └── RawArgs.php │ ├── Command │ │ ├── CannotAddCommandException.php │ │ ├── Command.php │ │ ├── CommandCollection.php │ │ └── NoSuchCommandException.php │ ├── Config │ │ ├── ApplicationConfig.php │ │ ├── CommandConfig.php │ │ ├── Config.php │ │ ├── OptionCommandConfig.php │ │ └── SubCommandConfig.php │ ├── Event │ │ ├── ConfigEvent.php │ │ ├── ConsoleEvents.php │ │ ├── PreHandleEvent.php │ │ └── PreResolveEvent.php │ ├── Formatter │ │ ├── Formatter.php │ │ ├── Style.php │ │ └── StyleSet.php │ ├── IO │ │ ├── IO.php │ │ ├── IOException.php │ │ ├── Input.php │ │ ├── InputStream.php │ │ ├── Output.php │ │ └── OutputStream.php │ └── Resolver │ │ ├── CannotResolveCommandException.php │ │ ├── CommandResolver.php │ │ └── ResolvedCommand.php ├── Args │ ├── ArgvArgs.php │ ├── DefaultArgsParser.php │ ├── StringArgs.php │ └── TokenParser.php ├── Config │ └── DefaultApplicationConfig.php ├── ConsoleApplication.php ├── Formatter │ ├── AnsiFormatter.php │ ├── DefaultStyleSet.php │ ├── NullFormatter.php │ └── PlainFormatter.php ├── Handler │ ├── CallbackHandler.php │ ├── DelegatingHandler.php │ ├── Help │ │ ├── HelpAsciiDocHandler.php │ │ ├── HelpHandler.php │ │ ├── HelpJsonHandler.php │ │ ├── HelpManHandler.php │ │ ├── HelpTextHandler.php │ │ └── HelpXmlHandler.php │ └── NullHandler.php ├── IO │ ├── BufferedIO.php │ ├── ConsoleIO.php │ ├── InputStream │ │ ├── NullInputStream.php │ │ ├── StandardInputStream.php │ │ ├── StreamInputStream.php │ │ └── StringInputStream.php │ └── OutputStream │ │ ├── BufferedOutputStream.php │ │ ├── ErrorOutputStream.php │ │ ├── NullOutputStream.php │ │ ├── StandardOutputStream.php │ │ └── StreamOutputStream.php ├── Process │ └── ProcessLauncher.php ├── Resolver │ ├── DefaultResolver.php │ └── ResolveResult.php ├── UI │ ├── Alignment │ │ └── LabelAlignment.php │ ├── Component.php │ ├── Component │ │ ├── BorderUtil.php │ │ ├── CellWrapper.php │ │ ├── EmptyLine.php │ │ ├── ExceptionTrace.php │ │ ├── Grid.php │ │ ├── LabeledParagraph.php │ │ ├── NameVersion.php │ │ ├── Paragraph.php │ │ └── Table.php │ ├── Help │ │ ├── AbstractHelp.php │ │ ├── ApplicationHelp.php │ │ └── CommandHelp.php │ ├── Layout │ │ └── BlockLayout.php │ ├── Rectangle.php │ └── Style │ │ ├── Alignment.php │ │ ├── BorderStyle.php │ │ ├── GridStyle.php │ │ └── TableStyle.php └── Util │ ├── ProcessTitle.php │ ├── SimilarCommandName.php │ └── StringUtil.php └── tests ├── Adapter ├── ApplicationAdapterTest.php ├── ArgsFormatInputDefinitionTest.php ├── ArgsInputTest.php ├── CommandAdapterTest.php ├── FormatterAdapterTest.php ├── IOOutputTest.php └── StyleConverterTest.php ├── Api ├── Args │ ├── ArgsTest.php │ └── Format │ │ ├── ArgsFormatBuilderTest.php │ │ ├── ArgsFormatTest.php │ │ ├── ArgumentTest.php │ │ ├── CommandNameTest.php │ │ ├── CommandOptionTest.php │ │ └── OptionTest.php ├── Command │ ├── CommandCollectionTest.php │ └── CommandTest.php ├── Config │ ├── ApplicationConfigTest.php │ ├── CommandConfigTest.php │ ├── ConfigTest.php │ ├── Fixtures │ │ └── ConcreteConfig.php │ ├── OptionCommandConfigTest.php │ └── SubCommandConfigTest.php ├── Formatter │ ├── StyleSetTest.php │ └── StyleTest.php └── IO │ ├── InputTest.php │ └── OutputTest.php ├── Args ├── ArgvArgsTest.php ├── DefaultArgsParserTest.php └── StringArgsTest.php ├── Config └── DefaultApplicationConfigTest.php ├── ConsoleApplicationTest.php ├── Fixtures └── terminate-after-run.php ├── Formatter ├── AnsiFormatterTest.php └── PlainFormatterTest.php ├── Handler ├── CallbackHandlerTest.php ├── DelegatingHandlerTest.php └── Help │ ├── Fixtures │ ├── ascii-doc │ │ ├── custom-app.txt │ │ ├── man-not-found.txt │ │ ├── prefix-the-command.txt │ │ ├── the-app.txt │ │ └── the-command.txt │ └── man │ │ ├── custom-app.1 │ │ ├── prefix-the-command.1 │ │ ├── the-app.1 │ │ └── the-command.1 │ ├── HelpAsciiDocHandlerTest.php │ ├── HelpHandlerTest.php │ ├── HelpJsonHandlerTest.php │ ├── HelpManHandlerTest.php │ ├── HelpTextHandlerTest.php │ └── HelpXmlHandlerTest.php ├── IO ├── BufferedIOTest.php ├── InputStream │ ├── StandardInputStreamTest.php │ ├── StreamInputStreamTest.php │ └── StringInputStreamTest.php └── OutputStream │ ├── BufferedOutputStreamTest.php │ ├── ErrorOutputStreamTest.php │ ├── StandardOutputStreamTest.php │ └── StreamOutputStreamTest.php ├── Process └── ProcessLauncherTest.php ├── Resolver └── DefaultResolverTest.php ├── UI ├── Component │ ├── EmptyLineTest.php │ ├── ExceptionTraceTest.php │ ├── GridTest.php │ ├── LabeledParagraphTest.php │ ├── ParagraphTest.php │ └── TableTest.php ├── Help │ ├── ApplicationHelpTest.php │ └── CommandHelpTest.php └── Layout │ └── BlockLayoutTest.php └── Util ├── SimilarCommandNameTest.php └── StringUtilTest.php /.composer-auth.json: -------------------------------------------------------------------------------- 1 | { 2 | "github-oauth": { 3 | "github.com": "PLEASE DO NOT USE THIS TOKEN IN YOUR OWN PROJECTS/FORKS", 4 | "github.com": "This token is reserved for testing the webmozart/* repositories", 5 | "github.com": "a9debbffdd953ee9b3b82dbc3b807cde2086bb86" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Make sure heredoc with "\n" endings used in the tests is interpreted equally 2 | # on Windows and Unix 3 | *.php text eol=lf 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: symfony 2 | 3 | enabled: 4 | - ordered_use 5 | - strict 6 | 7 | disabled: 8 | - empty_return 9 | - phpdoc_annotation_without_dot # This is still buggy: https://github.com/symfony/symfony/pull/19198 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | branches: 6 | only: 7 | - master 8 | 9 | cache: 10 | directories: 11 | - $HOME/.composer/cache/files 12 | 13 | matrix: 14 | include: 15 | - php: 5.3 16 | - php: 5.4 17 | - php: 5.5 18 | - php: 5.6 19 | - php: hhvm 20 | - php: nightly 21 | - php: 7.0 22 | env: COVERAGE=yes 23 | - php: 7.0 24 | env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' 25 | allow_failures: 26 | - php: hhvm 27 | - php: nightly 28 | fast_finish: true 29 | 30 | before_install: 31 | - if [[ $TRAVIS_PHP_VERSION != hhvm && $COVERAGE != yes ]]; then phpenv config-rm xdebug.ini; fi; 32 | - if [[ $TRAVIS_REPO_SLUG = webmozart/console ]]; then cp .composer-auth.json ~/.composer/auth.json; fi; 33 | - composer self-update 34 | 35 | install: composer update $COMPOSER_FLAGS --prefer-dist --no-interaction 36 | 37 | script: if [[ $COVERAGE = yes ]]; then vendor/bin/phpunit --verbose --coverage-clover=coverage.clover; else vendor/bin/phpunit --verbose; fi 38 | 39 | after_script: if [[ $COVERAGE = yes ]]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi 40 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | * 1.0.0-beta5 (2016-02-05) 5 | 6 | * added support for Symfony 3 7 | * fixed shell argument escaping on Windows 8 | 9 | * 1.0.0-beta4 (2015-10-02) 10 | 11 | * renamed `Input` and implementations to `InputStream` 12 | * renamed `Output` and implementations to `OutputStream` 13 | * turned `IO` into a class 14 | * added `Input` 15 | * added `Output` 16 | * added `isClosed()` to `InputStream` and `OutputStream` 17 | * removed `RawIO` and `FormattedIO` 18 | * changed constructor of `BufferedIO` 19 | * changed constructor of `ConsoleIO` 20 | 21 | * 1.0.0-beta3 (2015-08-24) 22 | 23 | * fixed minimum versions in composer.json 24 | 25 | * 1.0.0-beta2 (2015-05-28) 26 | 27 | * fixed `Paragraph` to not indent empty lines 28 | * added `RawArgs::getScriptName()` and `Args::getScriptName()` 29 | * enabled nice exception rendering for exceptions thrown before the IO is created 30 | * made it possible to pass a callable to `ConsoleApplication::__construct()` 31 | 32 | * 1.0.0-beta (2015-03-19) 33 | 34 | * first release 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Bernhard Schussek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | build: false 2 | platform: x86 3 | clone_folder: c:\projects\webmozart\console 4 | 5 | branches: 6 | only: 7 | - master 8 | 9 | cache: 10 | - c:\php -> appveyor.yml 11 | 12 | init: 13 | - SET PATH=c:\php;%PATH% 14 | - SET COMPOSER_NO_INTERACTION=1 15 | - SET PHP=1 16 | 17 | install: 18 | - IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php) 19 | - cd c:\php 20 | - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-7.0.0-nts-Win32-VC14-x86.zip 21 | - IF %PHP%==1 7z x php-7.0.0-nts-Win32-VC14-x86.zip -y >nul 22 | - IF %PHP%==1 del /Q *.zip 23 | - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat 24 | - IF %PHP%==1 copy /Y php.ini-development php.ini 25 | - IF %PHP%==1 echo max_execution_time=1200 >> php.ini 26 | - IF %PHP%==1 echo date.timezone="UTC" >> php.ini 27 | - IF %PHP%==1 echo extension_dir=ext >> php.ini 28 | - IF %PHP%==1 echo extension=php_curl.dll >> php.ini 29 | - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini 30 | - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini 31 | - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini 32 | - appveyor DownloadFile https://getcomposer.org/composer.phar 33 | - cd c:\projects\webmozart\console 34 | - mkdir %APPDATA%\Composer 35 | - IF %APPVEYOR_REPO_NAME%==webmozart/console copy /Y .composer-auth.json %APPDATA%\Composer\auth.json 36 | - composer update --prefer-dist --no-progress --ansi 37 | 38 | test_script: 39 | - cd c:\projects\webmozart\console 40 | - vendor\bin\phpunit.bat --verbose 41 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webmozart/console", 3 | "description": "A usable, beautiful and easily testable console toolkit written in PHP.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Bernhard Schussek", 8 | "email": "bschussek@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.3.9", 13 | "webmozart/assert": "^1.0", 14 | "symfony/console": "^2.7|^3.0", 15 | "symfony/process": "^2.5|^3.0", 16 | "symfony/event-dispatcher": "^2.5|^3.0" 17 | }, 18 | "require-dev": { 19 | "symfony/filesystem": "^2.3|^3.0", 20 | "phpunit/phpunit": "^4.6", 21 | "sebastian/version": "^1.0.1" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Webmozart\\Console\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "Webmozart\\Console\\Tests\\": "tests/" 31 | } 32 | }, 33 | "extra": { 34 | "branch-alias": { 35 | "dev-master": "1.0-dev" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./tests/ 7 | 8 | 9 | 10 | 11 | 12 | 13 | ./src/ 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Adapter/ApplicationAdapter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Adapter; 13 | 14 | use Exception; 15 | use Symfony\Component\Console\Application; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | use Webmozart\Assert\Assert; 19 | 20 | /** 21 | * Adapts an `Application` instance of this package to Symfony's 22 | * {@link Application} API. 23 | * 24 | * @since 1.0 25 | * 26 | * @author Bernhard Schussek 27 | */ 28 | class ApplicationAdapter extends Application 29 | { 30 | /** 31 | * @var \Webmozart\Console\Api\Application\Application 32 | */ 33 | private $adaptedApplication; 34 | 35 | /** 36 | * @var CommandAdapter 37 | */ 38 | private $currentCommand; 39 | 40 | /** 41 | * Creates the application. 42 | * 43 | * @param \Webmozart\Console\Api\Application\Application $application 44 | */ 45 | public function __construct(\Webmozart\Console\Api\Application\Application $application) 46 | { 47 | $this->adaptedApplication = $application; 48 | 49 | $config = $application->getConfig(); 50 | 51 | parent::__construct($config->getDisplayName(), $config->getVersion()); 52 | 53 | if ($dispatcher = $config->getEventDispatcher()) { 54 | $this->setDispatcher($dispatcher); 55 | } 56 | 57 | $this->setAutoExit($config->isTerminatedAfterRun()); 58 | $this->setCatchExceptions($config->isExceptionCaught()); 59 | 60 | foreach ($application->getCommands() as $command) { 61 | $this->add(new CommandAdapter($command, $this)); 62 | } 63 | } 64 | 65 | /** 66 | * @return \Webmozart\Console\Api\Application\Application 67 | */ 68 | public function getAdaptedApplication() 69 | { 70 | return $this->adaptedApplication; 71 | } 72 | 73 | /** 74 | * {@inheritdoc} 75 | */ 76 | public function doRun(InputInterface $input, OutputInterface $output) 77 | { 78 | /* @var ArgsInput $input */ 79 | Assert::isInstanceOf($input, 'Webmozart\Console\Adapter\ArgsInput'); 80 | 81 | $rawArgs = $input->getRawArgs(); 82 | $resolvedCommand = $this->adaptedApplication->resolveCommand($rawArgs); 83 | 84 | // Add parsed Args to the adapter 85 | $input = new ArgsInput($rawArgs, $resolvedCommand->getArgs()); 86 | 87 | // Don't use $this->get() as get() does not work for sub-commands 88 | $this->currentCommand = new CommandAdapter($resolvedCommand->getCommand(), $this); 89 | 90 | try { 91 | $result = parent::doRun($input, $output); 92 | $this->currentCommand = null; 93 | } catch (Exception $e) { 94 | $this->currentCommand = null; 95 | 96 | throw $e; 97 | } 98 | 99 | return $result; 100 | } 101 | 102 | /** 103 | * {@inheritdoc} 104 | */ 105 | protected function getCommandName(InputInterface $input) 106 | { 107 | // This method must return something, otherwise the base class tries 108 | // to set the "command" argument which doesn't usually exist 109 | return 'command-name'; 110 | } 111 | 112 | /** 113 | * {@inheritdoc} 114 | */ 115 | public function find($name) 116 | { 117 | return $this->currentCommand; 118 | } 119 | 120 | /** 121 | * {@inheritdoc} 122 | */ 123 | protected function getDefaultInputDefinition() 124 | { 125 | return new ArgsFormatInputDefinition($this->adaptedApplication->getGlobalArgsFormat()); 126 | } 127 | 128 | /** 129 | * {@inheritdoc} 130 | */ 131 | protected function getDefaultCommands() 132 | { 133 | return array(); 134 | } 135 | 136 | /** 137 | * {@inheritdoc} 138 | */ 139 | protected function getDefaultHelperSet() 140 | { 141 | return $this->adaptedApplication->getConfig()->getHelperSet(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Adapter/FormatterAdapter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Adapter; 13 | 14 | use Symfony\Component\Console\Formatter\OutputFormatterInterface; 15 | use Symfony\Component\Console\Formatter\OutputFormatterStyleInterface; 16 | use Webmozart\Console\Api\Formatter\Formatter; 17 | 18 | /** 19 | * Adapts a {@link Formatter} instance to Symfony's 20 | * {@link OutputFormatterInterface} API. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class FormatterAdapter implements OutputFormatterInterface 27 | { 28 | /** 29 | * @var Formatter 30 | */ 31 | private $adaptedFormatter; 32 | 33 | /** 34 | * @var bool 35 | */ 36 | private $decorated = true; 37 | 38 | /** 39 | * Creates the adapter. 40 | * 41 | * @param Formatter $adaptedFormatter The adapted formatter. 42 | */ 43 | public function __construct(Formatter $adaptedFormatter) 44 | { 45 | $this->adaptedFormatter = $adaptedFormatter; 46 | } 47 | 48 | /** 49 | * Returns the adapted formatter. 50 | * 51 | * @return Formatter The adapted formatter. 52 | */ 53 | public function getAdaptedFormatter() 54 | { 55 | return $this->adaptedFormatter; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function setDecorated($decorated) 62 | { 63 | $this->decorated = $decorated; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function isDecorated() 70 | { 71 | return $this->decorated; 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | */ 77 | public function setStyle($name, OutputFormatterStyleInterface $style) 78 | { 79 | } 80 | 81 | /** 82 | * {@inheritdoc} 83 | */ 84 | public function hasStyle($name) 85 | { 86 | } 87 | 88 | /** 89 | * {@inheritdoc} 90 | */ 91 | public function getStyle($name) 92 | { 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | */ 98 | public function format($message) 99 | { 100 | if ($this->decorated) { 101 | return $this->adaptedFormatter->format($message); 102 | } 103 | 104 | return $this->adaptedFormatter->removeFormat($message); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Adapter/StyleConverter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Adapter; 13 | 14 | use Symfony\Component\Console\Formatter\OutputFormatterStyle; 15 | use Webmozart\Console\Api\Formatter\Style; 16 | 17 | /** 18 | * Converts {@link Style} instances to Symfony's {@link OutputFormatterStyle}. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class StyleConverter 25 | { 26 | /** 27 | * Converts a {@link Style} instance to an {@link OutputFormatterStyle}. 28 | * 29 | * @param Style $style The style to convert. 30 | * 31 | * @return OutputFormatterStyle The converted style. 32 | */ 33 | public static function convert(Style $style) 34 | { 35 | $options = array(); 36 | 37 | if ($style->isBold()) { 38 | $options[] = 'bold'; 39 | } 40 | 41 | if ($style->isBlinking()) { 42 | $options[] = 'blink'; 43 | } 44 | 45 | if ($style->isUnderlined()) { 46 | $options[] = 'underscore'; 47 | } 48 | 49 | if ($style->isInverse()) { 50 | $options[] = 'reverse'; 51 | } 52 | 53 | if ($style->isHidden()) { 54 | $options[] = 'conceal'; 55 | } 56 | 57 | return new OutputFormatterStyle($style->getForegroundColor(), $style->getBackgroundColor(), $options); 58 | } 59 | 60 | private function __construct() 61 | { 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Api/Args/ArgsParser.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | use Webmozart\Console\Api\Args\Format\ArgsFormat; 15 | 16 | /** 17 | * Parses raw console arguments and returns the parsed arguments. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | interface ArgsParser 24 | { 25 | /** 26 | * Parses the raw console arguments and returns the parsed arguments. 27 | * 28 | * @param RawArgs $args The raw console arguments. 29 | * @param ArgsFormat $format The argument format. 30 | * @param bool $lenient Whether the parser should ignore parse errors. 31 | * If `true`, the parser will not throw any 32 | * exceptions when parse errors occur. 33 | * 34 | * @return Args The parsed console arguments. 35 | * 36 | * @throws CannotParseArgsException If the arguments cannot be parsed. 37 | */ 38 | public function parseArgs(RawArgs $args, ArgsFormat $format, $lenient = false); 39 | } 40 | -------------------------------------------------------------------------------- /src/Api/Args/CannotAddArgumentException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | 17 | /** 18 | * Thrown when an argument cannot be added. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class CannotAddArgumentException extends RuntimeException 25 | { 26 | /** 27 | * Code: The argument exists already. 28 | */ 29 | const EXISTS_ALREADY = 1; 30 | 31 | /** 32 | * Code: An argument was added after a multi-valued argument. 33 | */ 34 | const MULTI_VALUED_EXISTS = 2; 35 | 36 | /** 37 | * Code: A required argument was added after an optional argument. 38 | */ 39 | const REQUIRED_AFTER_OPTIONAL = 3; 40 | 41 | /** 42 | * Creates an exception with code {@link EXISTS_ALREADY}. 43 | * 44 | * @param string $name The argument name. 45 | * @param Exception $cause The exception that caused this exception. 46 | * 47 | * @return static The created exception. 48 | */ 49 | public static function existsAlready($name, Exception $cause = null) 50 | { 51 | return new static(sprintf( 52 | 'An argument named "%s" exists already.', 53 | $name 54 | ), self::EXISTS_ALREADY, $cause); 55 | } 56 | 57 | /** 58 | * Creates an exception with code {@link ADD_AFTER_MULTI_VALUED}. 59 | * 60 | * @param Exception $cause The exception that caused this exception. 61 | * 62 | * @return static The created exception. 63 | */ 64 | public static function cannotAddAfterMultiValued(Exception $cause = null) 65 | { 66 | return new static( 67 | 'Cannot add an argument after a multi-valued argument.', 68 | self::MULTI_VALUED_EXISTS, 69 | $cause 70 | ); 71 | } 72 | 73 | /** 74 | * Creates an exception with code {@link ADD_REQUIRED_AFTER_OPTIONAL}. 75 | * 76 | * @param Exception $cause The exception that caused this exception. 77 | * 78 | * @return static The created exception. 79 | */ 80 | public static function cannotAddRequiredAfterOptional(Exception $cause = null) 81 | { 82 | return new static( 83 | 'Cannot add a required argument after an optional one.', 84 | self::REQUIRED_AFTER_OPTIONAL, 85 | $cause 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Api/Args/CannotAddOptionException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | 17 | /** 18 | * Thrown when an option cannot be added. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class CannotAddOptionException extends RuntimeException 25 | { 26 | /** 27 | * Creates an exception for a duplicate option. 28 | * 29 | * @param string $name The option name. 30 | * @param Exception $cause The exception that caused this exception. 31 | * 32 | * @return static The created exception. 33 | */ 34 | public static function existsAlready($name, Exception $cause = null) 35 | { 36 | return new static(sprintf( 37 | 'An option named "%s%s" exists already.', 38 | strlen($name) > 1 ? '--' : '-', 39 | $name 40 | ), 0, $cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Api/Args/CannotParseArgsException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | use RuntimeException; 15 | 16 | /** 17 | * Thrown when console arguments cannot be parsed. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class CannotParseArgsException extends RuntimeException 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /src/Api/Args/Format/CommandName.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args\Format; 13 | 14 | use Webmozart\Assert\Assert; 15 | 16 | /** 17 | * A command name in the console arguments. 18 | * 19 | * The command name determines which command should be executed. The console 20 | * input may contain one or several command names. 21 | * 22 | * In the example below, the console arguments contain the two command names 23 | * "server" and "add": 24 | * 25 | * ``` 26 | * $ console server add localhost 27 | * ``` 28 | * 29 | * The last part "localhost" is the argument to the "server add" command. 30 | * 31 | * @since 1.0 32 | * 33 | * @author Bernhard Schussek 34 | * 35 | * @see CommandOption, ArgsFormat 36 | */ 37 | class CommandName 38 | { 39 | /** 40 | * @var string 41 | */ 42 | private $string; 43 | 44 | /** 45 | * @var string[] 46 | */ 47 | private $aliases; 48 | 49 | /** 50 | * Creates a new command name. 51 | * 52 | * @param string $string The command name. 53 | * @param string[] $aliases The alias names. 54 | */ 55 | public function __construct($string, array $aliases = array()) 56 | { 57 | Assert::string($string, 'The command name must be a string. Got: %s'); 58 | Assert::notEmpty($string, 'The command name must not be empty.'); 59 | Assert::regex($string, '~^[a-zA-Z0-9\-]+$~', 'The command name must contain letters, digits and hyphens only. Got: "%s"'); 60 | 61 | Assert::allString($aliases, 'The command aliases must be strings. Got: %s'); 62 | Assert::allNotEmpty($aliases, 'The command aliases must not be empty.'); 63 | Assert::allRegex($aliases, '~^[a-zA-Z0-9\-]+$~', 'The command aliases must contain letters, digits and hyphens only. Got: "%s"'); 64 | 65 | $this->string = $string; 66 | $this->aliases = $aliases; 67 | } 68 | 69 | /** 70 | * Returns the command name as string. 71 | * 72 | * @return string The command name. 73 | */ 74 | public function toString() 75 | { 76 | return $this->string; 77 | } 78 | 79 | /** 80 | * Returns the alias names. 81 | * 82 | * @return string[] The aliases of the command name. 83 | */ 84 | public function getAliases() 85 | { 86 | return $this->aliases; 87 | } 88 | 89 | /** 90 | * Returns whether a string matches the command name or one of its aliases. 91 | * 92 | * @param string $string The string to test. 93 | * 94 | * @return bool Returns `true` if the given string matches the command name 95 | * or one of its aliases and `false` otherwise. 96 | */ 97 | public function match($string) 98 | { 99 | return $this->string === $string || in_array($string, $this->aliases, true); 100 | } 101 | 102 | /** 103 | * Casts the command name to a string. 104 | * 105 | * @return string The command name. 106 | */ 107 | public function __toString() 108 | { 109 | return $this->string; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Api/Args/Format/CommandOption.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args\Format; 13 | 14 | use Webmozart\Assert\Assert; 15 | 16 | /** 17 | * A command option in the console arguments. 18 | * 19 | * The command names and command options determine which command is executed. 20 | * 21 | * In the example below, the console arguments contain the command name "server" 22 | * and the command option "delete": 23 | * 24 | * ``` 25 | * $ console server --delete localhost 26 | * $ console server -d localhost 27 | * ``` 28 | * 29 | * The last part "localhost" is the argument to the "server --delete" command. 30 | * 31 | * @since 1.0 32 | * 33 | * @author Bernhard Schussek 34 | * 35 | * @see CommandName, ArgsFormat 36 | */ 37 | class CommandOption extends AbstractOption 38 | { 39 | /** 40 | * @var string[] 41 | */ 42 | private $longAliases = array(); 43 | 44 | /** 45 | * @var string[] 46 | */ 47 | private $shortAliases = array(); 48 | 49 | /** 50 | * Creates the command option. 51 | * 52 | * @param string $longName The long option name. 53 | * @param string|null $shortName The short option name. 54 | * @param string[] $aliases A list of alias names. 55 | * @param int $flags A bitwise combination of the option flag 56 | * constants. 57 | * @param string $description A human-readable description of the option. 58 | * 59 | * @throws InvalidValueException If the default value is invalid. 60 | */ 61 | public function __construct($longName, $shortName = null, array $aliases = array(), $flags = 0, $description = null) 62 | { 63 | parent::__construct($longName, $shortName, $flags, $description); 64 | 65 | foreach ($aliases as $key => $alias) { 66 | $alias = $this->removeDashPrefix($alias); 67 | 68 | if (1 === strlen($alias)) { 69 | $this->assertShortAliasValid($alias); 70 | $this->shortAliases[] = $alias; 71 | } else { 72 | $this->assertLongAliasValid($alias); 73 | $this->longAliases[] = $alias; 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * Returns all long alias names. 80 | * 81 | * @return string[] The long alias names. 82 | */ 83 | public function getLongAliases() 84 | { 85 | return $this->longAliases; 86 | } 87 | 88 | /** 89 | * Returns all short alias names. 90 | * 91 | * @return string[] The short alias names. 92 | */ 93 | public function getShortAliases() 94 | { 95 | return $this->shortAliases; 96 | } 97 | 98 | private function removeDashPrefix($string) 99 | { 100 | if ('--' === substr($string, 0, 2)) { 101 | $string = substr($string, 2); 102 | } elseif (isset($string[0]) && '-' === $string[0]) { 103 | $string = substr($string, 1); 104 | } 105 | 106 | return $string; 107 | } 108 | 109 | private function assertLongAliasValid($alias) 110 | { 111 | Assert::string($alias, 'An option alias must be a string or null. Got: %s'); 112 | Assert::notEmpty($alias, 'An option alias must not be empty.'); 113 | Assert::startsWithLetter($alias, 'A long option alias must start with a letter.'); 114 | Assert::regex($alias, '~^[a-zA-Z0-9\-]+$~', 'A long option alias must contain letters, digits and hyphens only.'); 115 | } 116 | 117 | private function assertShortAliasValid($alias) 118 | { 119 | Assert::string($alias, 'An option alias must be a string or null. Got: %s'); 120 | Assert::notEmpty($alias, 'An option alias must not be empty.'); 121 | Assert::regex($alias, '~^[a-zA-Z]$~', 'A short option alias must be exactly one letter. Got: "%s"'); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Api/Args/Format/InvalidValueException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args\Format; 13 | 14 | use Exception; 15 | 16 | /** 17 | * Thrown when the value of an option or an argument is invalid. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class InvalidValueException extends Exception 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /src/Api/Args/NoSuchArgumentException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | 17 | /** 18 | * Thrown when a non-existing argument is accessed. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class NoSuchArgumentException extends RuntimeException 25 | { 26 | /** 27 | * Creates an exception for the given argument name. 28 | * 29 | * @param string $name The argument name. 30 | * @param int $code The exception code. 31 | * @param Exception $cause The exception that caused this exception. 32 | * 33 | * @return static The created exception. 34 | */ 35 | public static function forArgumentName($name, $code = 0, Exception $cause = null) 36 | { 37 | return new static(sprintf( 38 | 'The argument "%s" does not exist.', 39 | $name 40 | ), $code, $cause); 41 | } 42 | 43 | /** 44 | * Creates an exception for the given argument position. 45 | * 46 | * @param int $position The argument position. 47 | * @param int $code The exception code. 48 | * @param Exception $cause The exception that caused this exception. 49 | * 50 | * @return static The created exception. 51 | */ 52 | public static function forPosition($position, $code = 0, Exception $cause = null) 53 | { 54 | return new static(sprintf( 55 | 'The argument at position %s does not exist.', 56 | $position 57 | ), $code, $cause); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Api/Args/NoSuchOptionException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | 17 | /** 18 | * Thrown when a non-existing option is accessed. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class NoSuchOptionException extends RuntimeException 25 | { 26 | /** 27 | * Creates an exception for the given option name. 28 | * 29 | * @param string $name The option name. 30 | * @param int $code The exception code. 31 | * @param Exception $cause The exception that caused this exception. 32 | * 33 | * @return static The created exception. 34 | */ 35 | public static function forOptionName($name, $code = 0, Exception $cause = null) 36 | { 37 | return new static(sprintf( 38 | 'The option "%s%s" does not exist.', 39 | strlen($name) > 1 ? '--' : '-', 40 | $name 41 | ), $code, $cause); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Api/Args/RawArgs.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Args; 13 | 14 | /** 15 | * The unparsed console arguments. 16 | * 17 | * Implementations of this class represent the arguments that a user passes 18 | * when calling the console. For example: 19 | * 20 | * ``` 21 | * $ console server add --port 80 localhost 22 | * ``` 23 | * 24 | * In this case, the raw arguments contain the tokens: 25 | * 26 | * * "server" 27 | * * "add" 28 | * * "--port" 29 | * * "80" 30 | * * "localhost" 31 | * 32 | * With an implementation of {@link ArgsParser} and a configured 33 | * {@link ArgsFormat}, the {@link RawArgs} instance can be converted into an 34 | * {@link Args} instance: 35 | * 36 | * ```php 37 | * $format = ArgsFormat::build() 38 | * ->addCommandName(new CommandName('server')) 39 | * ->addCommandName(new CommandName('add')) 40 | * ->addOption(new Option('port', 'p', Option::VALUE_REQUIRED | Option::INTEGER)) 41 | * ->addArgument(new Argument('host', Argument::REQUIRED)) 42 | * ->getFormat(); 43 | * 44 | * $args = $parser->parseArgs($rawArgs, $format); 45 | * ``` 46 | * 47 | * The {@link Args} instance can be used to access the options and arguments of 48 | * a command in a convenient way. 49 | * 50 | * @since 1.0 51 | * 52 | * @author Bernhard Schussek 53 | * 54 | * @see Args, ArgsFormat, ArgsParser 55 | */ 56 | interface RawArgs 57 | { 58 | /** 59 | * Returns the PHP script as it was called on the console. 60 | * 61 | * @return string|null The script name or null if no script name is 62 | * available. 63 | */ 64 | public function getScriptName(); 65 | 66 | /** 67 | * Returns the tokens of the console arguments. 68 | * 69 | * @return string[] The argument tokens. 70 | */ 71 | public function getTokens(); 72 | 73 | /** 74 | * Returns whether the console arguments contain a given token. 75 | * 76 | * @param string $token The token to look for. 77 | * 78 | * @return bool Returns `true` if the arguments contain the token and 79 | * `false` otherwise. 80 | */ 81 | public function hasToken($token); 82 | 83 | /** 84 | * Returns the console arguments as string. 85 | * 86 | * @param bool $scriptName Whether to include the script name in the output. 87 | * 88 | * @return string The arguments as string. 89 | */ 90 | public function toString($scriptName = true); 91 | } 92 | -------------------------------------------------------------------------------- /src/Api/Command/CannotAddCommandException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Command; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | 17 | /** 18 | * Thrown when two commands have the same name. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class CannotAddCommandException extends RuntimeException 25 | { 26 | /** 27 | * Code: A command with the same name exists. 28 | */ 29 | const NAME_EXISTS = 1; 30 | 31 | /** 32 | * Code: An option with the same name exists. 33 | */ 34 | const OPTION_EXISTS = 2; 35 | 36 | /** 37 | * Code: The command name is empty. 38 | */ 39 | const NAME_EMPTY = 3; 40 | 41 | /** 42 | * Creates an exception for the code {@link NAME_EXISTS}. 43 | * 44 | * @param string $name The command name. 45 | * @param Exception $cause The exception that caused this exception. 46 | * 47 | * @return static The created exception. 48 | */ 49 | public static function nameExists($name, Exception $cause = null) 50 | { 51 | return new static(sprintf( 52 | 'A command named "%s" exists already.', 53 | $name 54 | ), self::NAME_EXISTS, $cause); 55 | } 56 | 57 | /** 58 | * Creates an exception for the code {@link OPTION_EXISTS}. 59 | * 60 | * @param string $name The command name. 61 | * @param Exception $cause The exception that caused this exception. 62 | * 63 | * @return static The created exception. 64 | */ 65 | public static function optionExists($name, Exception $cause = null) 66 | { 67 | return new static(sprintf( 68 | 'An option named "%s%s" exists already.', 69 | strlen($name) > 1 ? '--' : '-', 70 | $name 71 | ), self::OPTION_EXISTS, $cause); 72 | } 73 | 74 | /** 75 | * Creates an exception for the code {@link NAME_EMPTY}. 76 | * 77 | * @param Exception $cause The exception that caused this exception. 78 | * 79 | * @return static The created exception. 80 | */ 81 | public static function nameEmpty(Exception $cause = null) 82 | { 83 | return new static('The command name must be set.', self::NAME_EMPTY, $cause); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Api/Command/NoSuchCommandException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Command; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | 17 | /** 18 | * Thrown when a command was not found. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class NoSuchCommandException extends RuntimeException 25 | { 26 | /** 27 | * Creates an exception for the given command name. 28 | * 29 | * @param string $name The command name. 30 | * @param int $code The exception code. 31 | * @param Exception $cause The exception that caused this exception. 32 | * 33 | * @return static The created exception. 34 | */ 35 | public static function forCommandName($name, $code = 0, Exception $cause = null) 36 | { 37 | return new static(sprintf( 38 | 'The command "%s" does not exist.', 39 | $name 40 | ), $code, $cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Api/Config/SubCommandConfig.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Config; 13 | 14 | /** 15 | * The configuration of an console sub-command. 16 | * 17 | * A sub-command is defined within the scope of another command. For example, 18 | * in the command `server add `, the command "add" is a sub-command of the 19 | * "server" command. 20 | * 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | * 25 | * @see OptionCommandConfig 26 | */ 27 | class SubCommandConfig extends CommandConfig 28 | { 29 | /** 30 | * @var CommandConfig 31 | */ 32 | private $parentConfig; 33 | 34 | /** 35 | * Creates a new configuration. 36 | * 37 | * @param string $name The name of the command. 38 | * @param CommandConfig $parentConfig The command configuration that 39 | * contains this configuration. 40 | */ 41 | public function __construct($name = null, CommandConfig $parentConfig = null) 42 | { 43 | parent::__construct($name); 44 | 45 | if ($parentConfig) { 46 | $this->setParentConfig($parentConfig); 47 | } 48 | } 49 | 50 | /** 51 | * Returns the parent command configuration. 52 | * 53 | * @return CommandConfig The parent command configuration. 54 | */ 55 | public function getParentConfig() 56 | { 57 | return $this->parentConfig; 58 | } 59 | 60 | /** 61 | * Sets the parent command configuration. 62 | * 63 | * @param CommandConfig $parentConfig The parent command configuration. 64 | */ 65 | public function setParentConfig(CommandConfig $parentConfig) 66 | { 67 | $this->parentConfig = $parentConfig; 68 | 69 | if ($parentConfig->getApplicationConfig()) { 70 | $this->setApplicationConfig($parentConfig->getApplicationConfig()); 71 | } 72 | } 73 | 74 | /** 75 | * Ends the block when dynamically configuring a nested configuration. 76 | * 77 | * This method is usually used together with 78 | * {@link CommandConfig::beginSubCommand()}, 79 | * {@link CommandConfig::beginOptionCommand()} or 80 | * {@link CommandConfig::beginDefaultCommand()}: 81 | * 82 | * ```php 83 | * $config 84 | * ->beginSubCommand('add') 85 | * // ... 86 | * ->end() 87 | * 88 | * // ... 89 | * ; 90 | * ``` 91 | * 92 | * @return CommandConfig|SubCommandConfig|OptionCommandConfig The parent command configuration. 93 | */ 94 | public function end() 95 | { 96 | return $this->parentConfig; 97 | } 98 | 99 | /** 100 | * {@inheritdoc} 101 | */ 102 | protected function getDefaultHelperSet() 103 | { 104 | return $this->parentConfig 105 | ? $this->parentConfig->getHelperSet() 106 | : parent::getDefaultHelperSet(); 107 | } 108 | 109 | /** 110 | * {@inheritdoc} 111 | */ 112 | protected function getDefaultHandler() 113 | { 114 | return $this->parentConfig 115 | ? $this->parentConfig->getHandler() 116 | : parent::getDefaultHandler(); 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | protected function getDefaultHandlerMethod() 123 | { 124 | return $this->parentConfig 125 | ? $this->parentConfig->getHandlerMethod() 126 | : parent::getDefaultHandlerMethod(); 127 | } 128 | 129 | /** 130 | * {@inheritdoc} 131 | */ 132 | protected function getDefaultArgsParser() 133 | { 134 | return $this->parentConfig 135 | ? $this->parentConfig->getArgsParser() 136 | : parent::getDefaultArgsParser(); 137 | } 138 | 139 | /** 140 | * {@inheritdoc} 141 | */ 142 | protected function getDefaultLenientArgsParsing() 143 | { 144 | return $this->parentConfig 145 | ? $this->parentConfig->isLenientArgsParsingEnabled() 146 | : parent::getDefaultLenientArgsParsing(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Api/Event/ConfigEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Event; 13 | 14 | use Symfony\Component\EventDispatcher\Event; 15 | use Webmozart\Console\Api\Config\ApplicationConfig; 16 | 17 | /** 18 | * Dispatched after the configuration is built. 19 | * 20 | * Use this event to add custom configuration to the application. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class ConfigEvent extends Event 27 | { 28 | /** 29 | * @var ApplicationConfig 30 | */ 31 | private $config; 32 | 33 | /** 34 | * Creates the event. 35 | * 36 | * @param ApplicationConfig $config The application configuration. 37 | */ 38 | public function __construct(ApplicationConfig $config) 39 | { 40 | $this->config = $config; 41 | } 42 | 43 | /** 44 | * Returns the application configuration. 45 | * 46 | * @return ApplicationConfig The application configuration. 47 | */ 48 | public function getConfig() 49 | { 50 | return $this->config; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Api/Event/ConsoleEvents.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Event; 13 | 14 | /** 15 | * Contains all the events supported by this package. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | final class ConsoleEvents 22 | { 23 | /** 24 | * Dispatched before console arguments are resolved to a command. 25 | * 26 | * @see PreResolveEvent 27 | */ 28 | const PRE_RESOLVE = 'pre-resolve'; 29 | 30 | /** 31 | * Dispatched before a command is handled. 32 | * 33 | * @see PreHandleEvent 34 | */ 35 | const PRE_HANDLE = 'pre-handle'; 36 | 37 | /** 38 | * Dispatched after building the configuration. 39 | * 40 | * @see ConfigEvent 41 | */ 42 | const CONFIG = 'config'; 43 | 44 | /** 45 | * May not be instantiated. 46 | */ 47 | private function __construct() 48 | { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Api/Event/PreHandleEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Event; 13 | 14 | use Symfony\Component\EventDispatcher\Event; 15 | use Webmozart\Console\Api\Args\Args; 16 | use Webmozart\Console\Api\Command\Command; 17 | use Webmozart\Console\Api\IO\IO; 18 | 19 | /** 20 | * Dispatched before a command is handled. 21 | * 22 | * Add a listener for this event to execute custom logic before or instead of 23 | * the default handler. 24 | * 25 | * @since 1.0 26 | * 27 | * @author Bernhard Schussek 28 | */ 29 | class PreHandleEvent extends Event 30 | { 31 | /** 32 | * @var Args 33 | */ 34 | private $args; 35 | 36 | /** 37 | * @var IO 38 | */ 39 | private $io; 40 | 41 | /** 42 | * @var Command 43 | */ 44 | private $command; 45 | 46 | /** 47 | * @var bool 48 | */ 49 | private $handled = false; 50 | 51 | /** 52 | * @var int 53 | */ 54 | private $statusCode = 0; 55 | 56 | /** 57 | * Creates the event. 58 | * 59 | * @param Args $args The parsed console arguments. 60 | * @param IO $io The I/O. 61 | * @param Command $command The executed command. 62 | */ 63 | public function __construct(Args $args, IO $io, Command $command) 64 | { 65 | $this->args = $args; 66 | $this->io = $io; 67 | $this->command = $command; 68 | } 69 | 70 | /** 71 | * Returns the parsed console arguments. 72 | * 73 | * @return Args The parsed console arguments. 74 | */ 75 | public function getArgs() 76 | { 77 | return $this->args; 78 | } 79 | 80 | /** 81 | * Returns the I/O. 82 | * 83 | * @return IO The I/O. 84 | */ 85 | public function getIO() 86 | { 87 | return $this->io; 88 | } 89 | 90 | /** 91 | * Returns the executed command. 92 | * 93 | * @return Command The executed command. 94 | */ 95 | public function getCommand() 96 | { 97 | return $this->command; 98 | } 99 | 100 | /** 101 | * Returns whether the command was handled by the event listener. 102 | * 103 | * @return bool Returns `true` if the command was handled and `false` 104 | * otherwise. 105 | * 106 | * @see setHandled() 107 | */ 108 | public function isHandled() 109 | { 110 | return $this->handled; 111 | } 112 | 113 | /** 114 | * Sets whether the command was handled by the event listener. 115 | * 116 | * If set to `true`, the handler configured for the command is not 117 | * executed. Instead the status code returned by {@link getStatusCode()} 118 | * is returned. 119 | * 120 | * @param bool $handled Whether the command was handled by the event 121 | * listener. 122 | */ 123 | public function setHandled($handled) 124 | { 125 | $this->handled = (bool) $handled; 126 | } 127 | 128 | /** 129 | * Returns the status code to return. 130 | * 131 | * @return int Returns 0 on success and any positive integer on error. 132 | */ 133 | public function getStatusCode() 134 | { 135 | return $this->statusCode; 136 | } 137 | 138 | /** 139 | * Sets the status code to return. 140 | * 141 | * This method is only useful in combination with {@link setHandled()}. 142 | * If the event is not marked as handled, the status code is ignored. 143 | * 144 | * @param int $statusCode Set to 0 on success and any positive integer on 145 | * error. 146 | */ 147 | public function setStatusCode($statusCode) 148 | { 149 | $this->statusCode = (int) $statusCode; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/Api/Event/PreResolveEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Event; 13 | 14 | use Symfony\Component\EventDispatcher\Event; 15 | use Webmozart\Console\Api\Application\Application; 16 | use Webmozart\Console\Api\Args\RawArgs; 17 | use Webmozart\Console\Api\Resolver\ResolvedCommand; 18 | 19 | /** 20 | * Dispatched before the console arguments are resolved to a command. 21 | * 22 | * Add a listener for this event to customize the command used for the given 23 | * console arguments. 24 | * 25 | * @since 1.0 26 | * 27 | * @author Bernhard Schussek 28 | */ 29 | class PreResolveEvent extends Event 30 | { 31 | /** 32 | * @var RawArgs 33 | */ 34 | private $rawArgs; 35 | 36 | /** 37 | * @var Application 38 | */ 39 | private $application; 40 | 41 | /** 42 | * @var ResolvedCommand 43 | */ 44 | private $resolvedCommand; 45 | 46 | /** 47 | * Creates the event. 48 | * 49 | * @param RawArgs $rawArgs The raw console arguments. 50 | * @param Application $application The application. 51 | */ 52 | public function __construct(RawArgs $rawArgs, Application $application) 53 | { 54 | $this->rawArgs = $rawArgs; 55 | $this->application = $application; 56 | } 57 | 58 | /** 59 | * Returns the raw console arguments. 60 | * 61 | * @return RawArgs The raw console arguments. 62 | */ 63 | public function getRawArgs() 64 | { 65 | return $this->rawArgs; 66 | } 67 | 68 | /** 69 | * Returns the application. 70 | * 71 | * @return Application The application. 72 | */ 73 | public function getApplication() 74 | { 75 | return $this->application; 76 | } 77 | 78 | /** 79 | * Returns the resolved command. 80 | * 81 | * @return ResolvedCommand Returns the resolved command or `null` if none 82 | * was set. 83 | */ 84 | public function getResolvedCommand() 85 | { 86 | return $this->resolvedCommand; 87 | } 88 | 89 | /** 90 | * Sets the resolved command. 91 | * 92 | * @param ResolvedCommand $resolvedCommand The resolved command. Set to 93 | * `null` to let the configured 94 | * resolver decide. 95 | */ 96 | public function setResolvedCommand(ResolvedCommand $resolvedCommand = null) 97 | { 98 | $this->resolvedCommand = $resolvedCommand; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Api/Formatter/Formatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Formatter; 13 | 14 | /** 15 | * Formats strings. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | interface Formatter 22 | { 23 | /** 24 | * Formats the given string. 25 | * 26 | * @param string $string The string to format. 27 | * @param Style $style The style to use. 28 | * 29 | * @return string The formatted string. 30 | */ 31 | public function format($string, Style $style = null); 32 | 33 | /** 34 | * Removes the format tags from the given string. 35 | * 36 | * @param string $string The string to remove the format tags from. 37 | * 38 | * @return string The string without format tags. 39 | */ 40 | public function removeFormat($string); 41 | } 42 | -------------------------------------------------------------------------------- /src/Api/Formatter/StyleSet.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Formatter; 13 | 14 | use LogicException; 15 | use OutOfBoundsException; 16 | 17 | /** 18 | * A set of styles used by the formatter. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class StyleSet 25 | { 26 | /** 27 | * @var Style[] 28 | */ 29 | private $styles = array(); 30 | 31 | /** 32 | * Creates a new style set. 33 | * 34 | * @param Style[] $styles The styles to add. 35 | */ 36 | public function __construct(array $styles = array()) 37 | { 38 | $this->replace($styles); 39 | } 40 | 41 | /** 42 | * Adds a style. 43 | * 44 | * @param Style $style The style to add. 45 | * 46 | * @throws LogicException If the tag of the style is not set. 47 | */ 48 | public function add(Style $style) 49 | { 50 | if (!$style->getTag()) { 51 | throw new LogicException('The tag of a style added to the style set must be set.'); 52 | } 53 | 54 | $this->styles[$style->getTag()] = $style; 55 | } 56 | 57 | /** 58 | * Adds styles to the style set. 59 | * 60 | * Existing styles are preserved. 61 | * 62 | * @param Style[] $styles The styles to add. 63 | */ 64 | public function merge(array $styles) 65 | { 66 | foreach ($styles as $style) { 67 | $this->add($style); 68 | } 69 | } 70 | 71 | /** 72 | * Sets the styles of the style set. 73 | * 74 | * Existing styles are removed. 75 | * 76 | * @param Style[] $styles The styles to set. 77 | */ 78 | public function replace(array $styles) 79 | { 80 | $this->styles = array(); 81 | 82 | $this->merge($styles); 83 | } 84 | 85 | /** 86 | * Removes a style. 87 | * 88 | * This method does nothing if the tag does not exist. 89 | * 90 | * @param string $tag The tag of the style. 91 | */ 92 | public function remove($tag) 93 | { 94 | unset($this->styles[$tag]); 95 | } 96 | 97 | /** 98 | * Clears the contents of the style set. 99 | */ 100 | public function clear() 101 | { 102 | $this->styles = array(); 103 | } 104 | 105 | /** 106 | * Returns whether the style with the given tag exists. 107 | * 108 | * @param string $tag The tag of the style. 109 | * 110 | * @return bool Returns `true` if a style with the given tag exists and 111 | * `false` otherwise. 112 | */ 113 | public function contains($tag) 114 | { 115 | return isset($this->styles[$tag]); 116 | } 117 | 118 | /** 119 | * Returns whether the style set is empty. 120 | * 121 | * @return bool Returns `true` if the set contains no styles and `false` 122 | * otherwise. 123 | */ 124 | public function isEmpty() 125 | { 126 | return 0 === count($this->styles); 127 | } 128 | 129 | /** 130 | * Returns the style with the given tag. 131 | * 132 | * @param string $tag The tag of the style. 133 | * 134 | * @return Style The style. 135 | * 136 | * @throws OutOfBoundsException If no style is set for the given tag. 137 | */ 138 | public function get($tag) 139 | { 140 | if (!isset($this->styles[$tag])) { 141 | throw new OutOfBoundsException(sprintf( 142 | 'The style tag "%s" does not exist.', 143 | $tag 144 | )); 145 | } 146 | 147 | return $this->styles[$tag]; 148 | } 149 | 150 | /** 151 | * Returns all styles. 152 | * 153 | * @return Style[] The styles indexed by their tags. 154 | */ 155 | public function toArray() 156 | { 157 | return $this->styles; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Api/IO/IOException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\IO; 13 | 14 | use RuntimeException; 15 | 16 | /** 17 | * Thrown if an error happens during I/O. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class IOException extends RuntimeException 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /src/Api/IO/Input.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\IO; 13 | 14 | /** 15 | * The console input. 16 | * 17 | * This class wraps an input stream and adds convenience functionality for 18 | * reading that stream. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class Input 25 | { 26 | /** 27 | * @var InputStream 28 | */ 29 | private $stream; 30 | 31 | /** 32 | * @var bool 33 | */ 34 | private $interactive = true; 35 | 36 | /** 37 | * Creates an input for the given input stream. 38 | * 39 | * @param InputStream $stream The input stream. 40 | */ 41 | public function __construct(InputStream $stream) 42 | { 43 | $this->stream = $stream; 44 | } 45 | 46 | /** 47 | * Reads the given amount of characters from the input stream. 48 | * 49 | * @param int $length The number of characters to read. 50 | * @param string $default The default to return if interaction is disabled. 51 | * 52 | * @return string The characters read from the input stream. 53 | * 54 | * @throws IOException If reading fails or if the input stream is closed. 55 | */ 56 | public function read($length, $default = null) 57 | { 58 | if (!$this->interactive) { 59 | return $default; 60 | } 61 | 62 | return $this->stream->read($length); 63 | } 64 | 65 | /** 66 | * Reads a line from the input stream. 67 | * 68 | * @param string $default The default to return if interaction is disabled. 69 | * @param int $length The maximum number of characters to read. If 70 | * `null`, all characters up to the first newline are 71 | * returned. 72 | * 73 | * @return string The characters read from the input stream. 74 | * 75 | * @throws IOException If reading fails or if the input stream is closed. 76 | */ 77 | public function readLine($default = null, $length = null) 78 | { 79 | if (!$this->interactive) { 80 | return $default; 81 | } 82 | 83 | return $this->stream->readLine($length); 84 | } 85 | 86 | /** 87 | * Closes the input. 88 | */ 89 | public function close() 90 | { 91 | $this->stream->close(); 92 | } 93 | 94 | /** 95 | * Returns whether the input is closed. 96 | * 97 | * @return bool Returns `true` if the input is closed and `false` 98 | * otherwise. 99 | */ 100 | public function isClosed() 101 | { 102 | return $this->stream->isClosed(); 103 | } 104 | 105 | /** 106 | * Sets the underlying stream. 107 | * 108 | * @param InputStream $stream The input stream. 109 | */ 110 | public function setStream(InputStream $stream) 111 | { 112 | $this->stream = $stream; 113 | } 114 | 115 | /** 116 | * Returns the underlying stream. 117 | * 118 | * @return InputStream The input stream. 119 | */ 120 | public function getStream() 121 | { 122 | return $this->stream; 123 | } 124 | 125 | /** 126 | * Enables or disables interaction with the user. 127 | * 128 | * @param bool $interactive Whether the inputmay interact with the user. If 129 | * set to `false`, all calls to {@link read()} and 130 | * {@link readLine()} will immediately return the 131 | * default value. 132 | */ 133 | public function setInteractive($interactive) 134 | { 135 | $this->interactive = (bool) $interactive; 136 | } 137 | 138 | /** 139 | * Returns whether the user may be asked for input. 140 | * 141 | * @return bool Returns `true` if the user may be asked for input and 142 | * `false` otherwise. 143 | */ 144 | public function isInteractive() 145 | { 146 | return $this->interactive; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Api/IO/InputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\IO; 13 | 14 | /** 15 | * The console input stream. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | interface InputStream 22 | { 23 | /** 24 | * Reads the given amount of characters from the stream. 25 | * 26 | * @param int $length The number of characters to read. 27 | * 28 | * @return string The characters read from the stream. 29 | * 30 | * @throws IOException If reading fails or if the stream is closed. 31 | */ 32 | public function read($length); 33 | 34 | /** 35 | * Reads a line from the stream. 36 | * 37 | * @param int $length The maximum number of characters to read. If `null`, 38 | * all characters up to the first newline are returned. 39 | * 40 | * @return string The characters read from the stream. 41 | * 42 | * @throws IOException If reading fails or if the stream is closed. 43 | */ 44 | public function readLine($length = null); 45 | 46 | /** 47 | * Closes the stream. 48 | */ 49 | public function close(); 50 | 51 | /** 52 | * Returns whether the stream is closed. 53 | * 54 | * @return bool Returns `true` if the stream is closed. 55 | */ 56 | public function isClosed(); 57 | } 58 | -------------------------------------------------------------------------------- /src/Api/IO/OutputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\IO; 13 | 14 | /** 15 | * The console output stream. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | interface OutputStream 22 | { 23 | /** 24 | * Writes a string to the stream. 25 | * 26 | * @param string $string The string to write. 27 | * 28 | * @throws IOException If writing fails or if the stream is closed. 29 | */ 30 | public function write($string); 31 | 32 | /** 33 | * Flushes the stream and forces all pending text to be written out. 34 | * 35 | * @throws IOException If flushing fails or if the stream is closed. 36 | */ 37 | public function flush(); 38 | 39 | /** 40 | * Returns whether the stream supports ANSI format codes. 41 | * 42 | * @return bool Returns `true` if the stream supports ANSI format codes and 43 | * `false` otherwise. 44 | */ 45 | public function supportsAnsi(); 46 | 47 | /** 48 | * Closes the stream. 49 | */ 50 | public function close(); 51 | 52 | /** 53 | * Returns whether the stream is closed. 54 | * 55 | * @return bool Returns `true` if the stream is closed. 56 | */ 57 | public function isClosed(); 58 | } 59 | -------------------------------------------------------------------------------- /src/Api/Resolver/CannotResolveCommandException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Resolver; 13 | 14 | use Exception; 15 | use RuntimeException; 16 | use Webmozart\Console\Api\Command\CommandCollection; 17 | use Webmozart\Console\Util\SimilarCommandName; 18 | 19 | /** 20 | * Thrown when a command cannot be resolved. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class CannotResolveCommandException extends RuntimeException 27 | { 28 | /** 29 | * Code: The passed command name was not found. 30 | */ 31 | const NAME_NOT_FOUND = 1; 32 | 33 | /** 34 | * Code: No command was passed and no default was configured. 35 | */ 36 | const NO_DEFAULT_COMMAND = 2; 37 | 38 | /** 39 | * Creates an exception for the code {@link NAME_NOT_FOUND}. 40 | * 41 | * Suggested alternatives are searched in the passed commands. 42 | * 43 | * @param string $commandName The command name that was not found. 44 | * @param CommandCollection $commands A list of available commands that 45 | * is searched for similar names. 46 | * @param Exception $cause The exception that caused this 47 | * exception. 48 | * 49 | * @return static The created exception. 50 | */ 51 | public static function nameNotFound($commandName, CommandCollection $commands, Exception $cause = null) 52 | { 53 | $message = sprintf('The command "%s" is not defined.', $commandName); 54 | 55 | $suggestedNames = SimilarCommandName::find($commandName, $commands); 56 | 57 | if (count($suggestedNames) > 0) { 58 | if (1 === count($suggestedNames)) { 59 | $message .= "\n\nDid you mean this?\n "; 60 | } else { 61 | $message .= "\n\nDid you mean one of these?\n "; 62 | } 63 | $message .= implode("\n ", $suggestedNames); 64 | } 65 | 66 | return new static($message, self::NAME_NOT_FOUND, $cause); 67 | } 68 | 69 | /** 70 | * Creates an exception for the code {@link NO_DEFAULT_COMMAND}. 71 | * 72 | * @param Exception $cause The exception that caused this exception. 73 | * 74 | * @return static The created exception. 75 | */ 76 | public static function noDefaultCommand(Exception $cause = null) 77 | { 78 | return new static('No default command is defined.', self::NO_DEFAULT_COMMAND, $cause); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Api/Resolver/CommandResolver.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Resolver; 13 | 14 | use Webmozart\Console\Api\Application\Application; 15 | use Webmozart\Console\Api\Args\RawArgs; 16 | 17 | /** 18 | * Returns the command to execute for the given console arguments. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | interface CommandResolver 25 | { 26 | /** 27 | * Returns the command to execute for the given console arguments. 28 | * 29 | * @param RawArgs $args The console arguments. 30 | * @param Application $application The application. 31 | * 32 | * @return ResolvedCommand The command to execute. 33 | * 34 | * @throws CannotResolveCommandException If the command cannot be resolved. 35 | */ 36 | public function resolveCommand(RawArgs $args, Application $application); 37 | } 38 | -------------------------------------------------------------------------------- /src/Api/Resolver/ResolvedCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Api\Resolver; 13 | 14 | use Webmozart\Console\Api\Args\Args; 15 | use Webmozart\Console\Api\Args\RawArgs; 16 | use Webmozart\Console\Api\Command\Command; 17 | 18 | /** 19 | * A resolved command. 20 | * 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class ResolvedCommand 26 | { 27 | /** 28 | * @var Command 29 | */ 30 | private $command; 31 | 32 | /** 33 | * @var RawArgs 34 | */ 35 | private $args; 36 | 37 | /** 38 | * Creates a new resolved command. 39 | * 40 | * @param Command $command The command. 41 | * @param Args $args The console arguments. 42 | */ 43 | public function __construct(Command $command, Args $args) 44 | { 45 | $this->command = $command; 46 | $this->args = $args; 47 | } 48 | 49 | /** 50 | * Returns the command. 51 | * 52 | * @return Command The command. 53 | */ 54 | public function getCommand() 55 | { 56 | return $this->command; 57 | } 58 | 59 | /** 60 | * Returns the parsed console arguments. 61 | * 62 | * @return Args The parsed console arguments. 63 | */ 64 | public function getArgs() 65 | { 66 | return $this->args; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Args/ArgvArgs.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Args; 13 | 14 | use Webmozart\Console\Api\Args\RawArgs; 15 | 16 | /** 17 | * Console arguments passed via PHP's "argv" variable. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class ArgvArgs implements RawArgs 24 | { 25 | /** 26 | * @var string 27 | */ 28 | private $scriptName; 29 | 30 | /** 31 | * @var string[] 32 | */ 33 | private $tokens; 34 | 35 | /** 36 | * Creates the console arguments. 37 | * 38 | * @param array $argv The contents of the "argv" variable or `null` to read 39 | * the global "argv" variable. 40 | */ 41 | public function __construct(array $argv = null) 42 | { 43 | if (null === $argv) { 44 | $argv = $_SERVER['argv']; 45 | } 46 | 47 | $this->scriptName = array_shift($argv); 48 | $this->tokens = $argv; 49 | } 50 | 51 | /** 52 | * {@inheritdoc} 53 | */ 54 | public function getScriptName() 55 | { 56 | return $this->scriptName; 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function hasToken($token) 63 | { 64 | return in_array($token, $this->tokens); 65 | } 66 | 67 | /** 68 | * {@inheritdoc} 69 | */ 70 | public function getTokens() 71 | { 72 | return $this->tokens; 73 | } 74 | 75 | /** 76 | * {@inheritdoc} 77 | */ 78 | public function toString($scriptName = true) 79 | { 80 | $string = implode(' ', $this->tokens); 81 | 82 | if ($scriptName) { 83 | $string = ltrim($this->scriptName.' ').$string; 84 | } 85 | 86 | return $string; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Args/StringArgs.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Args; 13 | 14 | use Webmozart\Console\Api\Args\RawArgs; 15 | 16 | /** 17 | * Console arguments passed as a string. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class StringArgs implements RawArgs 24 | { 25 | /** 26 | * @var string[] 27 | */ 28 | private $tokens; 29 | 30 | /** 31 | * Creates the console arguments. 32 | * 33 | * @param string $string The console arguments string. 34 | */ 35 | public function __construct($string) 36 | { 37 | $parser = new TokenParser(); 38 | 39 | $this->tokens = $parser->parseTokens($string); 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function getScriptName() 46 | { 47 | return null; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function hasToken($token) 54 | { 55 | return in_array($token, $this->tokens); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function getTokens() 62 | { 63 | return $this->tokens; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function toString($scriptName = true) 70 | { 71 | return implode(' ', $this->tokens); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Formatter/AnsiFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Formatter; 13 | 14 | use Symfony\Component\Console\Formatter\OutputFormatter; 15 | use Webmozart\Console\Adapter\StyleConverter; 16 | use Webmozart\Console\Api\Formatter\Formatter; 17 | use Webmozart\Console\Api\Formatter\Style; 18 | use Webmozart\Console\Api\Formatter\StyleSet; 19 | 20 | /** 21 | * A formatter that replaces style tags by ANSI format codes. 22 | * 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class AnsiFormatter implements Formatter 28 | { 29 | /** 30 | * @var OutputFormatter 31 | */ 32 | private $innerFormatter; 33 | 34 | /** 35 | * Creates the formatter. 36 | * 37 | * @param StyleSet $styleSet The style set to use. 38 | */ 39 | public function __construct(StyleSet $styleSet = null) 40 | { 41 | $this->innerFormatter = new OutputFormatter(true); 42 | 43 | if (!$styleSet) { 44 | $styleSet = new DefaultStyleSet(); 45 | } 46 | 47 | foreach ($styleSet->toArray() as $tag => $style) { 48 | $this->innerFormatter->setStyle($tag, StyleConverter::convert($style)); 49 | } 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function format($string, Style $style = null) 56 | { 57 | if (null !== $style) { 58 | $this->innerFormatter->getStyleStack()->push(StyleConverter::convert($style)); 59 | } 60 | 61 | $formatted = $this->innerFormatter->format($string); 62 | 63 | if (null !== $style) { 64 | $this->innerFormatter->getStyleStack()->pop(); 65 | } 66 | 67 | return $formatted; 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | public function removeFormat($string) 74 | { 75 | $this->innerFormatter->setDecorated(false); 76 | $formatted = $this->innerFormatter->format($string); 77 | $this->innerFormatter->setDecorated(true); 78 | 79 | return $formatted; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Formatter/DefaultStyleSet.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Formatter; 13 | 14 | use Webmozart\Console\Api\Formatter\Style; 15 | use Webmozart\Console\Api\Formatter\StyleSet; 16 | 17 | /** 18 | * A color style which prefers cyan for its good readability. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class DefaultStyleSet extends StyleSet 25 | { 26 | public function __construct() 27 | { 28 | $this->replace(array( 29 | // Default styles 30 | Style::tag('b')->bold(), 31 | Style::tag('u')->underlined(), 32 | Style::tag('bu')->bold()->underlined(), 33 | Style::tag('c1')->fgCyan(), 34 | Style::tag('c2')->fgYellow(), 35 | Style::tag('error')->fgWhite()->bgRed(), 36 | Style::tag('warn')->fgBlack()->bgYellow(), 37 | 38 | // Adapted Symfony default styles 39 | Style::tag('info')->fgCyan(), 40 | Style::tag('comment')->fgCyan(), 41 | Style::tag('question')->fgBlack()->bgCyan(), 42 | )); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Formatter/NullFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Formatter; 13 | 14 | use Webmozart\Console\Api\Formatter\Formatter; 15 | use Webmozart\Console\Api\Formatter\Style; 16 | 17 | /** 18 | * A formatter that returns all text unchanged. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class NullFormatter implements Formatter 25 | { 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | public function format($string, Style $style = null) 30 | { 31 | return $string; 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function removeFormat($string) 38 | { 39 | return $string; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Formatter/PlainFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Formatter; 13 | 14 | use Symfony\Component\Console\Formatter\OutputFormatter; 15 | use Webmozart\Console\Adapter\StyleConverter; 16 | use Webmozart\Console\Api\Formatter\Formatter; 17 | use Webmozart\Console\Api\Formatter\Style; 18 | use Webmozart\Console\Api\Formatter\StyleSet; 19 | 20 | /** 21 | * A formatter that removes all format tags. 22 | * 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class PlainFormatter implements Formatter 28 | { 29 | /** 30 | * @var OutputFormatter 31 | */ 32 | private $innerFormatter; 33 | 34 | /** 35 | * Creates the formatter. 36 | * 37 | * @param StyleSet $styleSet The style set to use. 38 | */ 39 | public function __construct(StyleSet $styleSet = null) 40 | { 41 | $this->innerFormatter = new OutputFormatter(false); 42 | 43 | if (!$styleSet) { 44 | $styleSet = new DefaultStyleSet(); 45 | } 46 | 47 | foreach ($styleSet->toArray() as $tag => $style) { 48 | $this->innerFormatter->setStyle($tag, StyleConverter::convert($style)); 49 | } 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function format($string, Style $style = null) 56 | { 57 | return $this->innerFormatter->format($string); 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | public function removeFormat($string) 64 | { 65 | return $this->innerFormatter->format($string); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Handler/CallbackHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler; 13 | 14 | use Webmozart\Assert\Assert; 15 | use Webmozart\Console\Api\Args\Args; 16 | use Webmozart\Console\Api\Command\Command; 17 | use Webmozart\Console\Api\IO\IO; 18 | 19 | /** 20 | * Delegates command handling to a callable. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class CallbackHandler 27 | { 28 | /** 29 | * @var callable 30 | */ 31 | private $callback; 32 | 33 | /** 34 | * Creates the command handler. 35 | * 36 | * The passed callback receives three arguments: 37 | * 38 | * * {@link Args} `$args`: The console arguments. 39 | * * {@link IO} `$io`: The I/O. 40 | * * {@link Command} `$command`: The executed command. 41 | * 42 | * The callable should return 0 on success and a positive integer on error. 43 | * 44 | * @param callable $callback The callback to execute when handling a 45 | * command. 46 | */ 47 | public function __construct($callback) 48 | { 49 | Assert::isCallable($callback); 50 | 51 | $this->callback = $callback; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function handle(Args $args, IO $io, Command $command) 58 | { 59 | return call_user_func($this->callback, $args, $io, $command); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Handler/Help/HelpAsciiDocHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler\Help; 13 | 14 | use Symfony\Component\Process\ExecutableFinder; 15 | use Webmozart\Assert\Assert; 16 | use Webmozart\Console\Api\Args\Args; 17 | use Webmozart\Console\Api\IO\IO; 18 | use Webmozart\Console\Process\ProcessLauncher; 19 | 20 | /** 21 | * Displays the application/command help as AsciiDoc. 22 | * 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class HelpAsciiDocHandler 28 | { 29 | /** 30 | * @var string 31 | */ 32 | private $path; 33 | 34 | /** 35 | * @var string 36 | */ 37 | private $lessBinary; 38 | 39 | /** 40 | * @var ExecutableFinder 41 | */ 42 | private $executableFinder; 43 | 44 | /** 45 | * @var ProcessLauncher 46 | */ 47 | private $processLauncher; 48 | 49 | /** 50 | * Creates the handler. 51 | * 52 | * @param string $path The path to the AsciiDoc file. 53 | * @param ExecutableFinder $executableFinder The finder used to find the 54 | * "less" binary. 55 | * @param ProcessLauncher $processLauncher The launcher for executing the 56 | * "less" binary. 57 | */ 58 | public function __construct($path, ExecutableFinder $executableFinder = null, ProcessLauncher $processLauncher = null) 59 | { 60 | Assert::file($path); 61 | 62 | $this->path = $path; 63 | $this->executableFinder = $executableFinder ?: new ExecutableFinder(); 64 | $this->processLauncher = $processLauncher ?: new ProcessLauncher(); 65 | } 66 | 67 | /** 68 | * {@inheritdoc} 69 | */ 70 | public function handle(Args $args, IO $io) 71 | { 72 | if ($this->processLauncher->isSupported()) { 73 | if (!$this->lessBinary) { 74 | $this->lessBinary = $this->executableFinder->find('less'); 75 | } 76 | 77 | if ($this->lessBinary) { 78 | return $this->processLauncher->launchProcess( 79 | escapeshellcmd($this->lessBinary).' %path%', 80 | array('path' => $this->path), 81 | false 82 | ); 83 | } 84 | } 85 | 86 | $io->write(file_get_contents($this->path)); 87 | 88 | return 0; 89 | } 90 | 91 | /** 92 | * Returns the "less" binary used to display the AsciiDoc page. 93 | * 94 | * @return string The "less" binary or `null` if the binary is auto-detected. 95 | */ 96 | public function getLessBinary() 97 | { 98 | return $this->lessBinary; 99 | } 100 | 101 | /** 102 | * Sets the "less" binary used to display the AsciiDoc page. 103 | * 104 | * @param string $lessBinary The "less" binary to use. 105 | */ 106 | public function setLessBinary($lessBinary) 107 | { 108 | if (null !== $lessBinary) { 109 | Assert::string($lessBinary, 'The less binary must be a string or null. Got: %s'); 110 | Assert::notEmpty($lessBinary, 'The less binary must not be empty.'); 111 | } 112 | 113 | $this->lessBinary = $lessBinary; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Handler/Help/HelpJsonHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler\Help; 13 | 14 | use Symfony\Component\Console\Descriptor\JsonDescriptor; 15 | use Webmozart\Console\Adapter\ApplicationAdapter; 16 | use Webmozart\Console\Adapter\CommandAdapter; 17 | use Webmozart\Console\Adapter\IOOutput; 18 | use Webmozart\Console\Api\Args\Args; 19 | use Webmozart\Console\Api\Command\Command; 20 | use Webmozart\Console\Api\IO\IO; 21 | 22 | /** 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class HelpJsonHandler 28 | { 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | public function handle(Args $args, IO $io, Command $command) 33 | { 34 | $descriptor = new JsonDescriptor(); 35 | $output = new IOOutput($io); 36 | $application = $command->getApplication(); 37 | $applicationAdapter = new ApplicationAdapter($application); 38 | 39 | if ($args->isArgumentSet('command')) { 40 | $theCommand = $application->getCommand($args->getArgument('command')); 41 | $commandAdapter = new CommandAdapter($theCommand, $applicationAdapter); 42 | $descriptor->describe($output, $commandAdapter); 43 | } else { 44 | $descriptor->describe($output, $applicationAdapter); 45 | } 46 | 47 | return 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Handler/Help/HelpManHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler\Help; 13 | 14 | use RuntimeException; 15 | use Symfony\Component\Process\ExecutableFinder; 16 | use Webmozart\Assert\Assert; 17 | use Webmozart\Console\Process\ProcessLauncher; 18 | 19 | /** 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class HelpManHandler 25 | { 26 | /** 27 | * @var string 28 | */ 29 | private $path; 30 | 31 | /** 32 | * @var string 33 | */ 34 | private $manBinary; 35 | 36 | /** 37 | * @var ExecutableFinder 38 | */ 39 | private $executableFinder; 40 | 41 | /** 42 | * @var ProcessLauncher 43 | */ 44 | private $processLauncher; 45 | 46 | /** 47 | * Creates a new AsciiDoc descriptor. 48 | * 49 | * @param ExecutableFinder $executableFinder The finder used to find the 50 | * "man" binary. 51 | * @param ProcessLauncher $processLauncher The launcher for executing the 52 | * "man" binary. 53 | */ 54 | public function __construct($path, ExecutableFinder $executableFinder = null, ProcessLauncher $processLauncher = null) 55 | { 56 | Assert::file($path); 57 | 58 | $this->path = $path; 59 | $this->executableFinder = $executableFinder ?: new ExecutableFinder(); 60 | $this->processLauncher = $processLauncher ?: new ProcessLauncher(); 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | */ 66 | public function handle() 67 | { 68 | if (!$this->processLauncher->isSupported()) { 69 | throw new RuntimeException('The ProcessLauncher must be supported for the man help to run.'); 70 | } 71 | 72 | if (!$this->manBinary) { 73 | $this->manBinary = $this->executableFinder->find('man'); 74 | } 75 | 76 | if (!$this->manBinary) { 77 | throw new RuntimeException('The "man" binary was not found.'); 78 | } 79 | 80 | return $this->processLauncher->launchProcess( 81 | escapeshellcmd($this->manBinary).' -l %path%', 82 | array('path' => $this->path), 83 | false 84 | ); 85 | } 86 | 87 | /** 88 | * @return string 89 | */ 90 | public function getManBinary() 91 | { 92 | return $this->manBinary; 93 | } 94 | 95 | /** 96 | * @param string $manBinary 97 | */ 98 | public function setManBinary($manBinary) 99 | { 100 | $this->manBinary = $manBinary; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Handler/Help/HelpTextHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler\Help; 13 | 14 | use Webmozart\Console\Api\Args\Args; 15 | use Webmozart\Console\Api\Command\Command; 16 | use Webmozart\Console\Api\IO\IO; 17 | use Webmozart\Console\UI\Help\ApplicationHelp; 18 | use Webmozart\Console\UI\Help\CommandHelp; 19 | 20 | /** 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class HelpTextHandler 26 | { 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function handle(Args $args, IO $io, Command $command) 31 | { 32 | $application = $command->getApplication(); 33 | 34 | if ($args->isArgumentSet('command')) { 35 | $theCommand = $application->getCommand($args->getArgument('command')); 36 | $usage = new CommandHelp($theCommand); 37 | } else { 38 | $usage = new ApplicationHelp($application); 39 | } 40 | 41 | $usage->render($io); 42 | 43 | return 0; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Handler/Help/HelpXmlHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler\Help; 13 | 14 | use Symfony\Component\Console\Descriptor\XmlDescriptor; 15 | use Webmozart\Console\Adapter\ApplicationAdapter; 16 | use Webmozart\Console\Adapter\CommandAdapter; 17 | use Webmozart\Console\Adapter\IOOutput; 18 | use Webmozart\Console\Api\Args\Args; 19 | use Webmozart\Console\Api\Command\Command; 20 | use Webmozart\Console\Api\IO\IO; 21 | 22 | /** 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class HelpXmlHandler 28 | { 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | public function handle(Args $args, IO $io, Command $command) 33 | { 34 | $descriptor = new XmlDescriptor(); 35 | $output = new IOOutput($io); 36 | $application = $command->getApplication(); 37 | $applicationAdapter = new ApplicationAdapter($application); 38 | 39 | if ($args->isArgumentSet('command')) { 40 | $theCommand = $application->getCommand($args->getArgument('command')); 41 | $commandAdapter = new CommandAdapter($theCommand, $applicationAdapter); 42 | $descriptor->describe($output, $commandAdapter); 43 | } else { 44 | $descriptor->describe($output, $applicationAdapter); 45 | } 46 | 47 | return 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Handler/NullHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Handler; 13 | 14 | use Webmozart\Console\Api\Args\Args; 15 | use Webmozart\Console\Api\Command\Command; 16 | use Webmozart\Console\Api\IO\IO; 17 | 18 | /** 19 | * A command handler that does nothing. 20 | * 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class NullHandler 26 | { 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function handle(Args $args, IO $io, Command $command) 31 | { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/IO/BufferedIO.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO; 13 | 14 | use Webmozart\Console\Api\Formatter\Formatter; 15 | use Webmozart\Console\Api\IO\Input; 16 | use Webmozart\Console\Api\IO\IO; 17 | use Webmozart\Console\Api\IO\Output; 18 | use Webmozart\Console\Formatter\PlainFormatter; 19 | use Webmozart\Console\IO\InputStream\StringInputStream; 20 | use Webmozart\Console\IO\OutputStream\BufferedOutputStream; 21 | 22 | /** 23 | * An I/O that reads from and writes to a buffer. 24 | * 25 | * @since 1.0 26 | * 27 | * @author Bernhard Schussek 28 | */ 29 | class BufferedIO extends IO 30 | { 31 | /** 32 | * Creates the I/O. 33 | * 34 | * @param string $inputData The data to return from the input. 35 | * @param Formatter $formatter The formatter to use. 36 | */ 37 | public function __construct($inputData = '', Formatter $formatter = null) 38 | { 39 | $formatter = $formatter ?: new PlainFormatter(); 40 | $input = new Input(new StringInputStream($inputData)); 41 | $output = new Output(new BufferedOutputStream(), $formatter); 42 | $errorOutput = new Output(new BufferedOutputStream(), $formatter); 43 | 44 | parent::__construct($input, $output, $errorOutput); 45 | } 46 | 47 | /** 48 | * Sets the contents of the input buffer. 49 | * 50 | * @param string $data The input data. 51 | */ 52 | public function setInput($data) 53 | { 54 | $this->getInput()->getStream()->set($data); 55 | } 56 | 57 | /** 58 | * Appends data to the input buffer. 59 | * 60 | * @param string $data The input data to append. 61 | */ 62 | public function appendInput($data) 63 | { 64 | $this->getInput()->getStream()->append($data); 65 | } 66 | 67 | /** 68 | * Clears the input buffer. 69 | */ 70 | public function clearInput() 71 | { 72 | $this->getInput()->getStream()->clear(); 73 | } 74 | 75 | /** 76 | * Returns the contents of the output buffer. 77 | * 78 | * @return string The output data. 79 | */ 80 | public function fetchOutput() 81 | { 82 | return $this->getOutput()->getStream()->fetch(); 83 | } 84 | 85 | /** 86 | * Clears the output buffer. 87 | */ 88 | public function clearOutput() 89 | { 90 | $this->getOutput()->getStream()->clear(); 91 | } 92 | 93 | /** 94 | * Returns the contents of the error output buffer. 95 | * 96 | * @return string The data of the error output. 97 | */ 98 | public function fetchErrors() 99 | { 100 | return $this->getErrorOutput()->getStream()->fetch(); 101 | } 102 | 103 | /** 104 | * Clears the error output buffer. 105 | */ 106 | public function clearErrors() 107 | { 108 | $this->getErrorOutput()->getStream()->clear(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/IO/ConsoleIO.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO; 13 | 14 | use Symfony\Component\Console\Application; 15 | use Webmozart\Console\Api\IO\Input; 16 | use Webmozart\Console\Api\IO\IO; 17 | use Webmozart\Console\Api\IO\Output; 18 | use Webmozart\Console\Formatter\AnsiFormatter; 19 | use Webmozart\Console\Formatter\PlainFormatter; 20 | use Webmozart\Console\IO\InputStream\StandardInputStream; 21 | use Webmozart\Console\IO\OutputStream\ErrorOutputStream; 22 | use Webmozart\Console\IO\OutputStream\StandardOutputStream; 23 | use Webmozart\Console\UI\Rectangle; 24 | 25 | /** 26 | * An I/O that reads from/prints to the console. 27 | * 28 | * @since 1.0 29 | * 30 | * @author Bernhard Schussek 31 | */ 32 | class ConsoleIO extends IO 33 | { 34 | /** 35 | * Creates the I/O. 36 | * 37 | * @param Input $input The standard input. 38 | * @param Output $output The standard output. 39 | * @param Output $errorOutput The error output. 40 | */ 41 | public function __construct(Input $input = null, Output $output = null, Output $errorOutput = null) 42 | { 43 | if (null === $input) { 44 | $inputStream = new StandardInputStream(); 45 | $input = new Input($inputStream); 46 | } 47 | 48 | if (null === $output) { 49 | $outputStream = new StandardOutputStream(); 50 | $formatter = $outputStream->supportsAnsi() ? new AnsiFormatter() : new PlainFormatter(); 51 | $output = new Output($outputStream, $formatter); 52 | } 53 | 54 | if (null === $errorOutput) { 55 | $errorStream = new ErrorOutputStream(); 56 | $formatter = $errorStream->supportsAnsi() ? new AnsiFormatter() : new PlainFormatter(); 57 | $errorOutput = new Output($errorStream, $formatter); 58 | } 59 | 60 | parent::__construct($input, $output, $errorOutput); 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | */ 66 | protected function getDefaultTerminalDimensions() 67 | { 68 | $application = new Application(); 69 | 70 | list($width, $height) = $application->getTerminalDimensions(); 71 | 72 | return new Rectangle($width ?: 80, $height ?: 20); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/IO/InputStream/NullInputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\InputStream; 13 | 14 | use Webmozart\Console\Api\IO\InputStream; 15 | 16 | /** 17 | * An input stream that returns nothing. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class NullInputStream implements InputStream 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function read($length) 29 | { 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function readLine($length = null) 36 | { 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function close() 43 | { 44 | } 45 | 46 | /** 47 | * {@inheritdoc} 48 | */ 49 | public function isClosed() 50 | { 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/IO/InputStream/StandardInputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\InputStream; 13 | 14 | /** 15 | * An input stream that reads from the standard input. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class StandardInputStream extends StreamInputStream 22 | { 23 | /** 24 | * Creates the input. 25 | */ 26 | public function __construct() 27 | { 28 | parent::__construct(fopen('php://stdin', 'r')); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/IO/InputStream/StreamInputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\InputStream; 13 | 14 | use Webmozart\Assert\Assert; 15 | use Webmozart\Console\Api\IO\InputStream; 16 | use Webmozart\Console\Api\IO\IOException; 17 | 18 | /** 19 | * An input stream that reads from a PHP stream. 20 | * 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class StreamInputStream implements InputStream 26 | { 27 | /** 28 | * @var resource 29 | */ 30 | private $stream; 31 | 32 | /** 33 | * Creates the input. 34 | * 35 | * @param resource $stream A stream resource. 36 | */ 37 | public function __construct($stream) 38 | { 39 | Assert::resource($stream, 'stream'); 40 | 41 | $this->stream = $stream; 42 | 43 | // Not all streams are seekable 44 | @rewind($this->stream); 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function read($length) 51 | { 52 | if (null === $this->stream) { 53 | throw new IOException('Cannot read from a closed input.'); 54 | } 55 | 56 | if (feof($this->stream)) { 57 | return null; 58 | } 59 | 60 | $data = fread($this->stream, $length); 61 | 62 | if (false === $data && !feof($this->stream)) { 63 | throw new IOException('Could not read stream.'); 64 | } 65 | 66 | return $data ?: null; 67 | } 68 | 69 | /** 70 | * {@inheritdoc} 71 | */ 72 | public function readLine($length = null) 73 | { 74 | if (null === $this->stream) { 75 | throw new IOException('Cannot read from a closed input.'); 76 | } 77 | 78 | if (feof($this->stream)) { 79 | return null; 80 | } 81 | 82 | if (null !== $length) { 83 | $data = fgets($this->stream, $length); 84 | } else { 85 | $data = fgets($this->stream); 86 | } 87 | 88 | if (false === $data && !feof($this->stream)) { 89 | throw new IOException('Could not read stream.'); 90 | } 91 | 92 | return $data ?: null; 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | */ 98 | public function close() 99 | { 100 | if ($this->stream) { 101 | @fclose($this->stream); 102 | $this->stream = null; 103 | } 104 | } 105 | 106 | /** 107 | * {@inheritdoc} 108 | */ 109 | public function isClosed() 110 | { 111 | return null === $this->stream; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/IO/InputStream/StringInputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\InputStream; 13 | 14 | /** 15 | * An input stream that reads from a string. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class StringInputStream extends StreamInputStream 22 | { 23 | /** 24 | * @var resource 25 | */ 26 | private $stream; 27 | 28 | /** 29 | * Creates the input stream. 30 | * 31 | * @param string $string The string to read from. 32 | */ 33 | public function __construct($string = '') 34 | { 35 | $this->stream = fopen('php://memory', 'rw'); 36 | 37 | parent::__construct($this->stream); 38 | 39 | $this->set($string); 40 | } 41 | 42 | /** 43 | * Clears the contents of the buffer. 44 | */ 45 | public function clear() 46 | { 47 | ftruncate($this->stream, 0); 48 | rewind($this->stream); 49 | } 50 | 51 | /** 52 | * Sets the string to read from. 53 | * 54 | * @param string $string The string to read from. 55 | */ 56 | public function set($string) 57 | { 58 | $this->clear(); 59 | 60 | fwrite($this->stream, $string); 61 | rewind($this->stream); 62 | } 63 | 64 | /** 65 | * Appends a string to the stream. 66 | * 67 | * @param string $string The string to append. 68 | */ 69 | public function append($string) 70 | { 71 | $pos = ftell($this->stream); 72 | fseek($this->stream, 0, SEEK_END); 73 | fwrite($this->stream, $string); 74 | fseek($this->stream, $pos); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/IO/OutputStream/BufferedOutputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\OutputStream; 13 | 14 | use Webmozart\Console\Api\IO\IOException; 15 | use Webmozart\Console\Api\IO\OutputStream; 16 | 17 | /** 18 | * An output stream that writes to a buffer. 19 | * 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class BufferedOutputStream implements OutputStream 25 | { 26 | /** 27 | * @var string 28 | */ 29 | private $buffer = ''; 30 | 31 | /** 32 | * @var bool 33 | */ 34 | private $closed = false; 35 | 36 | /** 37 | * Returns the contents of the buffer. 38 | * 39 | * @return string The buffered data. 40 | */ 41 | public function fetch() 42 | { 43 | return $this->buffer; 44 | } 45 | 46 | /** 47 | * Clears the buffer. 48 | */ 49 | public function clear() 50 | { 51 | $this->buffer = ''; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function write($string) 58 | { 59 | if ($this->closed) { 60 | throw new IOException('Cannot read from a closed input.'); 61 | } 62 | 63 | $this->buffer .= $string; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function flush() 70 | { 71 | if ($this->closed) { 72 | throw new IOException('Cannot read from a closed input.'); 73 | } 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function supportsAnsi() 80 | { 81 | return false; 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function close() 88 | { 89 | $this->closed = true; 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function isClosed() 96 | { 97 | return $this->closed; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/IO/OutputStream/ErrorOutputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\OutputStream; 13 | 14 | /** 15 | * An output stream that writes to the error output. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class ErrorOutputStream extends StreamOutputStream 22 | { 23 | /** 24 | * Creates the stream. 25 | */ 26 | public function __construct() 27 | { 28 | parent::__construct(fopen('php://stderr', 'w')); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/IO/OutputStream/NullOutputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\OutputStream; 13 | 14 | use Webmozart\Console\Api\IO\OutputStream; 15 | 16 | /** 17 | * An output stream that ignores all output. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class NullOutputStream implements OutputStream 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function write($string) 29 | { 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function flush() 36 | { 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function supportsAnsi() 43 | { 44 | return false; 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function close() 51 | { 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function isClosed() 58 | { 59 | return false; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/IO/OutputStream/StandardOutputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\OutputStream; 13 | 14 | /** 15 | * An output stream that writes to the standard output. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class StandardOutputStream extends StreamOutputStream 22 | { 23 | /** 24 | * Creates the stream. 25 | */ 26 | public function __construct() 27 | { 28 | // From \Symfony\Component\Console\Output\ConsoleOutput 29 | // 30 | // Returns true if current environment supports writing console output 31 | // to STDOUT. 32 | // 33 | // IBM iSeries (OS400) exhibits character-encoding issues when writing 34 | // to STDOUT and doesn't properly convert ASCII to EBCDIC, resulting in 35 | // garbage output. 36 | 37 | $stream = 'OS400' === php_uname('s') ? 'php://output' : 'php://stdout'; 38 | 39 | parent::__construct(fopen($stream, 'w')); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/IO/OutputStream/StreamOutputStream.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\IO\OutputStream; 13 | 14 | use Webmozart\Assert\Assert; 15 | use Webmozart\Console\Api\IO\IOException; 16 | use Webmozart\Console\Api\IO\OutputStream; 17 | 18 | /** 19 | * An output stream that writes to a PHP stream. 20 | * 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class StreamOutputStream implements OutputStream 26 | { 27 | /** 28 | * @var resource 29 | */ 30 | private $stream; 31 | 32 | /** 33 | * Creates the stream. 34 | * 35 | * @param resource $stream A stream resource. 36 | */ 37 | public function __construct($stream) 38 | { 39 | Assert::resource($stream, 'stream'); 40 | 41 | $this->stream = $stream; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function write($string) 48 | { 49 | if (null === $this->stream) { 50 | throw new IOException('Cannot read from a closed input.'); 51 | } 52 | 53 | if (false === fwrite($this->stream, $string)) { 54 | throw new IOException('Could not write stream.'); 55 | } 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function flush() 62 | { 63 | if (null === $this->stream) { 64 | throw new IOException('Cannot read from a closed input.'); 65 | } 66 | 67 | if (false === fflush($this->stream)) { 68 | throw new IOException('Could not flush stream.'); 69 | } 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | public function supportsAnsi() 76 | { 77 | if (DIRECTORY_SEPARATOR === '\\') { 78 | return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); 79 | } 80 | 81 | return function_exists('posix_isatty') && @posix_isatty($this->stream); 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function close() 88 | { 89 | if ($this->stream) { 90 | @fclose($this->stream); 91 | $this->stream = null; 92 | } 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | */ 98 | public function isClosed() 99 | { 100 | return null === $this->stream; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Process/ProcessLauncher.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Process; 13 | 14 | use RuntimeException; 15 | use Symfony\Component\Process\ProcessUtils; 16 | 17 | /** 18 | * Launches an interactive process in the foreground. 19 | * 20 | * This class is used to execute "man" and "less". 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class ProcessLauncher 27 | { 28 | /** 29 | * @var bool 30 | */ 31 | private $running = false; 32 | 33 | /** 34 | * @var float 35 | */ 36 | private $checkInterval = 0.1; 37 | 38 | /** 39 | * Returns whether the launcher is supported on the current system. 40 | * 41 | * @return bool Whether the launcher is supported on the current system. 42 | */ 43 | public function isSupported() 44 | { 45 | return function_exists('proc_open'); 46 | } 47 | 48 | /** 49 | * Returns whether the launcher is currently running. 50 | * 51 | * @return bool Whether the launcher is running. 52 | */ 53 | public function isRunning() 54 | { 55 | return $this->running; 56 | } 57 | 58 | /** 59 | * Returns the interval used to check whether the process is still alive. 60 | * 61 | * By default, the interval is 1 second. 62 | * 63 | * @param float $checkInterval The check interval. 64 | */ 65 | public function setCheckInterval($checkInterval) 66 | { 67 | $this->checkInterval = $checkInterval; 68 | } 69 | 70 | /** 71 | * Launches a process in the foreground. 72 | * 73 | * @param string $command The command to execute. 74 | * @param string[] $arguments Arguments to be quoted and inserted into the 75 | * command. Each key "key" in the array should 76 | * correspond to a placeholder "%key%" in the 77 | * command. 78 | * @param bool $killable Whether the process can be killed by the user. 79 | * 80 | * @return int The exit status of the process. 81 | */ 82 | public function launchProcess($command, array $arguments = array(), $killable = true) 83 | { 84 | $this->installSignalHandlers($killable); 85 | 86 | $exitCode = $this->run($command, $arguments); 87 | 88 | $this->restoreSignalHandlers($killable); 89 | 90 | return $exitCode; 91 | } 92 | 93 | private function installSignalHandlers($terminable = true) 94 | { 95 | if (function_exists('pcntl_signal') && !$terminable) { 96 | pcntl_signal(SIGTERM, SIG_IGN); 97 | pcntl_signal(SIGINT, SIG_IGN); 98 | } 99 | } 100 | 101 | private function restoreSignalHandlers($terminable = true) 102 | { 103 | if (function_exists('pcntl_signal') && !$terminable) { 104 | pcntl_signal(SIGTERM, SIG_DFL); 105 | pcntl_signal(SIGINT, SIG_DFL); 106 | } 107 | } 108 | 109 | private function run($command, array $arguments) 110 | { 111 | if (!function_exists('proc_open')) { 112 | throw new RuntimeException('The "proc_open" function is not available.'); 113 | } 114 | 115 | $replacements = array(); 116 | 117 | foreach ($arguments as $name => $value) { 118 | $replacements['%'.$name.'%'] = ProcessUtils::escapeArgument($value); 119 | } 120 | 121 | // Insert quoted arguments 122 | $command = strtr($command, $replacements); 123 | 124 | $dspec = array( 125 | 0 => STDIN, 126 | 1 => STDOUT, 127 | 2 => STDERR, 128 | ); 129 | 130 | $this->running = true; 131 | $proc = proc_open($command, $dspec, $pipes, null, null); 132 | 133 | if (is_resource($proc)) { 134 | while (true) { 135 | $status = proc_get_status($proc); 136 | 137 | if (!$status['running']) { 138 | break; 139 | } 140 | 141 | sleep($this->checkInterval); 142 | } 143 | 144 | proc_close($proc); 145 | } 146 | 147 | $this->running = false; 148 | 149 | return isset($status['exitcode']) ? $status['exitcode'] : 1; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/Resolver/ResolveResult.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Resolver; 13 | 14 | use Webmozart\Console\Api\Args\Args; 15 | use Webmozart\Console\Api\Args\CannotParseArgsException; 16 | use Webmozart\Console\Api\Args\RawArgs; 17 | use Webmozart\Console\Api\Command\Command; 18 | 19 | /** 20 | * An intermediate result created during resolving. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class ResolveResult 27 | { 28 | /** 29 | * @var Command 30 | */ 31 | private $command; 32 | 33 | /** 34 | * @var RawArgs 35 | */ 36 | private $rawArgs; 37 | 38 | /** 39 | * @var Args 40 | */ 41 | private $parsedArgs; 42 | 43 | /** 44 | * @var CannotParseArgsException 45 | */ 46 | private $parseError; 47 | 48 | /** 49 | * @var bool 50 | */ 51 | private $parsed = false; 52 | 53 | /** 54 | * Creates a new resolved command. 55 | * 56 | * @param Command $command The command. 57 | * @param RawArgs $rawArgs The raw console arguments. 58 | */ 59 | public function __construct(Command $command, RawArgs $rawArgs) 60 | { 61 | $this->command = $command; 62 | $this->rawArgs = $rawArgs; 63 | } 64 | 65 | /** 66 | * Returns the command. 67 | * 68 | * @return Command The command. 69 | */ 70 | public function getCommand() 71 | { 72 | return $this->command; 73 | } 74 | 75 | /** 76 | * The raw console arguments. 77 | * 78 | * @return RawArgs The raw console arguments. 79 | */ 80 | public function getRawArgs() 81 | { 82 | return $this->rawArgs; 83 | } 84 | 85 | /** 86 | * Returns the parsed console arguments. 87 | * 88 | * @return Args The parsed console arguments or `null` if the console 89 | * arguments cannot be parsed. 90 | * 91 | * @see isParsable(), getParseError() 92 | */ 93 | public function getParsedArgs() 94 | { 95 | if (!$this->parsed) { 96 | $this->parse(); 97 | } 98 | 99 | return $this->parsedArgs; 100 | } 101 | 102 | /** 103 | * Returns the error that happened during argument parsing. 104 | * 105 | * @return CannotParseArgsException The parse error or `null` if the 106 | * arguments were parsed successfully. 107 | * 108 | * @see isParsable(), getParsedArgs() 109 | */ 110 | public function getParseError() 111 | { 112 | if (!$this->parsed) { 113 | $this->parse(); 114 | } 115 | 116 | return $this->parseError; 117 | } 118 | 119 | /** 120 | * Returns whether the console arguments can be parsed. 121 | * 122 | * @return bool Returns `true` if the console arguments can be parsed and 123 | * `false` if a parse error occurred. 124 | * 125 | * @see getParsedArgs(), getParseError() 126 | */ 127 | public function isParsable() 128 | { 129 | if (!$this->parsed) { 130 | $this->parse(); 131 | } 132 | 133 | return null === $this->parseError; 134 | } 135 | 136 | private function parse() 137 | { 138 | try { 139 | $this->parsedArgs = $this->command->parseArgs($this->rawArgs); 140 | } catch (CannotParseArgsException $e) { 141 | $this->parseError = $e; 142 | } 143 | 144 | $this->parsed = true; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/UI/Alignment/LabelAlignment.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI\Alignment; 13 | 14 | use Webmozart\Console\Api\Formatter\Formatter; 15 | use Webmozart\Console\UI\Component\LabeledParagraph; 16 | 17 | /** 18 | * Aligns labeled paragraphs. 19 | * 20 | * The alignment takes {@link LabeledParagraph} instances and aligns the texts 21 | * next to the labels so that all texts start at the same offset. Pass the 22 | * paragraphs that you want to align to {@link add()}. When you call 23 | * {@link align()}, the text offset is calculated. You can retrieve the 24 | * calculated offset with {@link getTextOffset()}. 25 | * 26 | * @since 1.0 27 | * 28 | * @author Bernhard Schussek 29 | */ 30 | class LabelAlignment 31 | { 32 | /** 33 | * @var LabeledParagraph[] 34 | */ 35 | private $paragraphs = array(); 36 | 37 | /** 38 | * @var int[] 39 | */ 40 | private $indentations = array(); 41 | 42 | /** 43 | * @var int 44 | */ 45 | private $textOffset = 0; 46 | 47 | /** 48 | * Adds a labeled paragraph to the alignment. 49 | * 50 | * @param LabeledParagraph $paragraph The labeled paragraph. 51 | * @param int $indentation The indentation of the paragraph. 52 | */ 53 | public function add(LabeledParagraph $paragraph, $indentation = 0) 54 | { 55 | if ($paragraph->isAligned()) { 56 | $this->paragraphs[] = $paragraph; 57 | $this->indentations[] = $indentation; 58 | } 59 | } 60 | 61 | /** 62 | * Calculates the text offset based on all labels in the alignment. 63 | * 64 | * The passed indentation is added to the indentations of all labeled 65 | * paragraphs. 66 | * 67 | * @param Formatter $formatter The formatter used to remove style tags when 68 | * calculating the label width. 69 | * @param int $indentation The indentation. 70 | */ 71 | public function align(Formatter $formatter, $indentation = 0) 72 | { 73 | $this->textOffset = 0; 74 | 75 | foreach ($this->paragraphs as $i => $item) { 76 | $label = $formatter->removeFormat($item->getLabel()); 77 | $textOffset = $this->indentations[$i] + strlen($label) + $item->getPadding(); 78 | 79 | $this->textOffset = max($this->textOffset, $textOffset); 80 | } 81 | 82 | $this->textOffset += $indentation; 83 | } 84 | 85 | /** 86 | * Manually sets the text offset. 87 | * 88 | * @param int $textOffset The text offset. 89 | */ 90 | public function setTextOffset($textOffset) 91 | { 92 | $this->textOffset = $textOffset; 93 | } 94 | 95 | /** 96 | * Returns the calculated text offset. 97 | * 98 | * Before calling {@link align()} or {@link setTextOffset()}, this method 99 | * returns 0. 100 | * 101 | * @return int The text offset. 102 | */ 103 | public function getTextOffset() 104 | { 105 | return $this->textOffset; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/UI/Component.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI; 13 | 14 | use Webmozart\Console\Api\IO\IO; 15 | 16 | /** 17 | * A UI component that can be rendered on the I/O. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | interface Component 24 | { 25 | /** 26 | * Renders the component. 27 | * 28 | * @param IO $io The I/O. 29 | * @param int $indentation The number of spaces to indent. 30 | */ 31 | public function render(IO $io, $indentation = 0); 32 | } 33 | -------------------------------------------------------------------------------- /src/UI/Component/EmptyLine.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI\Component; 13 | 14 | use Webmozart\Console\Api\IO\IO; 15 | use Webmozart\Console\UI\Component; 16 | 17 | /** 18 | * An empty line. 19 | * 20 | * Contrary to a {@link Line} with no text, an empty line is never indented. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class EmptyLine implements Component 27 | { 28 | /** 29 | * Renders the empty line. 30 | * 31 | * @param IO $io The I/O. 32 | * @param int $indentation The number of spaces to indent. 33 | */ 34 | public function render(IO $io, $indentation = 0) 35 | { 36 | // Indentation is ignored for empty lines 37 | $io->write("\n"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/UI/Component/NameVersion.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI\Component; 13 | 14 | use Webmozart\Console\Api\Config\ApplicationConfig; 15 | use Webmozart\Console\Api\IO\IO; 16 | use Webmozart\Console\UI\Component; 17 | 18 | /** 19 | * Renders the name and version of an application. 20 | * 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class NameVersion implements Component 26 | { 27 | private $config; 28 | 29 | /** 30 | * Creates the renderer. 31 | * 32 | * @param ApplicationConfig $config The application configuration. 33 | */ 34 | public function __construct(ApplicationConfig $config) 35 | { 36 | $this->config = $config; 37 | } 38 | 39 | /** 40 | * Renders the name and version. 41 | * 42 | * @param IO $io The I/O. 43 | * @param int $indentation The number of spaces to indent. 44 | */ 45 | public function render(IO $io, $indentation = 0) 46 | { 47 | if ($this->config->getDisplayName() && $this->config->getVersion()) { 48 | $paragraph = new Paragraph("{$this->config->getDisplayName()} version {$this->config->getVersion()}"); 49 | } elseif ($this->config->getDisplayName()) { 50 | $paragraph = new Paragraph("{$this->config->getDisplayName()}"); 51 | } else { 52 | $paragraph = new Paragraph('Console Tool'); 53 | } 54 | 55 | $paragraph->render($io, $indentation); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/UI/Component/Paragraph.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI\Component; 13 | 14 | use Webmozart\Console\Api\IO\IO; 15 | use Webmozart\Console\UI\Component; 16 | 17 | /** 18 | * A paragraph of text. 19 | * 20 | * The paragraph is wrapped into the dimensions of the output. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class Paragraph implements Component 27 | { 28 | /** 29 | * @var string 30 | */ 31 | private $text; 32 | 33 | /** 34 | * Creates a new paragraph. 35 | * 36 | * @param string $text The text of the paragraph. 37 | */ 38 | public function __construct($text) 39 | { 40 | $this->text = $text; 41 | } 42 | 43 | /** 44 | * Renders the paragraph. 45 | * 46 | * @param IO $io The I/O. 47 | * @param int $indentation The number of spaces to indent. 48 | */ 49 | public function render(IO $io, $indentation = 0) 50 | { 51 | $linePrefix = str_repeat(' ', $indentation); 52 | $textWidth = $io->getTerminalDimensions()->getWidth() - 1 - $indentation; 53 | // TODO replace wordwrap() by implementation that is aware of format codes 54 | $text = preg_replace("~\n(?!\n)~", "\n".$linePrefix, wordwrap($this->text, $textWidth)); 55 | 56 | $io->write($linePrefix.rtrim($text)."\n"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/UI/Layout/BlockLayout.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI\Layout; 13 | 14 | use Webmozart\Console\Api\IO\IO; 15 | use Webmozart\Console\UI\Alignment\LabelAlignment; 16 | use Webmozart\Console\UI\Component; 17 | use Webmozart\Console\UI\Component\LabeledParagraph; 18 | 19 | /** 20 | * Renders renderable objects in indented blocks. 21 | * 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class BlockLayout implements Component 27 | { 28 | /** 29 | * @var int 30 | */ 31 | private $currentIndentation = 0; 32 | 33 | /** 34 | * @var Component[] 35 | */ 36 | private $elements = array(); 37 | 38 | /** 39 | * @var int[] 40 | */ 41 | private $indentations = array(); 42 | 43 | /** 44 | * @var LabelAlignment 45 | */ 46 | private $alignment; 47 | 48 | /** 49 | * Creates a new layout. 50 | */ 51 | public function __construct() 52 | { 53 | $this->alignment = new LabelAlignment(); 54 | } 55 | 56 | /** 57 | * Adds a renderable element to the layout. 58 | * 59 | * @param Component $element The element to add. 60 | * 61 | * @return static The current instance. 62 | */ 63 | public function add(Component $element) 64 | { 65 | $this->elements[] = $element; 66 | $this->indentations[] = $this->currentIndentation; 67 | 68 | if ($element instanceof LabeledParagraph) { 69 | $this->alignment->add($element, $this->currentIndentation); 70 | $element->setAlignment($this->alignment); 71 | } 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * Starts a new indented block. 78 | * 79 | * @return static The current instance. 80 | */ 81 | public function beginBlock() 82 | { 83 | $this->currentIndentation += 2; 84 | 85 | return $this; 86 | } 87 | 88 | /** 89 | * Ends the current indented block. 90 | * 91 | * @return static The current instance. 92 | */ 93 | public function endBlock() 94 | { 95 | $this->currentIndentation -= 2; 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Renders all elements in the layout. 102 | * 103 | * @param IO $io The I/O. 104 | * @param int $indentation The number of spaces to indent. 105 | */ 106 | public function render(IO $io, $indentation = 0) 107 | { 108 | $this->alignment->align($io, $indentation); 109 | 110 | foreach ($this->elements as $i => $element) { 111 | $element->render($io, $this->indentations[$i] + $indentation); 112 | } 113 | 114 | $this->elements = array(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/UI/Rectangle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI; 13 | 14 | /** 15 | * A rectangle. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class Rectangle 22 | { 23 | /** 24 | * @var int 25 | */ 26 | private $width; 27 | 28 | /** 29 | * @var int 30 | */ 31 | private $height; 32 | 33 | /** 34 | * Creates dimensions with the given width and height. 35 | * 36 | * @param int $width The width as number of printable characters. 37 | * @param int $height The height as number of printable lines. 38 | */ 39 | public function __construct($width, $height) 40 | { 41 | $this->width = (int) $width; 42 | $this->height = (int) $height; 43 | } 44 | 45 | /** 46 | * Returns the width. 47 | * 48 | * @return int The width as number of printable characters. 49 | */ 50 | public function getWidth() 51 | { 52 | return $this->width; 53 | } 54 | 55 | /** 56 | * Returns the height. 57 | * 58 | * @return int The height as number of printable lines. 59 | */ 60 | public function getHeight() 61 | { 62 | return $this->height; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/UI/Style/Alignment.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\UI\Style; 13 | 14 | /** 15 | * Constants for text alignment. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | final class Alignment 22 | { 23 | /** 24 | * Alignment: Align a cell to the left. 25 | */ 26 | const LEFT = 0; 27 | 28 | /** 29 | * Alignment: Align a cell to the right. 30 | */ 31 | const RIGHT = 1; 32 | 33 | /** 34 | * Alignment: Align a cell to the center. 35 | */ 36 | const CENTER = 2; 37 | 38 | /** 39 | * Returns all possible alignments. 40 | * 41 | * @return int[] A list of valid alignment constants. 42 | */ 43 | public static function all() 44 | { 45 | return array( 46 | self::LEFT, 47 | self::RIGHT, 48 | self::CENTER, 49 | ); 50 | } 51 | 52 | private function __construct() 53 | { 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Util/ProcessTitle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Util; 13 | 14 | /** 15 | * Sets and resets the PHP process title. 16 | * 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class ProcessTitle 22 | { 23 | /** 24 | * @var bool 25 | */ 26 | private static $supported; 27 | 28 | /** 29 | * @var string[] 30 | */ 31 | private static $processTitles = array(); 32 | 33 | /** 34 | * Returns whether process titles can be set. 35 | * 36 | * @return bool Returns `true` if process titles can be set and `false` 37 | * otherwise. 38 | */ 39 | public static function isSupported() 40 | { 41 | if (null === self::$supported) { 42 | self::$supported = function_exists('cli_set_process_title') || function_exists('setproctitle'); 43 | } 44 | 45 | return self::$supported; 46 | } 47 | 48 | /** 49 | * Sets the title of the PHP process. 50 | * 51 | * @param string $processTitle The process title. 52 | */ 53 | public static function setProcessTitle($processTitle) 54 | { 55 | self::$processTitles[] = $processTitle; 56 | 57 | self::changeProcessTitleTo($processTitle); 58 | } 59 | 60 | /** 61 | * Resets the title of the PHP process to the previous value. 62 | */ 63 | public static function resetProcessTitle() 64 | { 65 | $processTitle = self::$processTitles ? array_pop(self::$processTitles) : null; 66 | 67 | self::changeProcessTitleTo($processTitle); 68 | } 69 | 70 | private static function changeProcessTitleTo($processTitle) 71 | { 72 | if (function_exists('cli_set_process_title')) { 73 | cli_set_process_title($processTitle); 74 | } elseif (function_exists('setproctitle')) { 75 | setproctitle($processTitle); 76 | } 77 | } 78 | 79 | private function __construct() 80 | { 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Util/SimilarCommandName.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Util; 13 | 14 | use Webmozart\Console\Api\Command\CommandCollection; 15 | 16 | /** 17 | * Utility to find similar command names. 18 | * 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class SimilarCommandName 24 | { 25 | /** 26 | * Searches a command collection for similar names. 27 | * 28 | * @param string $commandName The command name that was not found. 29 | * @param CommandCollection $commands The available commands. 30 | * 31 | * @return string[] The names of similar commands. 32 | */ 33 | public static function find($commandName, CommandCollection $commands) 34 | { 35 | $threshold = 1e3; 36 | $distancesByName = array(); 37 | 38 | // Include aliases in the search 39 | $actualNames = $commands->getNames(true); 40 | 41 | foreach ($actualNames as $actualName) { 42 | // Get Levenshtein distance between the input and each command name 43 | $distance = levenshtein($commandName, $actualName); 44 | 45 | $isSimilar = $distance <= (strlen($commandName) / 3); 46 | $isSubString = false !== strpos($actualName, $commandName); 47 | 48 | if ($isSimilar || $isSubString) { 49 | $distancesByName[$actualName] = $distance; 50 | } 51 | } 52 | 53 | // Only keep results with a distance below the threshold 54 | $distancesByName = array_filter($distancesByName, function ($distance) use ($threshold) { 55 | return $distance < 2 * $threshold; 56 | }); 57 | 58 | // Display results with shortest distance first 59 | asort($distancesByName); 60 | 61 | $suggestedNames = array_keys($distancesByName); 62 | 63 | return self::filterDuplicates($suggestedNames, $commands); 64 | } 65 | 66 | private static function filterDuplicates(array $names, CommandCollection $commands) 67 | { 68 | $filteredNames = array(); 69 | 70 | foreach ($names as $nameToFilter) { 71 | // Check all existing names for duplicates 72 | foreach ($filteredNames as $filteredName) { 73 | // $nameToFilter is a duplicate - skip 74 | if ($commands->get($nameToFilter) === $commands->get($filteredName)) { 75 | continue 2; 76 | } 77 | } 78 | 79 | $filteredNames[] = $nameToFilter; 80 | } 81 | 82 | return $filteredNames; 83 | } 84 | 85 | private function __construct() 86 | { 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/Adapter/ApplicationAdapterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Adapter; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Symfony\Component\Console\Helper\HelperSet; 16 | use Webmozart\Console\Adapter\ApplicationAdapter; 17 | use Webmozart\Console\Adapter\ArgsFormatInputDefinition; 18 | use Webmozart\Console\Adapter\CommandAdapter; 19 | use Webmozart\Console\Api\Config\ApplicationConfig; 20 | use Webmozart\Console\ConsoleApplication; 21 | 22 | /** 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class ApplicationAdapterTest extends PHPUnit_Framework_TestCase 28 | { 29 | public function testCreate() 30 | { 31 | $config = ApplicationConfig::create() 32 | ->setName('test-bin') 33 | ->setDisplayName('Test Name') 34 | ->setVersion('1.2.3') 35 | ->setHelperSet($helperSet = new HelperSet()) 36 | ->beginCommand('command')->end() 37 | ; 38 | 39 | $application = new ConsoleApplication($config); 40 | $adapter = new ApplicationAdapter($application); 41 | 42 | $this->assertSame('Test Name', $adapter->getName()); 43 | $this->assertSame('1.2.3', $adapter->getVersion()); 44 | $this->assertSame('Test Name version 1.2.3', $adapter->getLongVersion()); 45 | $this->assertSame('Test Name version 1.2.3', $adapter->getHelp()); 46 | $this->assertSame($helperSet, $adapter->getHelperSet()); 47 | $this->assertSame(array(), $adapter->getNamespaces()); 48 | $this->assertEquals(new ArgsFormatInputDefinition($application->getGlobalArgsFormat()), $adapter->getDefinition()); 49 | 50 | $commandAdapter = new CommandAdapter($application->getCommand('command'), $adapter); 51 | $commandAdapter->setApplication($adapter); 52 | $commandAdapter->setHelperSet($helperSet); 53 | 54 | $this->assertEquals($commandAdapter, $adapter->get('command')); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Adapter/CommandAdapterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Adapter; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Symfony\Component\Console\Helper\HelperSet; 16 | use Webmozart\Console\Adapter\ApplicationAdapter; 17 | use Webmozart\Console\Adapter\ArgsFormatInputDefinition; 18 | use Webmozart\Console\Adapter\CommandAdapter; 19 | use Webmozart\Console\Api\Command\Command; 20 | use Webmozart\Console\Api\Config\ApplicationConfig; 21 | use Webmozart\Console\Api\Config\CommandConfig; 22 | use Webmozart\Console\ConsoleApplication; 23 | 24 | /** 25 | * @since 1.0 26 | * 27 | * @author Bernhard Schussek 28 | */ 29 | class CommandAdapterTest extends PHPUnit_Framework_TestCase 30 | { 31 | public function testCreate() 32 | { 33 | $config = CommandConfig::create() 34 | ->setName('command') 35 | ->addAlias('alias1') 36 | ->addAlias('alias2') 37 | ->setDescription('Description of the command') 38 | ->setHelp('The help for %command.name%') 39 | ->addArgument('argument') 40 | ->addOption('option', 'o') 41 | ->setHelperSet($helperSet = new HelperSet()) 42 | ; 43 | 44 | $applicationConfig = new ApplicationConfig(); 45 | $application = new ConsoleApplication($applicationConfig); 46 | $applicationAdapter = new ApplicationAdapter($application); 47 | 48 | $command = new Command($config, $application); 49 | $adapter = new CommandAdapter($command, $applicationAdapter); 50 | 51 | $this->assertSame('command', $adapter->getName()); 52 | $this->assertEquals(new ArgsFormatInputDefinition($command->getArgsFormat()), $adapter->getDefinition()); 53 | $this->assertEquals(new ArgsFormatInputDefinition($command->getArgsFormat()), $adapter->getNativeDefinition()); 54 | $this->assertSame($command, $adapter->getAdaptedCommand()); 55 | $this->assertSame(array('alias1', 'alias2'), $adapter->getAliases()); 56 | $this->assertSame($applicationAdapter, $adapter->getApplication()); 57 | $this->assertSame('Description of the command', $adapter->getDescription()); 58 | $this->assertSame('The help for %command.name%', $adapter->getHelp()); 59 | $this->assertSame('The help for command', $adapter->getProcessedHelp()); 60 | $this->assertSame($helperSet, $adapter->getHelperSet()); 61 | $this->assertSame('command [-o|--option] [--] []', $adapter->getSynopsis()); 62 | $this->assertTrue($adapter->isEnabled()); 63 | } 64 | 65 | public function testCreateDisabled() 66 | { 67 | $config = CommandConfig::create() 68 | ->setName('command') 69 | ->disable() 70 | ; 71 | 72 | $applicationConfig = new ApplicationConfig(); 73 | $application = new ConsoleApplication($applicationConfig); 74 | $applicationAdapter = new ApplicationAdapter($application); 75 | 76 | $command = new Command($config, $application); 77 | $adapter = new CommandAdapter($command, $applicationAdapter); 78 | 79 | $this->assertFalse($adapter->isEnabled()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/Adapter/FormatterAdapterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Adapter; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Adapter\FormatterAdapter; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class FormatterAdapterTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testFormatDecorated() 25 | { 26 | $formatter = $this->getMock('Webmozart\Console\Api\Formatter\Formatter'); 27 | 28 | $formatter->expects($this->once()) 29 | ->method('format') 30 | ->with('text') 31 | ->willReturn('formatted'); 32 | 33 | $adapter = new FormatterAdapter($formatter); 34 | $adapter->setDecorated(true); 35 | 36 | $this->assertSame('formatted', $adapter->format('text')); 37 | } 38 | 39 | public function testFormatNonDecorated() 40 | { 41 | $formatter = $this->getMock('Webmozart\Console\Api\Formatter\Formatter'); 42 | 43 | $formatter->expects($this->once()) 44 | ->method('removeFormat') 45 | ->with('text') 46 | ->willReturn('unformatted'); 47 | 48 | $adapter = new FormatterAdapter($formatter); 49 | $adapter->setDecorated(false); 50 | 51 | $this->assertSame('unformatted', $adapter->format('text')); 52 | } 53 | 54 | public function testIsDecorated() 55 | { 56 | $formatter = $this->getMock('Webmozart\Console\Api\Formatter\Formatter'); 57 | $adapter = new FormatterAdapter($formatter); 58 | 59 | $this->assertTrue($adapter->isDecorated()); 60 | 61 | $adapter->setDecorated(false); 62 | 63 | $this->assertFalse($adapter->isDecorated()); 64 | } 65 | 66 | public function testGetAdaptedFormatter() 67 | { 68 | $formatter = $this->getMock('Webmozart\Console\Api\Formatter\Formatter'); 69 | $adapter = new FormatterAdapter($formatter); 70 | 71 | $this->assertSame($formatter, $adapter->getAdaptedFormatter()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/Api/Args/Format/CommandNameTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Api\Args\Format; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Args\Format\CommandName; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class CommandNameTest extends PHPUnit_Framework_TestCase 23 | { 24 | /** 25 | * @dataProvider getValidNames 26 | */ 27 | public function testCreate($string) 28 | { 29 | $commandName = new CommandName($string); 30 | 31 | $this->assertSame($string, $commandName->toString()); 32 | } 33 | 34 | /** 35 | * @dataProvider getValidNames 36 | */ 37 | public function testCreateWithAliases($string) 38 | { 39 | $commandName = new CommandName('cmd', array('alias', $string)); 40 | 41 | $this->assertSame('cmd', $commandName->toString()); 42 | $this->assertSame(array('alias', $string), $commandName->getAliases()); 43 | } 44 | 45 | public function testToString() 46 | { 47 | $commandName = new CommandName('cmd'); 48 | 49 | $this->assertSame('cmd', (string) $commandName); 50 | } 51 | 52 | /** 53 | * @dataProvider getInvalidNames 54 | * @expectedException \InvalidArgumentException 55 | */ 56 | public function testCreateFailsIfInvalidString($string) 57 | { 58 | new CommandName($string); 59 | } 60 | 61 | /** 62 | * @dataProvider getInvalidNames 63 | * @expectedException \InvalidArgumentException 64 | */ 65 | public function testCreateFailsIfInvalidAlias($string) 66 | { 67 | new CommandName('cmd', array($string)); 68 | } 69 | 70 | public function getValidNames() 71 | { 72 | return array( 73 | array('command'), 74 | array('COMMAND'), 75 | array('command-name'), 76 | array('c'), 77 | array('command1'), 78 | ); 79 | } 80 | 81 | public function getInvalidNames() 82 | { 83 | return array( 84 | array('command_name'), 85 | array('command&'), 86 | array(''), 87 | array(null), 88 | array(1234), 89 | array(true), 90 | ); 91 | } 92 | 93 | public function testMatch() 94 | { 95 | $commandName = new CommandName('cmd', array('alias1', 'alias2')); 96 | 97 | $this->assertTrue($commandName->match('cmd')); 98 | $this->assertTrue($commandName->match('alias1')); 99 | $this->assertTrue($commandName->match('alias2')); 100 | $this->assertFalse($commandName->match('foo')); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tests/Api/Config/Fixtures/ConcreteConfig.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Api\Config\Fixtures; 13 | 14 | use Webmozart\Console\Api\Config\Config; 15 | 16 | /** 17 | * @since 1.0 18 | * 19 | * @author Bernhard Schussek 20 | */ 21 | class ConcreteConfig extends Config 22 | { 23 | public $configureCalled = false; 24 | 25 | protected function configure() 26 | { 27 | $this->configureCalled = true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Api/Config/SubCommandConfigTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Api\Config; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Symfony\Component\Console\Helper\HelperSet; 16 | use Webmozart\Console\Api\Config\ApplicationConfig; 17 | use Webmozart\Console\Api\Config\CommandConfig; 18 | use Webmozart\Console\Api\Config\SubCommandConfig; 19 | use Webmozart\Console\Args\DefaultArgsParser; 20 | use Webmozart\Console\Handler\NullHandler; 21 | 22 | /** 23 | * @since 1.0 24 | * 25 | * @author Bernhard Schussek 26 | */ 27 | class SubCommandConfigTest extends PHPUnit_Framework_TestCase 28 | { 29 | /** 30 | * @var SubCommandConfig 31 | */ 32 | private $config; 33 | 34 | /** 35 | * @var CommandConfig 36 | */ 37 | private $parentConfig; 38 | 39 | /** 40 | * @var ApplicationConfig 41 | */ 42 | private $applicationConfig; 43 | 44 | protected function setUp() 45 | { 46 | $this->applicationConfig = new ApplicationConfig(); 47 | $this->parentConfig = new CommandConfig('command', $this->applicationConfig); 48 | $this->config = new SubCommandConfig('sub-command', $this->parentConfig, $this->applicationConfig); 49 | } 50 | 51 | public function testCreate() 52 | { 53 | $config = new SubCommandConfig(); 54 | 55 | $this->assertNull($config->getParentConfig()); 56 | $this->assertNull($config->getApplicationConfig()); 57 | $this->assertNull($config->getName()); 58 | } 59 | 60 | public function testCreateWithArguments() 61 | { 62 | $applicationConfig = new ApplicationConfig(); 63 | $parentConfig = new CommandConfig('command', $applicationConfig); 64 | $config = new SubCommandConfig('sub-command', $parentConfig, $applicationConfig); 65 | 66 | $this->assertSame($parentConfig, $config->getParentConfig()); 67 | $this->assertSame($applicationConfig, $config->getApplicationConfig()); 68 | $this->assertSame('sub-command', $config->getName()); 69 | } 70 | 71 | public function testGetHelperSetReturnsParentHelperSetByDefault() 72 | { 73 | $helperSet = new HelperSet(); 74 | 75 | $this->parentConfig->setHelperSet($helperSet); 76 | 77 | $this->assertSame($helperSet, $this->config->getHelperSet()); 78 | } 79 | 80 | public function testGetHandlerReturnsParentHandlerByDefault() 81 | { 82 | $handler = new NullHandler(); 83 | 84 | $this->parentConfig->setHandler($handler); 85 | 86 | $this->assertSame($handler, $this->config->getHandler()); 87 | } 88 | 89 | public function testGetHandlerMethodReturnsParentHandlerByDefault() 90 | { 91 | $this->parentConfig->setHandlerMethod('method'); 92 | 93 | $this->assertSame('method', $this->config->getHandlerMethod()); 94 | } 95 | 96 | public function testGetArgsParserReturnsParentArgsParserByDefault() 97 | { 98 | $parser = new DefaultArgsParser(); 99 | 100 | $this->parentConfig->setArgsParser($parser); 101 | 102 | $this->assertSame($parser, $this->config->getArgsParser()); 103 | } 104 | 105 | public function testLenientArgsParsingDefaultsToParentValue() 106 | { 107 | $this->parentConfig->enableLenientArgsParsing(); 108 | 109 | $this->assertTrue($this->config->isLenientArgsParsingEnabled()); 110 | 111 | $this->parentConfig->disableLenientArgsParsing(); 112 | 113 | $this->assertFalse($this->config->isLenientArgsParsingEnabled()); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tests/Api/IO/InputTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Api\IO; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\IO\Input; 16 | use Webmozart\Console\IO\InputStream\StringInputStream; 17 | 18 | /** 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class InputTest extends PHPUnit_Framework_TestCase 24 | { 25 | const LOREM_IPSUM = "Lorem ipsum dolor sit amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt"; 26 | 27 | /** 28 | * @var StringInputStream 29 | */ 30 | private $stream; 31 | 32 | /** 33 | * @var Input 34 | */ 35 | private $input; 36 | 37 | protected function setUp() 38 | { 39 | $this->stream = new StringInputStream(); 40 | $this->input = new Input($this->stream); 41 | } 42 | 43 | public function testRead() 44 | { 45 | $this->stream->set('Lorem ipsum'); 46 | 47 | $this->assertSame('L', $this->input->read(1)); 48 | $this->assertSame('orem ipsum', $this->input->read(20)); 49 | } 50 | 51 | public function testReadReturnsDefaultIfNotInteractive() 52 | { 53 | $this->stream->set('Lorem ipsum'); 54 | 55 | $this->input->setInteractive(false); 56 | 57 | $this->assertSame('Default', $this->input->read(20, 'Default')); 58 | } 59 | 60 | public function testReadLine() 61 | { 62 | $this->stream->set(self::LOREM_IPSUM); 63 | 64 | $this->assertSame("Lorem ipsum dolor sit amet,\n", $this->input->readLine()); 65 | $this->assertSame('consetetu', $this->input->readLine(null, 10)); 66 | } 67 | 68 | public function testReadLineReturnsDefaultIfNotInteractive() 69 | { 70 | $this->stream->set(self::LOREM_IPSUM); 71 | 72 | $this->input->setInteractive(false); 73 | 74 | $this->assertSame('Default', $this->input->readLine('Default')); 75 | } 76 | 77 | public function testIsInteractive() 78 | { 79 | $this->assertTrue($this->input->isInteractive()); 80 | 81 | $this->input->setInteractive(false); 82 | 83 | $this->assertFalse($this->input->isInteractive()); 84 | 85 | $this->input->setInteractive(true); 86 | 87 | $this->assertTrue($this->input->isInteractive()); 88 | } 89 | 90 | public function testClose() 91 | { 92 | $stream = $this->getMock('Webmozart\Console\Api\IO\InputStream'); 93 | $this->input = new Input($stream); 94 | 95 | $stream->expects($this->once()) 96 | ->method('close'); 97 | 98 | $this->input->close(); 99 | } 100 | 101 | public function testIsClosed() 102 | { 103 | $stream = $this->getMock('Webmozart\Console\Api\IO\InputStream'); 104 | $this->input = new Input($stream); 105 | 106 | $stream->expects($this->once()) 107 | ->method('isClosed') 108 | ->willReturn('RESULT'); 109 | 110 | $this->assertSame('RESULT', $this->input->isClosed()); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /tests/Args/ArgvArgsTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Args; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Args\ArgvArgs; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class ArgvArgsTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testCreate() 25 | { 26 | $_SERVER['argv'] = array('console', 'server', 'add', '--port', '80', 'localhost'); 27 | 28 | $args = new ArgvArgs(); 29 | 30 | $this->assertSame('console', $args->getScriptName()); 31 | $this->assertSame(array('server', 'add', '--port', '80', 'localhost'), $args->getTokens()); 32 | } 33 | 34 | public function testCreateWithCustomTokens() 35 | { 36 | $_SERVER['argv'] = array('console', 'server', 'add', 'localhost'); 37 | 38 | $args = new ArgvArgs(array('other', 'server', 'add', '--port', '80', 'localhost')); 39 | 40 | $this->assertSame('other', $args->getScriptName()); 41 | $this->assertSame(array('server', 'add', '--port', '80', 'localhost'), $args->getTokens()); 42 | } 43 | 44 | public function testCreateNoArgs() 45 | { 46 | $args = new ArgvArgs(array()); 47 | 48 | $this->assertNull($args->getScriptName()); 49 | $this->assertSame(array(), $args->getTokens()); 50 | } 51 | 52 | public function testHasToken() 53 | { 54 | $args = new ArgvArgs(array('console', 'server', 'add', '--port', '80', 'localhost')); 55 | 56 | $this->assertTrue($args->hasToken('server')); 57 | $this->assertTrue($args->hasToken('--port')); 58 | $this->assertTrue($args->hasToken('80')); 59 | $this->assertFalse($args->hasToken('console')); 60 | $this->assertFalse($args->hasToken('foobar')); 61 | } 62 | 63 | public function testToString() 64 | { 65 | $args = new ArgvArgs(array('console', 'server', 'add', '--port', '80', 'localhost')); 66 | 67 | $this->assertSame('console server add --port 80 localhost', $args->toString()); 68 | $this->assertSame('console server add --port 80 localhost', $args->toString(true)); 69 | $this->assertSame('server add --port 80 localhost', $args->toString(false)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Args/StringArgsTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Args; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Args\StringArgs; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class StringArgsTest extends PHPUnit_Framework_TestCase 23 | { 24 | /** 25 | * @dataProvider getStringsToParse 26 | */ 27 | public function testCreate($string, array $tokens) 28 | { 29 | $args = new StringArgs($string); 30 | 31 | $this->assertSame($tokens, $args->getTokens()); 32 | } 33 | 34 | public function getStringsToParse() 35 | { 36 | return array( 37 | array('', array()), 38 | array('foo', array('foo')), 39 | array(' foo bar ', array('foo', 'bar')), 40 | array('"quoted"', array('quoted')), 41 | array("'quoted'", array('quoted')), 42 | array("'a\rb\nc\td'", array("a\rb\nc\td")), 43 | array("'a'\r'b'\n'c'\t'd'", array('a', 'b', 'c', 'd')), 44 | array('"quoted \'twice\'"', array('quoted \'twice\'')), 45 | array("'quoted \"twice\"'", array('quoted "twice"')), 46 | array('"quoted \'three \"times\"\'"', array('quoted \'three "times"\'')), 47 | array("'quoted \"three 'times'\"'", array('quoted "three \'times\'"')), 48 | array("\\'escaped\\'", array('\'escaped\'')), 49 | array('\"escaped\"', array('"escaped"')), 50 | array("\\'escaped more\\'", array('\'escaped', 'more\'')), 51 | array('\"escaped more\"', array('"escaped', 'more"')), 52 | array('-a', array('-a')), 53 | array('-azc', array('-azc')), 54 | array('-awithavalue', array('-awithavalue')), 55 | array('-a"foo bar"', array('-afoo bar')), 56 | array('-a"foo bar""foo bar"', array('-afoo barfoo bar')), 57 | array('-a\'foo bar\'', array('-afoo bar')), 58 | array('-a\'foo bar\'\'foo bar\'', array('-afoo barfoo bar')), 59 | array('-a\'foo bar\'"foo bar"', array('-afoo barfoo bar')), 60 | array('--long-option', array('--long-option')), 61 | array('--long-option=foo', array('--long-option=foo')), 62 | array('--long-option="foo bar"', array('--long-option=foo bar')), 63 | array('--long-option="foo bar""another"', array('--long-option=foo baranother')), 64 | array('--long-option=\'foo bar\'', array('--long-option=foo bar')), 65 | array("--long-option='foo bar''another'", array('--long-option=foo baranother')), 66 | array("--long-option='foo bar'\"another\"", array('--long-option=foo baranother')), 67 | array('foo -a -ffoo --long bar', array('foo', '-a', '-ffoo', '--long', 'bar')), 68 | array('\\\' \\"', array('\'', '"')), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Fixtures/terminate-after-run.php: -------------------------------------------------------------------------------- 1 | setTerminateAfterRun(true) 11 | 12 | ->editCommand('help') 13 | ->setHandler(new CallbackHandler(function () { 14 | return 123; 15 | })) 16 | ->end() 17 | ; 18 | 19 | $application = new ConsoleApplication($config); 20 | $application->run(); 21 | 22 | // Should not be executed 23 | exit(234); 24 | -------------------------------------------------------------------------------- /tests/Formatter/AnsiFormatterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Formatter; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Formatter\Style; 16 | use Webmozart\Console\Api\Formatter\StyleSet; 17 | use Webmozart\Console\Formatter\AnsiFormatter; 18 | 19 | /** 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class AnsiFormatterTest extends PHPUnit_Framework_TestCase 25 | { 26 | public function testFormat() 27 | { 28 | $formatter = new AnsiFormatter(new StyleSet(array( 29 | Style::tag('bold')->bold(), 30 | Style::tag('yellow')->fgYellow(), 31 | ))); 32 | 33 | $this->assertSame("\033[1mtext\033[22m", $formatter->format('text')); 34 | } 35 | 36 | public function testFormatWithStyle() 37 | { 38 | $formatter = new AnsiFormatter(new StyleSet(array( 39 | Style::tag('yellow')->fgYellow(), 40 | ))); 41 | 42 | $this->assertSame("\033[1mtext\033[22m", $formatter->format('text', Style::noTag()->bold())); 43 | } 44 | 45 | public function testRemoveFormat() 46 | { 47 | $formatter = new AnsiFormatter(new StyleSet(array( 48 | Style::tag('bold')->bold(), 49 | Style::tag('yellow')->fgYellow(), 50 | ))); 51 | 52 | $this->assertSame('text', $formatter->removeFormat('text')); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/Formatter/PlainFormatterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Formatter; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Formatter\Style; 16 | use Webmozart\Console\Api\Formatter\StyleSet; 17 | use Webmozart\Console\Formatter\PlainFormatter; 18 | 19 | /** 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class PlainFormatterTest extends PHPUnit_Framework_TestCase 25 | { 26 | public function testFormat() 27 | { 28 | $formatter = new PlainFormatter(new StyleSet(array( 29 | Style::tag('bold')->bold(), 30 | ))); 31 | 32 | $this->assertSame('text', $formatter->removeFormat('text')); 33 | } 34 | 35 | public function testRemoveFormat() 36 | { 37 | $formatter = new PlainFormatter(new StyleSet(array( 38 | Style::tag('bold')->bold(), 39 | ))); 40 | 41 | $this->assertSame('text', $formatter->removeFormat('text')); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/Handler/CallbackHandlerTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Handler; 13 | 14 | use PHPUnit_Framework_Assert; 15 | use PHPUnit_Framework_TestCase; 16 | use Webmozart\Console\Api\Args\Args; 17 | use Webmozart\Console\Api\Args\Format\ArgsFormat; 18 | use Webmozart\Console\Api\Command\Command; 19 | use Webmozart\Console\Api\Config\CommandConfig; 20 | use Webmozart\Console\Api\IO\IO; 21 | use Webmozart\Console\Handler\CallbackHandler; 22 | use Webmozart\Console\IO\BufferedIO; 23 | 24 | /** 25 | * @since 1.0 26 | * 27 | * @author Bernhard Schussek 28 | */ 29 | class CallbackHandlerTest extends PHPUnit_Framework_TestCase 30 | { 31 | public function testHandleCommand() 32 | { 33 | $args = new Args(new ArgsFormat()); 34 | $io = new BufferedIO("line1\nline2"); 35 | $command = new Command(new CommandConfig('command')); 36 | 37 | $handler = new CallbackHandler( 38 | function (Args $passedArgs, IO $io, Command $passedCommand) use ($args, $command) { 39 | PHPUnit_Framework_Assert::assertSame($args, $passedArgs); 40 | PHPUnit_Framework_Assert::assertSame($command, $passedCommand); 41 | 42 | $io->write($io->readLine()); 43 | $io->error($io->readLine()); 44 | 45 | return 123; 46 | } 47 | ); 48 | 49 | $this->assertSame(123, $handler->handle($args, $io, $command)); 50 | $this->assertSame("line1\n", $io->fetchOutput()); 51 | $this->assertSame('line2', $io->fetchErrors()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/ascii-doc/custom-app.txt: -------------------------------------------------------------------------------- 1 | Contents of custom-app.txt 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/ascii-doc/man-not-found.txt: -------------------------------------------------------------------------------- 1 | Contents of man-not-found.txt 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/ascii-doc/prefix-the-command.txt: -------------------------------------------------------------------------------- 1 | Contents of prefix-the-command.txt 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/ascii-doc/the-app.txt: -------------------------------------------------------------------------------- 1 | Contents of the-app.txt 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/ascii-doc/the-command.txt: -------------------------------------------------------------------------------- 1 | Contents of the-command.txt 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/man/custom-app.1: -------------------------------------------------------------------------------- 1 | Contents of custom-app.1 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/man/prefix-the-command.1: -------------------------------------------------------------------------------- 1 | Contents of prefix-the-command.1 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/man/the-app.1: -------------------------------------------------------------------------------- 1 | Contents of the-app.1 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/Fixtures/man/the-command.1: -------------------------------------------------------------------------------- 1 | Contents of the-command.1 2 | -------------------------------------------------------------------------------- /tests/Handler/Help/HelpJsonHandlerTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Handler\Help; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Application\Application; 16 | use Webmozart\Console\Api\Args\Args; 17 | use Webmozart\Console\Api\Command\Command; 18 | use Webmozart\Console\Config\DefaultApplicationConfig; 19 | use Webmozart\Console\ConsoleApplication; 20 | use Webmozart\Console\Handler\Help\HelpJsonHandler; 21 | use Webmozart\Console\IO\BufferedIO; 22 | 23 | /** 24 | * @since 1.0 25 | * 26 | * @author Bernhard Schussek 27 | */ 28 | class HelpJsonHandlerTest extends PHPUnit_Framework_TestCase 29 | { 30 | /** 31 | * @var Application 32 | */ 33 | private $application; 34 | 35 | /** 36 | * @var Command 37 | */ 38 | private $command; 39 | 40 | /** 41 | * @var Command 42 | */ 43 | private $helpCommand; 44 | 45 | /** 46 | * @var BufferedIO 47 | */ 48 | private $io; 49 | 50 | /** 51 | * @var HelpJsonHandler 52 | */ 53 | private $handler; 54 | 55 | protected function setUp() 56 | { 57 | $config = DefaultApplicationConfig::create() 58 | ->beginCommand('the-command')->end() 59 | ; 60 | 61 | $this->application = new ConsoleApplication($config); 62 | $this->command = $this->application->getCommand('the-command'); 63 | $this->helpCommand = $this->application->getCommand('help'); 64 | $this->io = new BufferedIO(); 65 | $this->handler = new HelpJsonHandler(); 66 | } 67 | 68 | public function testRenderCommandJson() 69 | { 70 | $args = new Args($this->helpCommand->getArgsFormat()); 71 | $args->setArgument('command', 'the-command'); 72 | 73 | $status = $this->handler->handle($args, $this->io, $this->command); 74 | 75 | $this->assertStringStartsWith('{"name":"the-command",', $this->io->fetchOutput()); 76 | $this->assertSame(0, $status); 77 | } 78 | 79 | public function testRenderApplicationJson() 80 | { 81 | $args = new Args($this->helpCommand->getArgsFormat()); 82 | 83 | $status = $this->handler->handle($args, $this->io, $this->command); 84 | 85 | $this->assertStringStartsWith('{"commands":[{"name":"help",', $this->io->fetchOutput()); 86 | $this->assertSame(0, $status); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/Handler/Help/HelpTextHandlerTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Handler\Help; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Application\Application; 16 | use Webmozart\Console\Api\Args\Args; 17 | use Webmozart\Console\Api\Command\Command; 18 | use Webmozart\Console\Config\DefaultApplicationConfig; 19 | use Webmozart\Console\ConsoleApplication; 20 | use Webmozart\Console\Handler\Help\HelpTextHandler; 21 | use Webmozart\Console\IO\BufferedIO; 22 | 23 | /** 24 | * @since 1.0 25 | * 26 | * @author Bernhard Schussek 27 | */ 28 | class HelpTextHandlerTest extends PHPUnit_Framework_TestCase 29 | { 30 | /** 31 | * @var Application 32 | */ 33 | private $application; 34 | 35 | /** 36 | * @var Command 37 | */ 38 | private $command; 39 | 40 | /** 41 | * @var Command 42 | */ 43 | private $helpCommand; 44 | 45 | /** 46 | * @var BufferedIO 47 | */ 48 | private $io; 49 | 50 | /** 51 | * @var HelpTextHandler 52 | */ 53 | private $handler; 54 | 55 | protected function setUp() 56 | { 57 | $config = DefaultApplicationConfig::create() 58 | ->setDisplayName('The Application') 59 | ->setVersion('1.2.3') 60 | ->beginCommand('the-command')->end() 61 | ; 62 | 63 | $this->application = new ConsoleApplication($config); 64 | $this->command = $this->application->getCommand('the-command'); 65 | $this->helpCommand = $this->application->getCommand('help'); 66 | $this->io = new BufferedIO(); 67 | $this->handler = new HelpTextHandler(); 68 | } 69 | 70 | public function testRenderCommandText() 71 | { 72 | $args = new Args($this->helpCommand->getArgsFormat()); 73 | $args->setArgument('command', 'the-command'); 74 | 75 | $status = $this->handler->handle($args, $this->io, $this->command); 76 | 77 | $expected = <<<'EOF' 78 | USAGE 79 | console the-command 80 | 81 | GLOBAL OPTIONS 82 | EOF; 83 | 84 | $this->assertStringStartsWith($expected, $this->io->fetchOutput()); 85 | $this->assertSame(0, $status); 86 | } 87 | 88 | public function testRenderApplicationText() 89 | { 90 | $args = new Args($this->helpCommand->getArgsFormat()); 91 | 92 | $status = $this->handler->handle($args, $this->io, $this->command); 93 | 94 | $expected = <<<'EOF' 95 | The Application version 1.2.3 96 | 97 | USAGE 98 | console 99 | EOF; 100 | 101 | $this->assertStringStartsWith($expected, $this->io->fetchOutput()); 102 | $this->assertSame(0, $status); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/Handler/Help/HelpXmlHandlerTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Handler\Help; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Application\Application; 16 | use Webmozart\Console\Api\Args\Args; 17 | use Webmozart\Console\Api\Command\Command; 18 | use Webmozart\Console\Config\DefaultApplicationConfig; 19 | use Webmozart\Console\ConsoleApplication; 20 | use Webmozart\Console\Handler\Help\HelpXmlHandler; 21 | use Webmozart\Console\IO\BufferedIO; 22 | 23 | /** 24 | * @since 1.0 25 | * 26 | * @author Bernhard Schussek 27 | */ 28 | class HelpXmlHandlerTest extends PHPUnit_Framework_TestCase 29 | { 30 | /** 31 | * @var Application 32 | */ 33 | private $application; 34 | 35 | /** 36 | * @var Command 37 | */ 38 | private $command; 39 | 40 | /** 41 | * @var Command 42 | */ 43 | private $helpCommand; 44 | 45 | /** 46 | * @var BufferedIO 47 | */ 48 | private $io; 49 | 50 | /** 51 | * @var HelpXmlHandler 52 | */ 53 | private $handler; 54 | 55 | protected function setUp() 56 | { 57 | $config = DefaultApplicationConfig::create() 58 | ->setDisplayName('The Application') 59 | ->setVersion('1.2.3') 60 | ->beginCommand('the-command')->end() 61 | ; 62 | 63 | $this->application = new ConsoleApplication($config); 64 | $this->command = $this->application->getCommand('the-command'); 65 | $this->helpCommand = $this->application->getCommand('help'); 66 | $this->io = new BufferedIO(); 67 | $this->handler = new HelpXmlHandler(); 68 | } 69 | 70 | public function testRenderCommandXml() 71 | { 72 | $args = new Args($this->helpCommand->getArgsFormat()); 73 | $args->setArgument('command', 'the-command'); 74 | 75 | $status = $this->handler->handle($args, $this->io, $this->command); 76 | 77 | $expected = <<<'EOF' 78 | 79 | 80 | EOF; 81 | 82 | $this->assertStringStartsWith($expected, $this->io->fetchOutput()); 83 | $this->assertSame(0, $status); 84 | } 85 | 86 | public function testRenderApplicationXml() 87 | { 88 | $args = new Args($this->helpCommand->getArgsFormat()); 89 | 90 | $status = $this->handler->handle($args, $this->io, $this->command); 91 | 92 | $expected = <<<'EOF' 93 | 94 | 95 | EOF; 96 | 97 | $this->assertStringStartsWith($expected, $this->io->fetchOutput()); 98 | $this->assertSame(0, $status); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/IO/BufferedIOTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\BufferedIO; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class BufferedIOTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testCreate() 25 | { 26 | $io = new BufferedIO('Lorem ipsum'); 27 | 28 | $this->assertSame('Lorem ipsum', $io->readLine()); 29 | } 30 | 31 | public function testSetInput() 32 | { 33 | $io = new BufferedIO(); 34 | $io->setInput('Lorem ipsum'); 35 | 36 | $this->assertSame('Lorem ipsum', $io->readLine()); 37 | } 38 | 39 | public function testAppendInput() 40 | { 41 | $io = new BufferedIO(); 42 | $io->setInput('Lorem ipsum'); 43 | 44 | $this->assertSame('Lorem', $io->read(5)); 45 | 46 | $io->appendInput(' dolor'); 47 | 48 | $this->assertSame(' ipsum dolor', $io->readLine()); 49 | } 50 | 51 | public function testClearInput() 52 | { 53 | $io = new BufferedIO(); 54 | $io->setInput('Lorem ipsum'); 55 | 56 | $this->assertSame('Lorem', $io->read(5)); 57 | 58 | $io->clearInput(); 59 | 60 | $this->assertNull($io->readLine()); 61 | } 62 | 63 | public function testFetchOutput() 64 | { 65 | $io = new BufferedIO(); 66 | $io->write('Lorem ipsum'); 67 | 68 | $this->assertSame('Lorem ipsum', $io->fetchOutput()); 69 | } 70 | 71 | public function testClearOutput() 72 | { 73 | $io = new BufferedIO(); 74 | $io->write('Lorem'); 75 | $io->clearOutput(); 76 | $io->write('ipsum'); 77 | 78 | $this->assertSame('ipsum', $io->fetchOutput()); 79 | } 80 | 81 | public function testFetchErrors() 82 | { 83 | $io = new BufferedIO(); 84 | $io->error('Lorem ipsum'); 85 | 86 | $this->assertSame('Lorem ipsum', $io->fetchErrors()); 87 | } 88 | 89 | public function testClearErrors() 90 | { 91 | $io = new BufferedIO(); 92 | $io->error('Lorem'); 93 | $io->clearErrors(); 94 | $io->error('ipsum'); 95 | 96 | $this->assertSame('ipsum', $io->fetchErrors()); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/IO/InputStream/StandardInputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\InputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\InputStream\StandardInputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class StandardInputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testCreate() 25 | { 26 | $input = new StandardInputStream(); 27 | 28 | $this->assertInstanceOf('Webmozart\Console\IO\InputStream\StandardInputStream', $input); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/IO/InputStream/StreamInputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\InputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\InputStream\StreamInputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class StreamInputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | const LOREM_IPSUM = "Lorem ipsum dolor sit amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt"; 25 | 26 | private $handle; 27 | 28 | protected function setUp() 29 | { 30 | $this->handle = fopen('php://memory', 'rw'); 31 | 32 | fwrite($this->handle, self::LOREM_IPSUM); 33 | rewind($this->handle); 34 | } 35 | 36 | protected function tearDown() 37 | { 38 | @fclose($this->handle); 39 | } 40 | 41 | public function testRead() 42 | { 43 | $stream = new StreamInputStream($this->handle); 44 | 45 | $this->assertSame('L', $stream->read(1)); 46 | $this->assertSame('o', $stream->read(1)); 47 | $this->assertSame('rem ipsum dolor sit ', $stream->read(20)); 48 | $this->assertSame("amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt", $stream->read(100)); 49 | $this->assertNull($stream->read(1)); 50 | } 51 | 52 | /** 53 | * @expectedException \Webmozart\Console\Api\IO\IOException 54 | */ 55 | public function testReadFailsAfterClose() 56 | { 57 | $stream = new StreamInputStream($this->handle); 58 | $stream->close(); 59 | 60 | $stream->read(1); 61 | } 62 | 63 | public function testReadLine() 64 | { 65 | $stream = new StreamInputStream($this->handle); 66 | 67 | $this->assertSame("Lorem ipsum dolor sit amet,\n", $stream->readLine()); 68 | $this->assertSame('consetetu', $stream->readLine(10)); 69 | $this->assertSame("r sadipscing elitr,\n", $stream->readLine(100)); 70 | $this->assertSame('sed diam nonumy eirmod tempor invidunt', $stream->readLine()); 71 | $this->assertNull($stream->readLine()); 72 | } 73 | 74 | /** 75 | * @expectedException \Webmozart\Console\Api\IO\IOException 76 | */ 77 | public function testReadLineFailsAfterClose() 78 | { 79 | $stream = new StreamInputStream($this->handle); 80 | $stream->close(); 81 | 82 | $stream->readLine(); 83 | } 84 | 85 | public function testIgnoreDuplicateClose() 86 | { 87 | $stream = new StreamInputStream($this->handle); 88 | $stream->close(); 89 | $stream->close(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tests/IO/InputStream/StringInputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\InputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\InputStream\StringInputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class StringInputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | const LOREM_IPSUM = "Lorem ipsum dolor sit amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt"; 25 | 26 | public function testRead() 27 | { 28 | $stream = new StringInputStream(self::LOREM_IPSUM); 29 | 30 | $this->assertSame('L', $stream->read(1)); 31 | $this->assertSame('o', $stream->read(1)); 32 | $this->assertSame('rem ipsum dolor sit ', $stream->read(20)); 33 | $this->assertSame("amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt", $stream->read(100)); 34 | $this->assertNull($stream->read(1)); 35 | } 36 | 37 | public function testReadEmpty() 38 | { 39 | $stream = new StringInputStream(); 40 | 41 | $this->assertNull($stream->read(1)); 42 | } 43 | 44 | public function testReadLine() 45 | { 46 | $stream = new StringInputStream(self::LOREM_IPSUM); 47 | 48 | $this->assertSame("Lorem ipsum dolor sit amet,\n", $stream->readLine()); 49 | $this->assertSame('consetetu', $stream->readLine(10)); 50 | $this->assertSame("r sadipscing elitr,\n", $stream->readLine(100)); 51 | $this->assertSame('sed diam nonumy eirmod tempor invidunt', $stream->readLine()); 52 | $this->assertNull($stream->readLine()); 53 | } 54 | 55 | public function testReadLineEmpty() 56 | { 57 | $stream = new StringInputStream(); 58 | 59 | $this->assertNull($stream->readLine()); 60 | } 61 | 62 | public function testClear() 63 | { 64 | $stream = new StringInputStream(self::LOREM_IPSUM); 65 | 66 | $this->assertSame("Lorem ipsum dolor sit amet,\n", $stream->readLine()); 67 | 68 | $stream->clear(); 69 | 70 | $this->assertNull($stream->readLine()); 71 | } 72 | 73 | public function testAppend() 74 | { 75 | $stream = new StringInputStream("Lorem\nIpsum\n"); 76 | 77 | $this->assertSame("Lorem\n", $stream->readLine()); 78 | 79 | $stream->append("Dolor\n"); 80 | 81 | $this->assertSame("Ipsum\n", $stream->readLine()); 82 | $this->assertSame("Dolor\n", $stream->readLine()); 83 | $this->assertNull($stream->readLine()); 84 | } 85 | 86 | public function testSet() 87 | { 88 | $stream = new StringInputStream(self::LOREM_IPSUM); 89 | 90 | $this->assertSame("Lorem ipsum dolor sit amet,\n", $stream->readLine()); 91 | 92 | $stream->set('Foobar'); 93 | 94 | $this->assertSame('Foobar', $stream->readLine()); 95 | $this->assertNull($stream->readLine()); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tests/IO/OutputStream/BufferedOutputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\OutputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\OutputStream\BufferedOutputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class BufferedOutputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testWrite() 25 | { 26 | $stream = new BufferedOutputStream(); 27 | $stream->write('Lorem ipsum'); 28 | 29 | $this->assertSame('Lorem ipsum', $stream->fetch()); 30 | } 31 | 32 | /** 33 | * @expectedException \Webmozart\Console\Api\IO\IOException 34 | */ 35 | public function testWriteFailsAfterClose() 36 | { 37 | $stream = new BufferedOutputStream(); 38 | $stream->close(); 39 | $stream->write('Lorem ipsum'); 40 | } 41 | 42 | public function testFetchAfterClose() 43 | { 44 | $stream = new BufferedOutputStream(); 45 | $stream->write('Lorem ipsum'); 46 | $stream->close(); 47 | 48 | $this->assertSame('Lorem ipsum', $stream->fetch()); 49 | } 50 | 51 | /** 52 | * @expectedException \Webmozart\Console\Api\IO\IOException 53 | */ 54 | public function testFlushFailsAfterClose() 55 | { 56 | $stream = new BufferedOutputStream(); 57 | $stream->close(); 58 | $stream->flush(); 59 | } 60 | 61 | public function testIgnoreDuplicateClose() 62 | { 63 | $stream = new BufferedOutputStream(); 64 | $stream->close(); 65 | $stream->close(); 66 | } 67 | 68 | public function testClear() 69 | { 70 | $stream = new BufferedOutputStream(); 71 | $stream->write('Lorem'); 72 | $stream->clear(); 73 | $stream->write('ipsum'); 74 | $stream->close(); 75 | 76 | $this->assertSame('ipsum', $stream->fetch()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/IO/OutputStream/ErrorOutputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\OutputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\OutputStream\ErrorOutputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class ErrorOutputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testCreate() 25 | { 26 | $stream = new ErrorOutputStream(); 27 | 28 | $this->assertInstanceOf('Webmozart\Console\IO\OutputStream\ErrorOutputStream', $stream); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/IO/OutputStream/StandardOutputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\OutputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\OutputStream\StandardOutputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class StandardOutputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | public function testCreate() 25 | { 26 | $stream = new StandardOutputStream(); 27 | 28 | $this->assertInstanceOf('Webmozart\Console\IO\OutputStream\StandardOutputStream', $stream); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/IO/OutputStream/StreamOutputStreamTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\IO\OutputStream; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\OutputStream\StreamOutputStream; 16 | 17 | /** 18 | * @since 1.0 19 | * 20 | * @author Bernhard Schussek 21 | */ 22 | class StreamOutputStreamTest extends PHPUnit_Framework_TestCase 23 | { 24 | private $handle; 25 | 26 | protected function setUp() 27 | { 28 | $this->handle = fopen('php://memory', 'rw'); 29 | } 30 | 31 | protected function tearDown() 32 | { 33 | @fclose($this->handle); 34 | } 35 | 36 | public function testWrite() 37 | { 38 | $stream = new StreamOutputStream($this->handle); 39 | $stream->write('Lorem ipsum'); 40 | 41 | rewind($this->handle); 42 | 43 | $this->assertSame('Lorem ipsum', fread($this->handle, 20)); 44 | } 45 | 46 | /** 47 | * @expectedException \Webmozart\Console\Api\IO\IOException 48 | */ 49 | public function testWriteFailsAfterClose() 50 | { 51 | $stream = new StreamOutputStream($this->handle); 52 | $stream->close(); 53 | $stream->write('Lorem ipsum'); 54 | } 55 | 56 | /** 57 | * @expectedException \Webmozart\Console\Api\IO\IOException 58 | */ 59 | public function testFlushFailsAfterClose() 60 | { 61 | $stream = new StreamOutputStream($this->handle); 62 | $stream->close(); 63 | $stream->flush(); 64 | } 65 | 66 | public function testIgnoreDuplicateClose() 67 | { 68 | $stream = new StreamOutputStream($this->handle); 69 | $stream->close(); 70 | $stream->close(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/Process/ProcessLauncherTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Process; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Symfony\Component\Process\PhpExecutableFinder; 16 | use Webmozart\Console\Process\ProcessLauncher; 17 | 18 | /** 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class ProcessLauncherTest extends PHPUnit_Framework_TestCase 24 | { 25 | /** 26 | * @var ProcessLauncher 27 | */ 28 | private $launcher; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private $php; 34 | 35 | protected function setUp() 36 | { 37 | $finder = new PhpExecutableFinder(); 38 | $this->php = escapeshellcmd($finder->find()); 39 | $this->launcher = new ProcessLauncher(); 40 | 41 | // Speed up the tests 42 | $this->launcher->setCheckInterval(0.01); 43 | } 44 | 45 | public function testLaunchSuccessfully() 46 | { 47 | if (!$this->php) { 48 | $this->markTestSkipped('The "bash" binary is not available.'); 49 | 50 | return; 51 | } 52 | 53 | if (!function_exists('proc_open')) { 54 | $this->markTestSkipped('The "proc_open" function is not available.'); 55 | 56 | return; 57 | } 58 | 59 | $status = $this->launcher->launchProcess($this->php.' -r %command%', array( 60 | 'command' => 'exit(0);', 61 | )); 62 | 63 | $this->assertSame(0, $status); 64 | } 65 | 66 | public function testLaunchWithError() 67 | { 68 | if (!$this->php) { 69 | $this->markTestSkipped('The "bash" binary is not available.'); 70 | 71 | return; 72 | } 73 | 74 | if (!function_exists('proc_open')) { 75 | $this->markTestSkipped('The "proc_open" function is not available.'); 76 | 77 | return; 78 | } 79 | 80 | $status = $this->launcher->launchProcess($this->php.' -r %command%', array( 81 | 'command' => 'exit(123);', 82 | )); 83 | 84 | $this->assertSame(123, $status); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/UI/Component/EmptyLineTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\UI\Component; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\BufferedIO; 16 | use Webmozart\Console\UI\Component\EmptyLine; 17 | 18 | /** 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class EmptyLineTest extends PHPUnit_Framework_TestCase 24 | { 25 | /** 26 | * @var BufferedIO 27 | */ 28 | private $io; 29 | 30 | protected function setUp() 31 | { 32 | $this->io = new BufferedIO(); 33 | } 34 | 35 | public function testRender() 36 | { 37 | $line = new EmptyLine(); 38 | $line->render($this->io); 39 | 40 | $this->assertSame("\n", $this->io->fetchOutput()); 41 | } 42 | 43 | public function testRenderIgnoresIndentation() 44 | { 45 | $line = new EmptyLine(); 46 | $line->render($this->io, 10); 47 | 48 | $this->assertSame("\n", $this->io->fetchOutput()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/UI/Component/LabeledParagraphTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\UI\Component; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\BufferedIO; 16 | use Webmozart\Console\UI\Alignment\LabelAlignment; 17 | use Webmozart\Console\UI\Component\LabeledParagraph; 18 | 19 | /** 20 | * @since 1.0 21 | * 22 | * @author Bernhard Schussek 23 | */ 24 | class LabeledParagraphTest extends PHPUnit_Framework_TestCase 25 | { 26 | const LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt'; 27 | 28 | /** 29 | * @var BufferedIO 30 | */ 31 | private $io; 32 | 33 | protected function setUp() 34 | { 35 | $this->io = new BufferedIO(); 36 | } 37 | 38 | public function testRender() 39 | { 40 | $para = new LabeledParagraph('Label', 'Text'); 41 | $para->render($this->io); 42 | 43 | $this->assertSame("Label Text\n", $this->io->fetchOutput()); 44 | } 45 | 46 | public function testRenderWithTrailingNewline() 47 | { 48 | $para = new LabeledParagraph('Label', "Text\n"); 49 | $para->render($this->io); 50 | 51 | $this->assertSame("Label Text\n", $this->io->fetchOutput()); 52 | } 53 | 54 | public function testRenderWithIndentation() 55 | { 56 | $para = new LabeledParagraph('Label', 'Text'); 57 | $para->render($this->io, 4); 58 | 59 | $this->assertSame(" Label Text\n", $this->io->fetchOutput()); 60 | } 61 | 62 | public function testRenderWithLabelDistance() 63 | { 64 | $para = new LabeledParagraph('Label', 'Text', 1); 65 | $para->render($this->io); 66 | 67 | $this->assertSame("Label Text\n", $this->io->fetchOutput()); 68 | } 69 | 70 | public function testRenderWithoutText() 71 | { 72 | $para = new LabeledParagraph('Label', ''); 73 | $para->render($this->io); 74 | 75 | $this->assertSame("Label\n", $this->io->fetchOutput()); 76 | } 77 | 78 | public function testRenderWithAlignment() 79 | { 80 | $alignment = new LabelAlignment(); 81 | $alignment->setTextOffset(10); 82 | 83 | $para = new LabeledParagraph('Label', 'Text'); 84 | $para->setAlignment($alignment); 85 | $para->render($this->io); 86 | 87 | $this->assertSame("Label Text\n", $this->io->fetchOutput()); 88 | } 89 | 90 | public function testRenderWithAlignmentIgnoresIfTextOffsetToSmall() 91 | { 92 | $alignment = new LabelAlignment(); 93 | $alignment->setTextOffset(5); 94 | 95 | $para = new LabeledParagraph('Label', 'Text'); 96 | $para->setAlignment($alignment); 97 | $para->render($this->io); 98 | 99 | $this->assertSame("Label Text\n", $this->io->fetchOutput()); 100 | } 101 | 102 | public function testRenderWrapsText() 103 | { 104 | $para = new LabeledParagraph('Label', self::LOREM_IPSUM); 105 | $para->render($this->io); 106 | 107 | $expected = <<<'EOF' 108 | Label Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 109 | eirmod tempor invidunt 110 | 111 | EOF; 112 | 113 | $this->assertSame($expected, $this->io->fetchOutput()); 114 | } 115 | 116 | public function testRenderWithIndentationWrapsText() 117 | { 118 | $para = new LabeledParagraph('Label', self::LOREM_IPSUM); 119 | $para->render($this->io, 4); 120 | 121 | $expected = <<<'EOF' 122 | Label Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 123 | nonumy eirmod tempor invidunt 124 | 125 | EOF; 126 | 127 | $this->assertSame($expected, $this->io->fetchOutput()); 128 | } 129 | 130 | public function testRenderWithLabelDistanceWrapsText() 131 | { 132 | $para = new LabeledParagraph('Label', self::LOREM_IPSUM, 6); 133 | $para->render($this->io); 134 | 135 | $expected = <<<'EOF' 136 | Label Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 137 | nonumy eirmod tempor invidunt 138 | 139 | EOF; 140 | 141 | $this->assertSame($expected, $this->io->fetchOutput()); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /tests/UI/Component/ParagraphTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\UI\Component; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\BufferedIO; 16 | use Webmozart\Console\UI\Component\Paragraph; 17 | 18 | /** 19 | * @since 1.0 20 | * 21 | * @author Bernhard Schussek 22 | */ 23 | class ParagraphTest extends PHPUnit_Framework_TestCase 24 | { 25 | const LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt'; 26 | 27 | /** 28 | * @var BufferedIO 29 | */ 30 | private $io; 31 | 32 | protected function setUp() 33 | { 34 | $this->io = new BufferedIO(); 35 | } 36 | 37 | public function testRender() 38 | { 39 | $para = new Paragraph(self::LOREM_IPSUM); 40 | $para->render($this->io); 41 | 42 | $expected = <<<'EOF' 43 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod 44 | tempor invidunt 45 | 46 | EOF; 47 | 48 | $this->assertSame($expected, $this->io->fetchOutput()); 49 | } 50 | 51 | public function testRenderWithIndentation() 52 | { 53 | $para = new Paragraph(self::LOREM_IPSUM); 54 | $para->render($this->io, 6); 55 | 56 | $expected = <<<'EOF' 57 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 58 | eirmod tempor invidunt 59 | 60 | EOF; 61 | 62 | $this->assertSame($expected, $this->io->fetchOutput()); 63 | } 64 | 65 | public function testSkipIndentationForEmptyLines() 66 | { 67 | $para = new Paragraph(self::LOREM_IPSUM."\n\n".self::LOREM_IPSUM); 68 | $para->render($this->io, 6); 69 | 70 | $expected = <<<'EOF' 71 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 72 | eirmod tempor invidunt 73 | 74 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 75 | eirmod tempor invidunt 76 | 77 | EOF; 78 | 79 | $this->assertSame($expected, $this->io->fetchOutput()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/UI/Layout/BlockLayoutTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\UI\Layout; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\IO\BufferedIO; 16 | use Webmozart\Console\UI\Component\EmptyLine; 17 | use Webmozart\Console\UI\Component\LabeledParagraph; 18 | use Webmozart\Console\UI\Component\Paragraph; 19 | use Webmozart\Console\UI\Layout\BlockLayout; 20 | 21 | /** 22 | * @since 1.0 23 | * 24 | * @author Bernhard Schussek 25 | */ 26 | class BlockLayoutTest extends PHPUnit_Framework_TestCase 27 | { 28 | const LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt'; 29 | 30 | /** 31 | * @var BufferedIO 32 | */ 33 | private $io; 34 | 35 | protected function setUp() 36 | { 37 | $this->io = new BufferedIO(); 38 | } 39 | 40 | public function testRender() 41 | { 42 | $layout = new BlockLayout(); 43 | 44 | $layout 45 | ->add(new Paragraph('HEADING 1')) 46 | ->add(new Paragraph(self::LOREM_IPSUM)) 47 | ->add(new EmptyLine()) 48 | ->add(new LabeledParagraph('Not Aligned', self::LOREM_IPSUM, 1, false)) 49 | ->add(new EmptyLine()) 50 | ->add(new Paragraph('HEADING 2')) 51 | ->beginBlock() 52 | ->add(new LabeledParagraph('Label 1', self::LOREM_IPSUM)) 53 | ->add(new LabeledParagraph('Label 2', self::LOREM_IPSUM)) 54 | ->endBlock() 55 | ->add(new Paragraph('HEADING 3')) 56 | ->beginBlock() 57 | ->add(new LabeledParagraph('Longer Label', self::LOREM_IPSUM)) 58 | ->endBlock() 59 | ; 60 | 61 | $layout->render($this->io); 62 | 63 | $expected = <<<'EOF' 64 | HEADING 1 65 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod 66 | tempor invidunt 67 | 68 | Not Aligned Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 69 | nonumy eirmod tempor invidunt 70 | 71 | HEADING 2 72 | Label 1 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed 73 | diam nonumy eirmod tempor invidunt 74 | Label 2 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed 75 | diam nonumy eirmod tempor invidunt 76 | HEADING 3 77 | Longer Label Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed 78 | diam nonumy eirmod tempor invidunt 79 | 80 | EOF; 81 | 82 | $this->assertSame($expected, $this->io->fetchOutput()); 83 | } 84 | 85 | public function testRenderWithIndentation() 86 | { 87 | $layout = new BlockLayout(); 88 | 89 | $layout 90 | ->add(new Paragraph('HEADING 1')) 91 | ->add(new Paragraph(self::LOREM_IPSUM)) 92 | ->add(new EmptyLine()) 93 | ->add(new LabeledParagraph('Not Aligned', self::LOREM_IPSUM, 1, false)) 94 | ->add(new EmptyLine()) 95 | ->add(new Paragraph('HEADING 2')) 96 | ->beginBlock() 97 | ->add(new LabeledParagraph('Label 1', self::LOREM_IPSUM)) 98 | ->add(new LabeledParagraph('Label 2', self::LOREM_IPSUM)) 99 | ->endBlock() 100 | ->add(new Paragraph('HEADING 3')) 101 | ->beginBlock() 102 | ->add(new LabeledParagraph('Longer Label', self::LOREM_IPSUM)) 103 | ->endBlock() 104 | ; 105 | 106 | $layout->render($this->io, 4); 107 | 108 | $expected = <<<'EOF' 109 | HEADING 1 110 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 111 | eirmod tempor invidunt 112 | 113 | Not Aligned Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed 114 | diam nonumy eirmod tempor invidunt 115 | 116 | HEADING 2 117 | Label 1 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, 118 | sed diam nonumy eirmod tempor invidunt 119 | Label 2 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, 120 | sed diam nonumy eirmod tempor invidunt 121 | HEADING 3 122 | Longer Label Lorem ipsum dolor sit amet, consetetur sadipscing elitr, 123 | sed diam nonumy eirmod tempor invidunt 124 | 125 | EOF; 126 | 127 | $this->assertSame($expected, $this->io->fetchOutput()); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /tests/Util/SimilarCommandNameTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Webmozart\Console\Tests\Util; 13 | 14 | use PHPUnit_Framework_TestCase; 15 | use Webmozart\Console\Api\Command\Command; 16 | use Webmozart\Console\Api\Command\CommandCollection; 17 | use Webmozart\Console\Api\Config\CommandConfig; 18 | use Webmozart\Console\Util\SimilarCommandName; 19 | 20 | /** 21 | * @since 1.0 22 | * 23 | * @author Bernhard Schussek 24 | */ 25 | class SimilarCommandNameTest extends PHPUnit_Framework_TestCase 26 | { 27 | /** 28 | * @dataProvider getInputOutput 29 | */ 30 | public function testFindSimilarNames($input, array $suggestions) 31 | { 32 | $commands = new CommandCollection(array( 33 | new Command( 34 | CommandConfig::create('package')->addAlias('package-alias') 35 | ), 36 | new Command( 37 | CommandConfig::create('pack')->addAlias('pack-alias') 38 | ), 39 | new Command(CommandConfig::create('pack')), 40 | )); 41 | 42 | $this->assertSame($suggestions, SimilarCommandName::find($input, $commands)); 43 | } 44 | 45 | public function getInputOutput() 46 | { 47 | return array( 48 | array('pac', array('pack', 'package')), 49 | array('pack', array('pack', 'package')), 50 | array('pack-', array('pack')), 51 | array('pack-a', array('pack')), 52 | array('pack-al', array('pack-alias')), 53 | array('pack-ali', array('pack-alias')), 54 | array('pack-alia', array('pack-alias')), 55 | array('pack-alias', array('pack-alias', 'package-alias')), 56 | array('packa', array('pack', 'package')), 57 | array('packag', array('package', 'pack')), 58 | array('package', array('package')), 59 | array('package-', array('package')), 60 | array('package-a', array('package')), 61 | array('package-al', defined('HHVM_VERSION') || PHP_VERSION_ID >= 70000 ? array('package') : array('package-alias')), 62 | array('package-ali', array('package-alias')), 63 | array('package-alia', array('package-alias', 'pack-alias')), 64 | array('package-alias', array('package-alias', 'pack-alias')), 65 | ); 66 | } 67 | } 68 | --------------------------------------------------------------------------------