diff --git a/commands/core/archive.drush.inc b/commands/core/archive.drush.inc index d4c58eb958..acd7cb1976 100644 --- a/commands/core/archive.drush.inc +++ b/commands/core/archive.drush.inc @@ -88,7 +88,7 @@ function drush_archive_dump($sites_subdirs = '@self') { } else { $sites[$key]['databases'] = array(); - drush_log(dt('DB definition not found for !alias', array('!alias' => $key)), LogLevel::NOTICE); + drush_log(dt('DB definition not found for !alias', array('!alias' => $key)), LogLevel::INFO); } } diff --git a/commands/core/config.drush.inc b/commands/core/config.drush.inc index 1af08826da..99151a5770 100644 --- a/commands/core/config.drush.inc +++ b/commands/core/config.drush.inc @@ -832,7 +832,7 @@ function drush_config_get_object($config_name) { return drush_set_error(dt('Config !name does not exist in !source configuration.', array('!name' => $config_name, '!source' => $source))); } if (empty($data)) { - drush_log(dt('Config !name exists but has no data.', array('!name' => $config_name)), LogLevel::NOTICE); + drush_log(dt('Config !name exists but has no data.', array('!name' => $config_name)), LogLevel::INFO); return; } return $data; diff --git a/commands/core/core.drush.inc b/commands/core/core.drush.inc index ca00a5ef32..d4f36b6245 100644 --- a/commands/core/core.drush.inc +++ b/commands/core/core.drush.inc @@ -1351,7 +1351,7 @@ function drush_core_twig_compile() { $relative = str_replace(drush_get_context('DRUSH_DRUPAL_ROOT'). '/', '', $file->filename); // @todo Dynamically disable twig debugging since there is no good info there anyway. twig_render_template($relative, array('theme_hook_original' => '')); - drush_log(dt('Compiled twig template !path', array('!path' => $relative)), LogLevel::NOTICE); + drush_log(dt('Compiled twig template !path', array('!path' => $relative)), LogLevel::INFO); } } } diff --git a/commands/core/init.drush.inc b/commands/core/init.drush.inc deleted file mode 100644 index 6170c96a70..0000000000 --- a/commands/core/init.drush.inc +++ /dev/null @@ -1,173 +0,0 @@ - 'Enrich the bash startup file with completion and aliases. Copy .drushrc file to ~/.drush', - 'aliases' => array('init'), - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'package' => 'core', - 'global-options' => array('editor', 'bg'), - 'options' => array( - 'edit' => 'Open the new config file in an editor.', - 'add-path' => "Always add Drush to the \$PATH in the user's .bashrc file, even if it is already in the \$PATH. Use --no-add-path to skip updating .bashrc with the Drush \$PATH. Default is to update .bashrc only if Drush is not already in the \$PATH.", - ), - 'examples' => array( - 'drush core-init --edit' => 'Enrich Bash and open drush config file in editor.', - 'drush core-init --edit --bg' => 'Return to shell prompt as soon as the editor window opens.', - ), - ); - return $items; -} - -/** - * Initialize local Drush configuration - */ -function drush_init_core_init() { - $home = drush_server_home(); - $drush_config_dir = $home . "/.drush"; - $drush_config_file = $drush_config_dir . "/drushrc.php"; - $drush_bashrc = $drush_config_dir . "/drush.bashrc"; - $drush_prompt = $drush_config_dir . "/drush.prompt.sh"; - $drush_complete = $drush_config_dir . "/drush.complete.sh"; - $examples_dir = DRUSH_BASE_PATH . "/examples"; - $example_configuration = $examples_dir . "/example.drushrc.php"; - $example_bashrc = $examples_dir . "/example.bashrc"; - $example_prompt = $examples_dir . "/example.prompt.sh"; - $example_complete = DRUSH_BASE_PATH . "/drush.complete.sh"; - $bashrc_additions = array(); - - // If Drush is not in the $PATH, then figure out which - // path to add so that Drush can be found globally. - $add_path = drush_get_option('add-path', NULL); - if ((!drush_which("drush") || $add_path) && ($add_path !== FALSE)) { - $drush_path = drush_find_path_to_drush($home); - $drush_path = preg_replace("%^" . preg_quote($home) . "/%", '$HOME/', $drush_path); - - $bashrc_additions["%$drush_path%"] = "# Path to Drush, added by 'drush init'.\nexport PATH=\"\$PATH:$drush_path\"\n\n"; - } - - // Create a ~/.drush directory if it does not yet exist - if (!is_dir($drush_config_dir)) { - drush_mkdir($drush_config_dir); - } - - // If there is no ~/.drush/drushrc.php, then copy the - // example Drush configuration file here - if (!is_file($drush_config_file)) { - copy($example_configuration, $drush_config_file); - drush_log(dt("Copied example Drush configuration file to !path", array('!path' => $drush_config_file)), LogLevel::OK); - } - - // If there is no ~/.drush/drush.bashrc file, then copy - // the example bashrc file there - if (!is_file($drush_bashrc)) { - copy($example_bashrc, $drush_bashrc); - $pattern = basename($drush_bashrc); - $bashrc_additions["%$pattern%"] = "# Include Drush bash customizations.\n". drush_bash_addition($drush_bashrc); - drush_log(dt("Copied example Drush bash configuration file to !path", array('!path' => $drush_bashrc)), LogLevel::OK); - } - - // If there is no ~/.drush/drush.complete.sh file, then copy it there - if (!is_file($drush_complete)) { - copy($example_complete, $drush_complete); - $pattern = basename($drush_complete); - $bashrc_additions["%$pattern%"] = "# Include Drush completion.\n". drush_bash_addition($drush_complete); - drush_log(dt("Copied Drush completion file to !path", array('!path' => $drush_complete)), LogLevel::OK); - } - - // If there is no ~/.drush/drush.prompt.sh file, then copy - // the example prompt.sh file here - if (!is_file($drush_prompt)) { - copy($example_prompt, $drush_prompt); - $pattern = basename($drush_prompt); - $bashrc_additions["%$pattern%"] = "# Include Drush prompt customizations.\n". drush_bash_addition($drush_prompt); - drush_log(dt("Copied example Drush prompt file to !path", array('!path' => $drush_prompt)), LogLevel::OK); - } - - // Decide whether we want to add our Bash commands to - // ~/.bashrc or ~/.bash_profile - $bashrc = drush_init_find_bashrc($home); - - // Modify the user's bashrc file, adding our customizations. - $bashrc_contents = ""; - if (file_exists($bashrc)) { - $bashrc_contents = file_get_contents($bashrc); - } - $new_bashrc_contents = $bashrc_contents; - foreach ($bashrc_additions as $pattern => $addition) { - // Only put in the addition if the pattern does not already - // exist in the bashrc file. - if (!preg_match($pattern, $new_bashrc_contents)) { - $new_bashrc_contents = $new_bashrc_contents . $addition; - } - } - if ($new_bashrc_contents != $bashrc_contents) { - if (drush_confirm(dt(implode('', $bashrc_additions) . "Append the above code to !file?", array('!file' => $bashrc)))) { - file_put_contents($bashrc, "\n\n". $new_bashrc_contents); - drush_log(dt("Updated bash configuration file !path", array('!path' => $bashrc)), LogLevel::OK); - drush_log(dt("Start a new shell in order to experience the improvements (e.g. `bash`)."), LogLevel::OK); - if (drush_get_option('edit')) { - $exec = drush_get_editor(); - drush_shell_exec_interactive($exec, $drush_config_file, $drush_config_file); - } - } - else { - return drush_user_abort(); - } - } - else { - drush_log(dt('No code added to !path', array('!path' => $bashrc)), LogLevel::OK); - } -} - -/** - * Determine which .bashrc file is best to use on this platform. - */ -function drush_init_find_bashrc($home) { - return $home . "/.bashrc"; -} - -/** - * Determine where Drush is located, so that we can add - * that location to the $PATH - */ -function drush_find_path_to_drush($home) { - // First test: is Drush inside a vendor directory? - // Does vendor/bin exist? If so, use that. We do - // not have a good way to locate the 'bin' directory - // if it has been relocated in the composer.json config - // section. - if ($vendor_pos = strpos(DRUSH_BASE_PATH, "/vendor/")) { - $vendor_dir = substr(DRUSH_BASE_PATH, 0, $vendor_pos + 7); - $vendor_bin = $vendor_dir . '/bin'; - if (is_dir($vendor_bin)) { - return $vendor_bin; - } - } - - // Fallback is to use the directory that Drush is in. - return DRUSH_BASE_PATH; -} - -function drush_bash_addition($file) { - return << $cmd['command'])); diff --git a/commands/core/views.d8.drush.inc b/commands/core/views.d8.drush.inc index 6b95c3d41c..d4f53dd022 100644 --- a/commands/core/views.d8.drush.inc +++ b/commands/core/views.d8.drush.inc @@ -386,7 +386,7 @@ function _views_drush_op($op = '', array $view_names = array()) { drush_log(dt('View: @view has been @action', $tokens), LogLevel::SUCCESS); } else { - drush_log(dt('View: @view is already @action', $tokens), LogLevel::NOTICE); + drush_log(dt('View: @view is already @action', $tokens), LogLevel::INFO); } // Remove this view from the viewnames input list. unset($view_names[$view->id()]); diff --git a/commands/make/make.project.inc b/commands/make/make.project.inc index 1e96ee754f..86c1a28e20 100644 --- a/commands/make/make.project.inc +++ b/commands/make/make.project.inc @@ -534,7 +534,7 @@ class DrushMakeProject { function recurse($path) { if (!$this->do_recursion || drush_get_option('no-recursion')) { drush_log(dt("Preventing recursive makefile parsing for !project", - array("!project" => $this->name)), LogLevel::NOTICE); + array("!project" => $this->name)), LogLevel::INFO); return TRUE; } $candidates = array( diff --git a/composer.json b/composer.json index e27d5008f2..c867bcf9e0 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,11 @@ "symfony/yaml": "~2.3|~3.0", "symfony/var-dumper": "~2.7|~3.0", "league/container": "~2", + "codegyre/robo": "~1.0.0-beta1", + "consolidation/annotated-command": "~1.0.0-beta1", + "consolidation/output-formatters": "~1.0.0-beta1", + "symfony/console": "2.7.*", + "symfony/event-dispatcher": "2.7.*", "symfony/config": "~2.2", "pear/console_table": "~1.3.0" }, diff --git a/composer.lock b/composer.lock index 56ba74d848..5a85978953 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,222 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "a6c7c753ba3d4dd5532a3f4070101584", - "content-hash": "74ffc4f89fe92ded8a6c4fc75f277229", + "hash": "5bd57ac012915f836165419817f9cf4f", + "content-hash": "cf07eeece6d4d8decc73cc6b01f8ad80", "packages": [ + { + "name": "codegyre/robo", + "version": "1.0.0-beta1", + "source": { + "type": "git", + "url": "https://github.com/Codegyre/Robo.git", + "reference": "0a6988640610c51526e9f41c7607345ddcae2012" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codegyre/Robo/zipball/0a6988640610c51526e9f41c7607345ddcae2012", + "reference": "0a6988640610c51526e9f41c7607345ddcae2012", + "shasum": "" + }, + "require": { + "consolidation/annotated-command": "~1.0.0-beta1", + "consolidation/log": "~1", + "consolidation/output-formatters": "~1.0.0-beta1", + "league/container": "~2.2", + "php": ">=5.5.0", + "symfony/console": "~2.5|~3.0", + "symfony/filesystem": "~2.5|~3.0", + "symfony/finder": "~2.5|~3.0", + "symfony/process": "~2.5|~3.0" + }, + "require-dev": { + "codeception/aspect-mock": "0.5.4", + "codeception/base": "~2.1.5", + "codeception/verify": "0.2.*", + "henrikbjorn/lurker": "~1.0", + "natxet/cssmin": "~3.0", + "patchwork/jsqueeze": "~1.0", + "pear/archive_tar": "~1.0", + "squizlabs/php_codesniffer": "2.*" + }, + "suggest": { + "henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch", + "natxet/CssMin": "For minifying JS files in taskMinify", + "patchwork/jsqueeze": "For minifying JS files in taskMinify", + "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." + }, + "bin": [ + "robo" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Robo\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "Modern task runner", + "time": "2016-04-25 10:24:13" + }, + { + "name": "consolidation/annotated-command", + "version": "1.0.0-beta11", + "source": { + "type": "git", + "url": "https://github.com/consolidation-org/annotated-command.git", + "reference": "d10d37f3ec0634d9ac6fc83ce4727cf59b936da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation-org/annotated-command/zipball/d10d37f3ec0634d9ac6fc83ce4727cf59b936da2", + "reference": "d10d37f3ec0634d9ac6fc83ce4727cf59b936da2", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "phpdocumentor/reflection-docblock": "~2", + "psr/log": "~1.0", + "symfony/console": "~2.5|~3.0", + "symfony/finder": "~2.5|~3.0" + }, + "require-dev": { + "consolidation/output-formatters": "~1.0.0-beta3", + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "^1.0", + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\AnnotatedCommand\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Initialize Symfony Console commands from annotated command class methods.", + "time": "2016-05-06 02:32:06" + }, + { + "name": "consolidation/log", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/consolidation-org/log.git", + "reference": "74ba81b4edc585616747cc5c5309ce56fec41254" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation-org/log/zipball/74ba81b4edc585616747cc5c5309ce56fec41254", + "reference": "74ba81b4edc585616747cc5c5309ce56fec41254", + "shasum": "" + }, + "require": { + "php": ">=5.5.0", + "psr/log": "~1.0", + "symfony/console": "~2.5|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", + "time": "2016-03-23 23:46:42" + }, + { + "name": "consolidation/output-formatters", + "version": "1.0.0-beta5", + "source": { + "type": "git", + "url": "https://github.com/consolidation-org/output-formatters.git", + "reference": "777f0a58b2ecdcff7c1bd2f2c444c8256068a0a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation-org/output-formatters/zipball/777f0a58b2ecdcff7c1bd2f2c444c8256068a0a7", + "reference": "777f0a58b2ecdcff7c1bd2f2c444c8256068a0a7", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/console": "~2.5|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "^1.0", + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\OutputFormatters\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Format text by applying transformations provided by plug-in formatters.", + "time": "2016-04-29 22:31:04" + }, { "name": "container-interop/container-interop", "version": "1.1.0", @@ -156,16 +369,16 @@ }, { "name": "league/container", - "version": "2.0.3", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/thephpleague/container.git", - "reference": "d4b5e0dde44aec50e4025c7249d668ea74b1ae44" + "reference": "c0e7d947b690891f700dc4967ead7bdb3d6708c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/d4b5e0dde44aec50e4025c7249d668ea74b1ae44", - "reference": "d4b5e0dde44aec50e4025c7249d668ea74b1ae44", + "url": "https://api.github.com/repos/thephpleague/container/zipball/c0e7d947b690891f700dc4967ead7bdb3d6708c1", + "reference": "c0e7d947b690891f700dc4967ead7bdb3d6708c1", "shasum": "" }, "require": { @@ -184,8 +397,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev", - "dev-1.x": "1.5-dev" + "dev-master": "2.x-dev", + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -216,20 +429,20 @@ "provider", "service" ], - "time": "2015-09-07 10:16:18" + "time": "2016-03-17 11:07:59" }, { "name": "nikic/php-parser", - "version": "v2.0.1", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ce5be709d59b32dd8a88c80259028759991a4206" + "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ce5be709d59b32dd8a88c80259028759991a4206", - "reference": "ce5be709d59b32dd8a88c80259028759991a4206", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/47b254ea51f1d6d5dc04b9b299e88346bf2369e3", + "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3", "shasum": "" }, "require": { @@ -245,7 +458,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -267,7 +480,7 @@ "parser", "php" ], - "time": "2016-02-28 19:48:28" + "time": "2016-04-19 13:41:41" }, { "name": "pear/console_table", @@ -324,6 +537,55 @@ ], "time": "2016-01-21 16:14:31" }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, { "name": "psr/log", "version": "1.0.0", @@ -436,16 +698,16 @@ }, { "name": "symfony/config", - "version": "v2.8.3", + "version": "v2.8.5", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19" + "reference": "edbbcf33cffa2a85104fc80de8dc052cc51596bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19", - "reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19", + "url": "https://api.github.com/repos/symfony/config/zipball/edbbcf33cffa2a85104fc80de8dc052cc51596bb", + "reference": "edbbcf33cffa2a85104fc80de8dc052cc51596bb", "shasum": "" }, "require": { @@ -485,30 +747,29 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-02-22 16:12:45" + "time": "2016-04-20 18:52:26" }, { "name": "symfony/console", - "version": "v3.0.3", + "version": "v2.7.12", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2ed5e2706ce92313d120b8fe50d1063bcfd12e04" + "reference": "dfb9d26a4dd62fc9389c42196cf4a087400948b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2ed5e2706ce92313d120b8fe50d1063bcfd12e04", - "reference": "2ed5e2706ce92313d120b8fe50d1063bcfd12e04", + "url": "https://api.github.com/repos/symfony/console/zipball/dfb9d26a4dd62fc9389c42196cf4a087400948b8", + "reference": "dfb9d26a4dd62fc9389c42196cf4a087400948b8", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=5.3.9" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" }, "suggest": { "psr/log": "For using the console logger", @@ -518,7 +779,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.7-dev" } }, "autoload": { @@ -545,20 +806,80 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:24:34" + "time": "2016-04-20 06:32:07" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.7.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "e86b8282381f4fa7732f3847e152c01a32d721d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e86b8282381f4fa7732f3847e152c01a32d721d7", + "reference": "e86b8282381f4fa7732f3847e152c01a32d721d7", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2016-04-04 17:08:16" }, { "name": "symfony/filesystem", - "version": "v3.0.3", + "version": "v3.0.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "23ae8f9648d0a7fe94a47c8e20e5bf37c489a451" + "reference": "74fec3511b62cb934b64bce1d96f06fffa4beafd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/23ae8f9648d0a7fe94a47c8e20e5bf37c489a451", - "reference": "23ae8f9648d0a7fe94a47c8e20e5bf37c489a451", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/74fec3511b62cb934b64bce1d96f06fffa4beafd", + "reference": "74fec3511b62cb934b64bce1d96f06fffa4beafd", "shasum": "" }, "require": { @@ -594,7 +915,56 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-02-23 15:16:06" + "time": "2016-04-12 18:09:53" + }, + { + "name": "symfony/finder", + "version": "v3.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "c54e407b35bc098916704e9fd090da21da4c4f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52", + "reference": "c54e407b35bc098916704e9fd090da21da4c4f52", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2016-03-10 11:13:05" }, { "name": "symfony/polyfill-mbstring", @@ -655,18 +1025,67 @@ ], "time": "2016-01-20 09:13:37" }, + { + "name": "symfony/process", + "version": "v2.7.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "a49e4c67a6a52e9c5bce1f28d9ea8618f36a43d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/a49e4c67a6a52e9c5bce1f28d9ea8618f36a43d0", + "reference": "a49e4c67a6a52e9c5bce1f28d9ea8618f36a43d0", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2016-04-12 11:52:58" + }, { "name": "symfony/var-dumper", - "version": "v3.0.3", + "version": "v3.0.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "9a6a883c48acb215d4825ce9de61dccf93d62074" + "reference": "0e918c269093ba4c77fca14e9424fa74ed16f1a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a6a883c48acb215d4825ce9de61dccf93d62074", - "reference": "9a6a883c48acb215d4825ce9de61dccf93d62074", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e918c269093ba4c77fca14e9424fa74ed16f1a6", + "reference": "0e918c269093ba4c77fca14e9424fa74ed16f1a6", "shasum": "" }, "require": { @@ -716,20 +1135,20 @@ "debug", "dump" ], - "time": "2016-02-13 09:23:44" + "time": "2016-04-25 11:17:47" }, { "name": "symfony/yaml", - "version": "v3.0.3", + "version": "v3.0.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c" + "reference": "0047c8366744a16de7516622c5b7355336afae96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/b5ba64cd67ecd6887f63868fa781ca094bd1377c", - "reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96", + "reference": "0047c8366744a16de7516622c5b7355336afae96", "shasum": "" }, "require": { @@ -765,7 +1184,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-02-23 15:16:06" + "time": "2016-03-04 07:55:57" } ], "packages-dev": [ @@ -823,55 +1242,6 @@ ], "time": "2015-06-14 21:17:01" }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "dflydev/markdown": "~1.0", - "erusev/parsedown": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2015-02-03 12:10:50" - }, { "name": "phpspec/prophecy", "version": "v1.6.0", @@ -1176,16 +1546,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.23", + "version": "4.8.24", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483" + "reference": "a1066c562c52900a142a0e2bbf0582994671385e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483", - "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e", + "reference": "a1066c562c52900a142a0e2bbf0582994671385e", "shasum": "" }, "require": { @@ -1244,7 +1614,7 @@ "testing", "xunit" ], - "time": "2016-02-11 14:56:33" + "time": "2016-03-14 06:16:08" }, { "name": "phpunit/phpunit-mock-objects", @@ -1420,16 +1790,16 @@ }, { "name": "sebastian/environment", - "version": "1.3.5", + "version": "1.3.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf" + "reference": "2292b116f43c272ff4328083096114f84ea46a56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", - "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/2292b116f43c272ff4328083096114f84ea46a56", + "reference": "2292b116f43c272ff4328083096114f84ea46a56", "shasum": "" }, "require": { @@ -1466,7 +1836,7 @@ "environment", "hhvm" ], - "time": "2016-02-26 18:40:46" + "time": "2016-05-04 07:59:13" }, { "name": "sebastian/exporter", @@ -1672,64 +2042,19 @@ "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", "time": "2015-06-21 13:59:46" - }, - { - "name": "symfony/process", - "version": "v2.7.10", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "faa89438017392585abdf7f5a47f3f5f282d93c1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/faa89438017392585abdf7f5a47f3f5f282d93c1", - "reference": "faa89438017392585abdf7f5a47f3f5f282d93c1", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "time": "2016-02-02 13:32:58" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "codegyre/robo": 10, + "consolidation/annotated-command": 10, + "consolidation/output-formatters": 10 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=5.4.5" + "php": ">=5.5.0" }, "platform-dev": [] } diff --git a/includes/annotationcommand_adapter.inc b/includes/annotationcommand_adapter.inc new file mode 100644 index 0000000000..2ce07b18e2 --- /dev/null +++ b/includes/annotationcommand_adapter.inc @@ -0,0 +1,36 @@ +/** + * Adapt Annotation Commands to work with Drush 8. + * + * Hooks are ignored; only the main command hook is called. + * + * Drush formatters are used instead of the consolidation/output-formatters + * project. + * + * Symfony commands are not used; annotation commands are instead converted + * to Drush 8 command records. + * + * Only annotation commands associated with Drupal modules are discovered + * and loaded. Global commands and internal commands must be implemented + * with the Drush 8 command mechanism. + */ + +/** + * Create the annotation adapter + */ +function annotationcommand_adapter_setup() { + +} + +/** + * + */ +function annotationcommand_adapter_register() { + +} + +/** + * Run an adapted annotation command for $hook, if it exists. + */ +function annotationcommand_adapter_run($hook) { + return null; +} diff --git a/includes/backend.inc b/includes/backend.inc index ad9a60661b..466765c98a 100644 --- a/includes/backend.inc +++ b/includes/backend.inc @@ -546,7 +546,7 @@ function drush_backend_parse_packets(&$string, &$remainder, $backend_options) { $function($entry, $backend_options); } else { - drush_log(dt("Unknown backend packet @packet", array('@packet' => $entry['packet'])), LogLevel::NOTICE); + drush_log(dt("Unknown backend packet @packet", array('@packet' => $entry['packet'])), LogLevel::INFO); } } else { diff --git a/includes/command.inc b/includes/command.inc index 7c6f9cdb56..1a1aa6f741 100644 --- a/includes/command.inc +++ b/includes/command.inc @@ -186,7 +186,7 @@ function drush_dispatch($command, $arguments = array()) { } // Add a final log entry, just so a timestamp appears. - drush_log(dt('Command dispatch complete'), LogLevel::NOTICE); + drush_log(dt('Command dispatch complete'), LogLevel::INFO); return $return; } diff --git a/includes/complete.inc b/includes/complete.inc index f746e6eef6..cb070d2b50 100644 --- a/includes/complete.inc +++ b/includes/complete.inc @@ -104,10 +104,11 @@ function drush_early_complete() { // We use a distinct --complete-debug option to avoid unwanted debug messages // being printed when users use this option for other purposes in the command // they are trying to complete. - drush_set_option(LogLevel::DEBUG, FALSE); + drush_set_option('debug', FALSE); if (drush_get_option('complete-debug', FALSE)) { - drush_set_context('DRUSH_DEBUG', TRUE); + drush_set_option('debug', TRUE); } + _drush_preflight_global_options(); // Set up as if we were running the command, and attempt to parse. $argv = drush_complete_process_argv(); if ($alias = drush_get_context('DRUSH_TARGET_SITE_ALIAS')) { diff --git a/includes/drush.inc b/includes/drush.inc index 466d2fc4ca..c3609fa3c4 100644 --- a/includes/drush.inc +++ b/includes/drush.inc @@ -271,7 +271,7 @@ function drush_flatten_array($a) { function drush_get_global_options($brief = FALSE) { $options['root'] = array('short-form' => 'r', 'short-has-arg' => TRUE, 'never-post' => TRUE, 'description' => "Drupal root directory to use (default: current directory).", 'example-value' => 'path'); $options['uri'] = array('short-form' => 'l', 'short-has-arg' => TRUE, 'never-post' => TRUE, 'description' => 'URI of the drupal site to use (only needed in multisite environments or when running on an alternate port).', 'example-value' => 'http://example.com:8888'); - $options['verbose'] = array('short-form' => 'v', 'context' => 'DRUSH_VERBOSE', 'description' => 'Display extra information about the command.'); + $options['verbose'] = array('short-form' => 'v', 'context' => 'DRUSH_VERBOSE', 'description' => 'Display extra information about the command.', 'symfony-conflict' => TRUE); $options['debug'] = array('short-form' => 'd', 'context' => 'DRUSH_DEBUG', 'description' => 'Display even more information, including internal messages.'); $options['yes'] = array('short-form' => 'y', 'context' => 'DRUSH_AFFIRMATIVE', 'description' => "Assume 'yes' as answer to all prompts."); $options['no'] = array('short-form' => 'n', 'context' => 'DRUSH_NEGATIVE', 'description' => "Assume 'no' as answer to all prompts."); @@ -280,7 +280,7 @@ function drush_get_global_options($brief = FALSE) { $options['help'] = array('short-form' => 'h', 'description' => "This help system."); if (!$brief) { - $options['version'] = array('description' => "Show drush version."); + $options['version'] = array('description' => "Show drush version.", 'symfony-conflict' => TRUE); $options['php'] = array('description' => "The absolute path to your PHP intepreter, if not 'php' in the path.", 'example-value' => '/path/to/file', 'never-propagate' => TRUE); $options['interactive'] = array('short-form' => 'ia', 'description' => "Force interactive mode for commands run on multiple targets (e.g. `drush @site1,@site2 cc --ia`).", 'never-propagate' => TRUE); $options['tty'] = array('hidden' => TRUE, 'description' => "Force allocation of tty for remote commands", 'never-propagate' => TRUE); @@ -295,7 +295,7 @@ function drush_get_global_options($brief = FALSE) { $options['search-depth'] = array('description' => "Control the depth that drush will search for alias files.", 'example-value' => 'number'); $options['ignored-modules'] = array('description' => "Exclude some modules from consideration when searching for drush command files.", 'example-value' => 'token,views'); $options['no-label'] = array('description' => "Remove the site label that drush includes in multi-site command output (e.g. `drush @site1,@site2 status`)."); - $options['label-separator'] = array('description' => "Specify the separator to use in multi-site command output (e.g. `drush @sites pm-list --label-separator=',' --format=csv`)."); + $options['label-separator'] = array('description' => "Specify the separator to use in multi-site command output (e.g. `drush @sites pm-list --label-separator=',' --format=csv`).", 'example-value' => ','); $options['nocolor'] = array('context' => 'DRUSH_NOCOLOR', 'propagate-cli-value' => TRUE, 'description' => "Suppress color highlighting on log messages."); $options['show-passwords'] = array('description' => "Show database passwords in commands that display connection information."); $options['show-invoke'] = array('description' => "Show all function names which could have been called for the current command. See drush_invoke()."); @@ -310,11 +310,11 @@ function drush_get_global_options($brief = FALSE) { $options['php-options'] = array('description' => "Options to pass to `php` when running drush. Only effective when using the drush.launcher script.", 'never-propagate' => TRUE, 'example-value' => '-d error_reporting="E_ALL"'); $options['halt-on-error'] = array('propagate-cli-value' => TRUE, 'description' => "Controls error handling of recoverable errors (E_RECOVERABLE_ERROR). --halt-on-error=1: Execution is halted. --halt-on-error=0: Drush execution continues"); $options['deferred-sanitization'] = array('hidden' => TRUE, 'description' => "Defer calculating the sanitization operations until after the database has been copied. This is done automatically if the source database is remote."); - $options['remote-host'] = array('hidden' => TRUE, 'description' => 'Remote site to execute drush command on. Managed by site alias.'); - $options['remote-user'] = array('hidden' => TRUE, 'description' => 'User account to use with a remote drush command. Managed by site alias.'); - $options['remote-os'] = array('hidden' => TRUE, 'description' => 'The operating system used on the remote host. Managed by site alias.'); - $options['site-list'] = array('hidden' => TRUE, 'description' => 'List of sites to run commands on. Managed by site alias.'); - $options['reserve-margin'] = array('hidden' => TRUE, 'description' => 'Remove columns from formatted opions. Managed by multi-site command handling.'); + $options['remote-host'] = array('hidden' => TRUE, 'description' => 'Remote site to execute drush command on. Managed by site alias.', 'example-value' => 'http://example.com'); + $options['remote-user'] = array('hidden' => TRUE, 'description' => 'User account to use with a remote drush command. Managed by site alias.', 'example-value' => 'www-data'); + $options['remote-os'] = array('hidden' => TRUE, 'description' => 'The operating system used on the remote host. Managed by site alias.', 'example-value' => 'linux'); + $options['site-list'] = array('hidden' => TRUE, 'description' => 'List of sites to run commands on. Managed by site alias.', 'example-value' => '@site1,@site2'); + $options['reserve-margin'] = array('hidden' => TRUE, 'description' => 'Remove columns from formatted opions. Managed by multi-site command handling.', 'example-value' => 'number'); $options['strict'] = array('propagate' => TRUE, 'description' => 'Return an error on unrecognized options. --strict=0: Allow unrecognized options. --strict=2: Also return an error on any "warning" log messages. Optional. Default is 1.'); $options['command-specific'] = array('hidden' => TRUE, 'merge-associative' => TRUE, 'description' => 'Command-specific options.'); $options['site-aliases'] = array('hidden' => TRUE, 'merge-associative' => TRUE, 'description' => 'List of site aliases.'); @@ -875,7 +875,7 @@ function _drush_download_file($url, $destination, $overwrite = TRUE) { function drush_mime_content_type($filename) { $content_type = drush_attempt_mime_content_type($filename); if ($content_type) { - drush_log(dt('Mime type for !file is !mt', array('!file' => $filename, '!mt' => $content_type)), LogLevel::NOTICE); + drush_log(dt('Mime type for !file is !mt', array('!file' => $filename, '!mt' => $content_type)), LogLevel::INFO); return $content_type; } return drush_set_error('MIME_CONTENT_TYPE_UNKNOWN', dt('Unable to determine mime type for !file.', array('!file' => $filename))); @@ -1245,11 +1245,11 @@ function drush_do_command_redispatch($command, $args = array(), $remote_host = N * The type of message to be logged. Common types are 'warning', 'error', 'success' and 'notice'. * A type of 'ok' or 'success' can also be supplied to flag something that worked. * If you want your log messages to print to screen without the user entering - * a -v or --verbose flag, use type 'ok', this prints log messages out to + * a -v or --verbose flag, use type 'ok' or 'notice', this prints log messages out to * STDERR, which prints to screen (unless you have redirected it). All other - * types of messages will be assumed to be notices. + * types of messages will be assumed to be info. */ -function drush_log($message, $type = LogLevel::NOTICE, $error = null) { +function drush_log($message, $type = LogLevel::INFO, $error = null) { $entry = array( 'type' => $type, 'message' => $message, @@ -1270,7 +1270,6 @@ function _drush_log($entry) { if (!$callback) { $callback = \Drush::logger(); } - if ($callback instanceof LoggerInterface) { $context = $entry; $log_level = $entry['type']; @@ -1416,7 +1415,10 @@ function _drush_log_drupal_messages() { drush_log(preg_replace('/^warning: /i', '', $error), LogLevel::WARNING); } elseif (preg_match('/^notice:/i', $error)) { - drush_log(preg_replace('/^notice: /i', '', $error), LogLevel::NOTICE); + // Drush LogLevel::NOTICE is printed all the time; we map + // watchdog notices to LogLevel::INFO, which are only + // printed in verbose mode. + drush_log(preg_replace('/^notice: /i', '', $error), LogLevel::INFO); } elseif (preg_match('/^user warning:/i', $error)) { // This is a special case. PHP logs sql errors as 'User Warnings', not errors. diff --git a/includes/environment.inc b/includes/environment.inc index 1b20547adb..bc5e65e6fc 100644 --- a/includes/environment.inc +++ b/includes/environment.inc @@ -27,7 +27,7 @@ function drush_error_handler($errno, $message, $filename, $line, $context) { // drush_errors_on() and drush_errors_off(). if ($errno & error_reporting()) { // By default we log notices. - $type = drush_get_option('php-notices', 'notice'); + $type = drush_get_option('php-notices', LogLevel::INFO); $halt_on_error = drush_get_option('halt-on-error', (drush_drupal_major_version() != 6)); // Bitmask value that constitutes an error needing to be logged. diff --git a/includes/exec.inc b/includes/exec.inc index 2147616bf9..e58b427aff 100644 --- a/includes/exec.inc +++ b/includes/exec.inc @@ -396,7 +396,7 @@ function drush_start_browser($uri = NULL, $sleep = FALSE, $port = FALSE) { // We can only open a browser if we have a DISPLAY environment variable on // POSIX or are running Windows or OS X. if (!drush_get_context('DRUSH_SIMULATE') && !getenv('DISPLAY') && !drush_is_windows() && !drush_is_osx()) { - drush_log(dt('No graphical display appears to be available, not starting browser.'), LogLevel::NOTICE); + drush_log(dt('No graphical display appears to be available, not starting browser.'), LogLevel::INFO); return FALSE; } $host = parse_url($uri, PHP_URL_HOST); diff --git a/includes/preflight.inc b/includes/preflight.inc index c4796bcf57..7a3d75ac1f 100644 --- a/includes/preflight.inc +++ b/includes/preflight.inc @@ -8,6 +8,11 @@ use Drush\Log\LogLevel; use League\Container\Container; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\OutputInterface; +use Robo\Container\RoboContainer; /** * The main Drush function. @@ -25,8 +30,10 @@ use League\Container\Container; * Whatever the given command returns. */ function drush_main() { - // Load Drush core include files, and parse command line arguments. - if (drush_preflight_prepare() === FALSE) { + // Load Drush core include files, create the container and + // parse commandline arguments + $container = drush_preflight_prepare(); + if ($container === FALSE) { return(1); } // Start code coverage collection. @@ -61,11 +68,25 @@ function drush_main() { } } else { - // Do any necessary preprocessing operations on the command, - // perhaps handling immediately. - $command_handled = drush_preflight_command_dispatch(); - if (!$command_handled) { - $return = $bootstrap->bootstrap_and_dispatch(); + // TODO: If 'DRUSH_SYMFONY' is set, then disable the legacy command + // runner, and use only the Symfony Application. n.b. the legacy runner + // will also try to run commands via the Symfony Application runner if + // it cannot find a matching legacy Drush command. + if (getenv('DRUSH_SYMFONY')) { + // Get the application and run it. + // TODO: We need a new way to handle @alias arguments, + // remote command dispatching, bootstrapping, etc. + $application = $container->get('application'); + $input = drush_symfony_input(); + $application->run($input); + } + else { + // Do any necessary preprocessing operations on the command, + // perhaps handling immediately. + $command_handled = drush_preflight_command_dispatch(); + if (!$command_handled) { + $return = $bootstrap->bootstrap_and_dispatch(); + } } } } @@ -89,6 +110,19 @@ function drush_main() { return $return; } +function drush_symfony_input() { + // Symfony ArgvInput is touchy; fix up the args. + $argv = $_SERVER['argv']; + $scriptname = array_shift($argv); + // Get rid of --php= and --php-options= + while (strpos($argv[0], '--php') === 0) { + array_shift($argv); + } + array_unshift($argv, $scriptname); + + return new ArgvInput($argv); +} + /** * Prepare Drush for preflight. * @@ -140,9 +174,21 @@ function drush_preflight_prepare() { drush_set_context('DRUSH_VENDOR_PATH', dirname($vendor_path)); drush_set_context('DRUSH_CLASSLOADER', $classloader); + // Set up for backwards-compatibility. New code should call + // \Drush::getVersion() and \Drush::getMajorVersion() directly + $drush_version = \Drush::getVersion(); + $version_parts = explode('.', $drush_version); + define('DRUSH_VERSION', $drush_version); + define('DRUSH_MAJOR_VERSION', $version_parts[0]); + define('DRUSH_MINOR_VERSION', $version_parts[1]); + // We need to load our services right away, as we cannot log // or do much else until after this is done. - drush_init_dependency_injection_container(); + $container = drush_init_dependency_injection_container(); + + // Add our core annotation command files to the application. + drush_init_annotation_commands($container); + drush_init_application_global_options($container); // Terminate immediately unless invoked as a command line script if (!drush_verify_cli()) { @@ -159,14 +205,6 @@ function drush_preflight_prepare() { return; // An error was logged. } - // Set up for backwards-compatibility. New code should call - // \Drush::getVersion() and \Drush::getMajorVersion() directly - $drush_version = \Drush::getVersion(); - $version_parts = explode('.', $drush_version); - define('DRUSH_VERSION', $drush_version); - define('DRUSH_MAJOR_VERSION', $version_parts[0]); - define('DRUSH_MINOR_VERSION', $version_parts[1]); - define('DRUSH_REQUEST_TIME', microtime(TRUE)); drush_set_context('argc', $GLOBALS['argc']); @@ -175,6 +213,8 @@ function drush_preflight_prepare() { // Set an error handler and a shutdown function set_error_handler('drush_error_handler'); register_shutdown_function('drush_shutdown'); + + // TODO: Remove drush_parse_args // We need some global options/arguments processed at this early stage. drush_parse_args(); @@ -182,6 +222,8 @@ function drush_preflight_prepare() { _drush_preflight_global_options(); drush_log(dt("Drush preflight prepare loaded autoloader at !autoloader", array('!autoloader' => realpath($vendor_path))), LogLevel::PREFLIGHT); + + return $container; } /** @@ -189,12 +231,34 @@ function drush_preflight_prepare() { * * The Drupal6 boot service is needed in order to show the D6 deprecation message. */ -function drush_init_dependency_injection_container() { - +function drush_init_dependency_injection_container($input = null, $output = null) { // Set up our dependency injection container. $container = new Container(); - $container->share('logger', 'Drush\Log\Logger'); + // Create default input and output objects if they were not provided + if (!$input) { + $input = new StringInput(''); + } + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + $container->add('input', $input); + $container->add('output', $output); + + // Set up Robo's dependency injection container, and configure it as a delegate + $roboContainer = new RoboContainer(); + $roboContainer->add('roboContainer', $roboContainer); + \Robo\Runner::configureContainer($roboContainer, $input, $output); + \Robo\Runner::addServiceProviders($roboContainer); + $container->delegate($roboContainer); + \Robo\Runner::addInflectors($container); + + $container->add('container', $container); + + $container->share('logStyler', \Robo\Log\RoboLogStyle::class); + $container->share('logger', 'Drush\Log\Logger') + ->withArgument('output') + ->withMethodCall('setLogOutputStyler', ['logStyler']); $container->share('bootstrap.default', 'Drush\Boot\EmptyBoot'); $container->share('bootstrap.drupal6', 'Drush\Boot\DrupalBoot6'); $container->share('bootstrap.drupal7', 'Drush\Boot\DrupalBoot7'); @@ -205,12 +269,130 @@ function drush_init_dependency_injection_container() { ->withMethodCall('add', ['bootstrap.drupal6']) ->withMethodCall('add', ['bootstrap.drupal7']) ->withMethodCall('add', ['bootstrap.drupal8']); - + $container->share('globalOptionsEventListener', \Drush\Command\GlobalOptionsEventListener::class); + $container->share('eventDispatcher', \Symfony\Component\EventDispatcher\EventDispatcher::class) + ->withMethodCall('addSubscriber', ['globalOptionsEventListener']); + $container->share('application', 'Symfony\Component\Console\Application') + ->withArgument('Drush Commandline Tool') + ->withArgument(\Drush::getVersion()) + ->withMethodCall('setDispatcher', ['eventDispatcher']) + ->withMethodCall('setAutoExit', [false]); + $container->share('commandDiscovery', 'Consolidation\AnnotatedCommand\CommandFileDiscovery') + ->withMethodCall('addSearchLocation', ['CommandFiles']) + ->withMethodCall('setSearchPattern', ['#.*(Commands|CommandFile).php$#']); + $container->share('formatterManager', 'Consolidation\OutputFormatters\FormatterManager'); + $container->share('backendResultSetter', 'Drush\Backend\BackendResultSetter'); + $container->share('hookManager', 'Consolidation\AnnotatedCommand\Hooks\HookManager') + ->withMethodCall('addOutputExtractor', ['backendResultSetter']); + $container->share('commandProcessor', 'Consolidation\AnnotatedCommand\CommandProcessor') + ->withArgument('hookManager') + ->withMethodCall('setFormatterManager', ['formatterManager']); + $container->share('commandFactory', 'Consolidation\AnnotatedCommand\AnnotatedCommandFactory') + ->withMethodCall('setCommandProcessor', ['commandProcessor']); $container->inflector('Psr\Log\LoggerAwareInterface') - ->invokeMethod('setLogger', ['logger']); + ->invokeMethod('setLogger', ['logger']); // Store the container in the \Drush object \Drush::setContainer($container); + \Robo\Config::setContainer($container); + + return $container; +} + + +// TODO: Where should this go? +function drush_init_application_global_options($container) { + $application = $container->get('application'); + $definition = $application->getDefinition(); + + // TODO: We should make a better way to manage global options + $globalOptions = drush_get_global_options(); + + foreach ($globalOptions as $option => $info) { + $info += [ + 'short-form' => null, + ]; + // TODO: We can't register options that Symfony has already registered, + // but we need a better way than this. + if (array_key_exists('symfony-conflict', $info)) { + continue; + } + if ($info['short-form'] == 'n') { + $info['short-form'] = null; + } + $description = $info['description']; + $default = null; + $mode = InputOption::VALUE_NONE; + if (array_key_exists('example-value', $info)) { + $mode = InputOption::VALUE_REQUIRED; + // TODO: at the moment, global options do not know their default values, + // but if they did, it would look like this: + if (array_key_exists('default-value', $info)) { + $default = $info['default-value']; + $mode = InputOption::VALUE_OPTIONAL; + } + } + // TODO: Any need to make use of InputOption::VALUE_IS_ARRAY? + + $definition->addOption( + new InputOption("--$option", $info['short-form'], $mode, $description, $default) + ); + + // TODO: If the default is TRUE, add a --no alias option. + if ($default === TRUE) { + $definition->addOption( + new InputOption("--no-$option", null, $mode, "Negation of --$option.", FALSE) + ); + } + } +} + +function drush_init_annotation_commands($container) { + $application = $container->get('application'); + $discovery = $container->get('commandDiscovery'); + $commandFiles = $discovery->discover(DRUSH_BASE_PATH . '/lib/Drush', '\Drush'); + drush_init_register_command_files($container, $commandFiles); +} + +function drush_init_register_command_files($container, $commandFiles) { + foreach ($commandFiles as $sourcePath => $className) { + if (!class_exists($className)) { + include $sourcePath; + } + $classAlias = str_replace('\\', '', $className); + // Add and fetch our class from the container to apply the inductors + $container->share($classAlias, $className); + $commandFileInstance = $container->get($classAlias); + drush_add_command_instance($container, $commandFileInstance); + } +} + +function drush_add_command_instance($container, $commandInstance, $includeAllPublicMethods = true) { + if ($commandInstance instanceof Symfony\Component\Console\Command\Command) { + drush_add_command_to_application($container, $commandInstance); + return; + } + drush_create_commands_from_command_instance($container, $commandInstance); +} + +function drush_create_commands_from_command_instance($container, $commandInstance, $includeAllPublicMethods = true) { + $application = $container->get('application'); + $commandFactory = $container->get('commandFactory'); + $commandList = $commandFactory->createCommandsFromClass($commandInstance, $includeAllPublicMethods); + foreach ($commandList as $command) { + drush_add_command_to_application($container, $command); + } +} + +function drush_add_command_to_application($container, $command) { + $application = $container->get('application'); + $commandName = $command->getName(); + $drushAlias = strtr($commandName, ':', '-'); + if ($commandName != $drushAlias) { + $aliases = $command->getAliases(); + $command->setAliases(array_unique(array_merge($aliases, [$drushAlias]))); + } + $application->add($command); } /** @@ -407,6 +589,22 @@ function _drush_preflight_global_options() { $nocolor = !($colors === FALSE || (is_numeric($colors) && $colors >= 3)); } drush_set_context('DRUSH_NOCOLOR', $nocolor); + + // Copy the simulated option to the RoboContainer. + // TODO: Long-term there should be a better way to do this (e.g. via an event listener) + $roboContainer = \Drush::service('roboContainer'); + $roboContainer->setSimulated(drush_get_context('DRUSH_SIMULATE')); + + // Copy the output verbosity into the output object + $verbosity = OutputInterface::VERBOSITY_NORMAL; + if (drush_get_context('DRUSH_VERBOSE')) { + $verbosity = OutputInterface::VERBOSITY_VERBOSE; + } + if (drush_get_context('DRUSH_DEBUG')) { + $verbosity = OutputInterface::VERBOSITY_DEBUG; + } + $output = \Drush::service('output'); + $output->setVerbosity($verbosity); } /** @@ -513,7 +711,7 @@ function _drush_find_commandfiles_drush() { $include = drush_get_context('DRUSH_INCLUDE', array()); foreach ($include as $path) { if (is_dir($path)) { - drush_log('Include ' . $path, LogLevel::NOTICE); + drush_log('Include ' . $path, LogLevel::INFO); $searchpath[] = $path; } } diff --git a/lib/Drush.php b/lib/Drush.php index a2128cb502..67a5841414 100644 --- a/lib/Drush.php +++ b/lib/Drush.php @@ -53,6 +53,9 @@ class Drush { /** * Return the current Drush version. + * + * n.b. Called before the DI container is initialized. + * Do not log, etc. here. */ public static function getVersion() { if (!static::$version) { diff --git a/lib/Drush/Backend/BackendResultSetter.php b/lib/Drush/Backend/BackendResultSetter.php new file mode 100644 index 0000000000..b22c998810 --- /dev/null +++ b/lib/Drush/Backend/BackendResultSetter.php @@ -0,0 +1,14 @@ +get('application'); + $args = drush_get_arguments(); + if (count($args)) { + $name = $args[0]; + if ($this->hasRegisteredSymfonyCommand($application, $name)) { + $command_found = true; + $input = drush_symfony_input(); + $application->run($input); + } + } + } + if (!$command_found) { // If we reach this point, command doesn't fit requirements or we have not // found either a valid or matching command. $this->report_command_error($command); } + + // Prevent a '1' at the end of the output. + if ($return === TRUE) { + $return = ''; + } + return $return; } + protected function hasRegisteredSymfonyCommand($application, $name) { + try { + $application->find($name); + return true; + } + catch (\InvalidArgumentException $e) { + return false; + } + } + /** * {@inheritdoc} */ diff --git a/lib/Drush/Boot/DrupalBoot.php b/lib/Drush/Boot/DrupalBoot.php index f994e6f414..682ada05b4 100644 --- a/lib/Drush/Boot/DrupalBoot.php +++ b/lib/Drush/Boot/DrupalBoot.php @@ -106,13 +106,17 @@ function commandfile_searchpaths($phase, $phase_max = FALSE) { $phase_max = $phase; } - $searchpath = array(); + $container = \Drush::getContainer(); + $discovery = $container->get('commandDiscovery'); + $commandFiles = []; + $searchpath = []; switch ($phase) { case DRUSH_BOOTSTRAP_DRUPAL_ROOT: $drupal_root = \Drush::bootstrapManager()->getRoot(); $searchpath[] = $drupal_root . '/../drush'; $searchpath[] = $drupal_root . '/drush'; $searchpath[] = $drupal_root . '/sites/all/drush'; + $commandFiles = $discovery->discover($searchpath, '\Drupal'); break; case DRUSH_BOOTSTRAP_DRUPAL_SITE: // If we are going to stop bootstrapping at the site, then @@ -141,6 +145,11 @@ function commandfile_searchpaths($phase, $phase_max = FALSE) { } $searchpath = array_merge($searchpath, $this->contrib_themes_paths()); + // Drupal 8 uses the modules' services files to find commandfiles. Should we allow + // redundant find-module-by-location for Drupal 8? (Maybe not.) + if (drush_drupal_major_version() < 8) { + $commandFiles = $discovery->discoverNamespaced($searchpath, '\Drupal'); + } } break; case DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION: @@ -165,8 +174,15 @@ function commandfile_searchpaths($phase, $phase_max = FALSE) { foreach (drush_theme_list() as $key => $value) { $searchpath[] = drupal_get_path('theme', $key); } + // Drupal 8 uses the modules' services files to find commandfiles. Should we allow + // redundant find-module-by-location for Drupal 8? (Maybe not.) + if (drush_drupal_major_version() < 8) { + $commandFiles = $discovery->discoverNamespaced($searchpath, '\Drupal'); + } break; } + // A little inelegant, but will do for now. + drush_init_register_command_files($container, $commandFiles); return $searchpath; } diff --git a/lib/Drush/Boot/DrupalBoot8.php b/lib/Drush/Boot/DrupalBoot8.php index b64dab6b60..46c1bbaa71 100644 --- a/lib/Drush/Boot/DrupalBoot8.php +++ b/lib/Drush/Boot/DrupalBoot8.php @@ -6,6 +6,11 @@ use Symfony\Component\HttpFoundation\Response; use Psr\Log\LoggerInterface; use Drupal\Core\DrupalKernel; +use Drush\Drupal\DrupalKernel as DrushDrupalKernel; +use Drush\Drupal\DrushServiceModfier; +use Symfony\Component\DependencyInjection\Reference; + +use Drush\Log\LogLevel; class DrupalBoot8 extends DrupalBoot { @@ -116,7 +121,15 @@ function bootstrap_drupal_configuration() { $this->request = Request::createFromGlobals(); $classloader = drush_drupal_load_autoloader(DRUPAL_ROOT); // @todo - use Request::create() and then no need to set PHP superglobals - $this->kernel = DrupalKernel::createFromRequest($this->request, $classloader, 'prod'); + $kernelClass = new \ReflectionClass('\Drupal\Core\DrupalKernel'); + if ($kernelClass->hasMethod('addServiceModifier')) { + $this->kernel = DrupalKernel::createFromRequest($this->request, $classloader, 'prod'); + } + else { + $this->kernel = DrushDrupalKernel::createFromRequest($this->request, $classloader, 'prod'); + } + // @see Drush\Drupal\DrupalKernel::addServiceModifier() + $this->kernel->addServiceModifier(new DrushServiceModfier()); // Unset drupal error handler and restore Drush's one. restore_error_handler(); @@ -125,16 +138,54 @@ function bootstrap_drupal_configuration() { } function bootstrap_drupal_full() { + drush_log(dt('About to bootstrap the Drupal 8 Kernel.'), LogLevel::DEBUG); + // TODO: do we need to do ob_start any longer? if (!drush_get_context('DRUSH_QUIET', FALSE)) { ob_start(); } + $this->kernel->invalidateContainer(); $this->kernel->boot(); $this->kernel->prepareLegacyRequest($this->request); if (!drush_get_context('DRUSH_QUIET', FALSE)) { ob_end_clean(); } + drush_log(dt('Finished bootstraping the Drupal 8 Kernel.'), LogLevel::DEBUG); parent::bootstrap_drupal_full(); + + // Get a list of the modules to ignore + $ignored_modules = drush_get_option_list('ignored-modules', array()); + + // We have to get the service command list from the container, because + // it is constructed in an indirect way during the container initialization. + // The upshot is that the list of console commands is not available + // until after $kernel->boot() is called. + $container = \Drupal::getContainer(); + $serviceCommandlist = $container->get('drush.service.consolecommands'); + foreach ($serviceCommandlist->getCommandList() as $command) { + if (!$this->commandIgnored($command, $ignored_modules)) { + drush_log(dt('Add a command: !name', ['!name' => $command->getName()]), LogLevel::DEBUG); + drush_add_command_to_application(\Drush::getContainer(), $command); + } + } + // Do the same thing with the annotation commands. + $serviceCommandlist = $container->get('drush.service.consolidationcommands'); + foreach ($serviceCommandlist->getCommandList() as $commandhandler) { + if (!$this->commandIgnored($commandhandler, $ignored_modules)) { + drush_log(dt('Add a commandhandler: !name', ['!name' => get_class($commandhandler)]), LogLevel::DEBUG); + drush_create_commands_from_command_instance(\Drush::getContainer(), $commandhandler); + } + } + } + + public function commandIgnored($command, $ignored_modules) { + if (empty($ignored_modules)) { + return false; + } + $ignored_regex = '#\\\\(' . implode('|', $ignored_modules) . ')\\\\#'; + $class = new \ReflectionClass($command); + $commandNamespace = $class->getNamespaceName(); + return preg_match($ignored_regex, $commandNamespace); } /** diff --git a/lib/Drush/Command/Commandfiles.php b/lib/Drush/Command/Commandfiles.php index 516f71f3f2..07c813e1c6 100644 --- a/lib/Drush/Command/Commandfiles.php +++ b/lib/Drush/Command/Commandfiles.php @@ -55,7 +55,7 @@ function add($commandfile) { else { // Signal that we should try again on // the next bootstrap phase. - $this->deferred[$module] = $commandfile; + $this->deferred[$module] = $commandfile; } } if ($load_command) { diff --git a/lib/Drush/Command/GlobalOptionsEventListener.php b/lib/Drush/Command/GlobalOptionsEventListener.php new file mode 100644 index 0000000000..c0816cf42f --- /dev/null +++ b/lib/Drush/Command/GlobalOptionsEventListener.php @@ -0,0 +1,36 @@ + 'setGlobalOptions']; + } + + /** + * Before a Console command runs, examine the global + * commandline options from the event Input, and set + * configuration values as appropriate. + * + * @param ConsoleCommandEvent $event + */ + public function setGlobalOptions(ConsoleCommandEvent $event) + { + /* @var Input $input */ + $input = $event->getInput(); + + // TODO: We need a good strategy for managing global options. + // $simulate = $input->getOption('simulate'); + } +} diff --git a/lib/Drush/Command/ServiceCommandlist.php b/lib/Drush/Command/ServiceCommandlist.php new file mode 100644 index 0000000000..b0bcfc3044 --- /dev/null +++ b/lib/Drush/Command/ServiceCommandlist.php @@ -0,0 +1,23 @@ +commandList[] = $command; + } + + public function getCommandList() + { + return $this->commandList; + } +} diff --git a/lib/Drush/CommandFiles/EvalCommandFile.php b/lib/Drush/CommandFiles/EvalCommandFile.php new file mode 100644 index 0000000000..faa6368be9 --- /dev/null +++ b/lib/Drush/CommandFiles/EvalCommandFile.php @@ -0,0 +1,34 @@ +title;' + * Loads node with nid 1 and then prints its title. + * @usage php-eval "file_unmanaged_copy('$HOME/Pictures/image.jpg', 'public://image.jpg');" + * Copies a file whose path is determined by an environment's variable. + * Note the use of double quotes so the variable $HOME gets replaced by + * its value. + * @usage php-eval "node_access_rebuild();" + * Rebuild node access permissions. + * @default-format var_export + */ + public function phpEval($php, $options = + [ + 'format' => 'var_export', + ]) { + return eval($php . ';'); + } +} diff --git a/lib/Drush/CommandFiles/InitCommandFile.php b/lib/Drush/CommandFiles/InitCommandFile.php new file mode 100644 index 0000000000..52af2de7bf --- /dev/null +++ b/lib/Drush/CommandFiles/InitCommandFile.php @@ -0,0 +1,174 @@ + '', + 'add-path' => '', + ]) { + $home = drush_server_home(); + $drush_config_dir = $home . "/.drush"; + $drush_config_file = $drush_config_dir . "/drushrc.php"; + $drush_bashrc = $drush_config_dir . "/drush.bashrc"; + $drush_prompt = $drush_config_dir . "/drush.prompt.sh"; + $drush_complete = $drush_config_dir . "/drush.complete.sh"; + $examples_dir = DRUSH_BASE_PATH . "/examples"; + $example_configuration = $examples_dir . "/example.drushrc.php"; + $example_bashrc = $examples_dir . "/example.bashrc"; + $example_prompt = $examples_dir . "/example.prompt.sh"; + $example_complete = DRUSH_BASE_PATH . "/drush.complete.sh"; + + $collection = $this->collection(); + + // Create a ~/.drush directory if it does not yet exist + $this->taskFileSystemStack() + ->mkdir($drush_config_dir) + ->addToCollection($collection); + + // If there is no ~/.drush/drushrc.php, then copy the + // example Drush configuration file here + if (!is_file($drush_config_file)) { + $this->taskWriteToFile($drush_config_file) + ->textFromFile($example_configuration) + ->addToCollection($collection); + } + + // Decide whether we want to add our Bash commands to + // ~/.bashrc or ~/.bash_profile, and create a task to + // update it with includes of the various files we write, + // as needed. + $bashrc = $this->findBashrc($home); + $taskUpdateBashrc = $this->taskWriteToFile($bashrc) + ->append(); + + // List of Drush bash configuration files, and + // their source templates. + $drushBashFiles = [ + $drush_bashrc => $example_bashrc, + $drush_complete => $example_complete, + $drush_prompt => $example_prompt, + ]; + + // Mapping from Drush bash configuration files + // to a description of what each one is. + $drushBashFileDescriptions = [ + $drush_bashrc => 'Drush bash customizations', + $drush_complete => 'Drush completion', + $drush_prompt => 'Drush prompt customizations', + ]; + + foreach ($drushBashFiles as $destFile => $sourceFile) { + // If the destination file does not exist, then + // copy the example file there. + if (!is_file($destFile)) { + $this->taskWriteToFile($destFile) + ->textFromFile($sourceFile) + ->addToCollection($collection); + $description = $drushBashFileDescriptions[$destFile]; + $collection->progressMessage('Copied {description} to {path}', ['description' => $description, 'path' => $destFile], LogLevel::OK); + $pattern = basename($destFile); + $taskUpdateBashrc->appendUnlessMatches("#$pattern#", "# Include $description.\n". $this->bashAddition($destFile)); + } + } + + // If Drush is not in the $PATH, then figure out which + // path to add so that Drush can be found globally. + $add_path = $options['add-path']; + if ((!drush_which("drush") || $add_path) && ($add_path !== FALSE)) { + $drush_path = $this->findPathToDrush(); + $drush_path = preg_replace("%^" . preg_quote($home) . "/%", '$HOME/', $drush_path); + $pattern = "$drush_path"; + $taskUpdateBashrc->appendUnlessMatches("#$pattern#", "# Path to Drush, added by 'drush init'.\nexport PATH=\"\$PATH:$drush_path\"\n\n"); + } + + $openEditor = FALSE; + if ($taskUpdateBashrc->wouldChange()) { + if (drush_confirm(dt("Modify !file to include Drush configuration files?", array('!file' => $bashrc)))) { + $collection->add($taskUpdateBashrc); + $collection->progressMessage('Updated bash configuration file {path}', ['path' => $bashrc], LogLevel::OK); + $collection->progressMessage('Start a new shell in order to experience the improvements (e.g. `{shell}`).', ['shell' => 'bash'], LogLevel::OK); + $openEditor = $options['edit']; + } + else { + return drush_user_abort(); + } + } + else { + $collection->progressMessage('No code added to {path}', ['path' => $bashrc]); + } + $result = $collection->run(); + + if ($result->wasSuccessful() && $openEditor) { + $exec = drush_get_editor(); + drush_shell_exec_interactive($exec, $drush_config_file, $drush_config_file); + } + + return $result; + } + + /** + * Determine which .bashrc file is best to use on this platform. + */ + protected function findBashrc($home) { + return $home . "/.bashrc"; + } + + /** + * Determine where Drush is located, so that we can add + * that location to the $PATH + */ + protected function findPathToDrush() { + // First test: is Drush inside a vendor directory? + // Does vendor/bin exist? If so, use that. We do + // not have a good way to locate the 'bin' directory + // if it has been relocated in the composer.json config + // section. + if ($vendor_pos = strpos(DRUSH_BASE_PATH, "/vendor/")) { + $vendor_dir = substr(DRUSH_BASE_PATH, 0, $vendor_pos + 7); + $vendor_bin = $vendor_dir . '/bin'; + if (is_dir($vendor_bin)) { + return $vendor_bin; + } + } + + // Fallback is to use the directory that Drush is in. + return DRUSH_BASE_PATH; + } + + protected function bashAddition($file) { + return <<initializeSettings($request); + return $kernel; + } + + /** + * Add a service modifier to the container builder. + * + * The container is not compiled until $kernel->boot(), so there is a chance + * for clients to add compiler passes et. al. before then. + */ + public function addServiceModifier(ServiceModifierInterface $serviceModifier) { + drush_log(dt("add service modifier"), LogLevel::DEBUG); + $this->serviceModifiers[] = $serviceModifier; + } + + /** + * @inheritdoc + */ + protected function getContainerBuilder() { + drush_log(dt("get container builder"), LogLevel::DEBUG); + $container = parent::getContainerBuilder(); + foreach ($this->serviceModifiers as $serviceModifier) { + $serviceModifier->alter($container); + } + return $container; + } +} diff --git a/lib/Drush/Drupal/DrushServiceModfier.php b/lib/Drush/Drupal/DrushServiceModfier.php new file mode 100644 index 0000000000..c895f2e55b --- /dev/null +++ b/lib/Drush/Drupal/DrushServiceModfier.php @@ -0,0 +1,22 @@ +register('drush.service.consolecommands', 'Drush\Command\ServiceCommandlist'); + $container->addCompilerPass(new FindCommandsCompilerPass('drush.service.consolecommands', 'console.command')); + $container->register('drush.service.consolidationcommands', 'Drush\Command\ServiceCommandlist'); + $container->addCompilerPass(new FindCommandsCompilerPass('drush.service.consolidationcommands', 'consolidation.commandhandler')); + } +} diff --git a/lib/Drush/Drupal/FindCommandsCompilerPass.php b/lib/Drush/Drupal/FindCommandsCompilerPass.php new file mode 100644 index 0000000000..b1e515de1a --- /dev/null +++ b/lib/Drush/Drupal/FindCommandsCompilerPass.php @@ -0,0 +1,70 @@ +boot(), when Drupal's dependency injection container is being + * compiled. Since we cannot use the container at this point (since its + * initialization is not yet complete), we instead alter the definition of + * a storage class in the container to add more setter injection method + * calls to 'addCommandReference'. + * + * Later, after the container has been completely initialized, we can + * fetch the storage class from the DI container (perhaps also via + * injection from a reference in the container). At that point, we can + * request the list of Console commands that were added via the + * (delayed) call(s) to addCommandReference. + * + * Documentation: + * + * http://symfony.com/doc/2.7/components/dependency_injection/tags.html#create-a-compilerpass + */ +class FindCommandsCompilerPass implements CompilerPassInterface +{ + protected $storageClassId; + protected $tagId; + + public function __construct($storageClassId, $tagId) + { + $this->storageClassId = $storageClassId; + $this->tagId = $tagId; + } + + public function process(ContainerBuilder $container) + { + drush_log(dt("process !storage !tag", ['!storage' => $this->storageClassId, '!tag' => $this->tagId]), LogLevel::DEBUG); + // We expect that our called registered the storage + // class under the storage class id before adding this + // compiler pass, but we will test this presumption to be sure. + if (!$container->has($this->storageClassId)) { + drush_log(dt("storage class not registered"), LogLevel::DEBUG); + return; + } + + $definition = $container->findDefinition( + $this->storageClassId + ); + + $taggedServices = $container->findTaggedServiceIds( + $this->tagId + ); + foreach ($taggedServices as $id => $tags) { + drush_log(dt("found tagged service !id", ['!id' => $id]), LogLevel::DEBUG); + $definition->addMethodCall( + 'addCommandReference', + array(new Reference($id)) + ); + } + } +} diff --git a/lib/Drush/Log/Logger.php b/lib/Drush/Log/Logger.php index cfe3c212ed..d74ace01d6 100644 --- a/lib/Drush/Log/Logger.php +++ b/lib/Drush/Log/Logger.php @@ -27,8 +27,14 @@ use Drush\Log\LogLevel; use Psr\Log\AbstractLogger; +use Robo\Log\RoboLogger; +use Symfony\Component\Console\Output\OutputInterface; -class Logger extends AbstractLogger { +class Logger extends RoboLogger { + + public function __construct(OutputInterface $output) { + parent::__construct($output); + } public function log($level, $message, array $context = array()) { // Convert to old $entry array for b/c calls @@ -84,8 +90,11 @@ public function log($level, $message, array $context = array()) { return TRUE; } $type_msg = sprintf($green, $level); + $level = LogLevel::NOTICE; break; case LogLevel::NOTICE : + $type_msg = sprintf("[%s]", $level); + break; case 'message' : // Obsolete; only here in case contrib is using it. case LogLevel::INFO : if (!$verbose) { @@ -93,6 +102,7 @@ public function log($level, $message, array $context = array()) { return TRUE; } $type_msg = sprintf("[%s]", $level); + $level = LogLevel::INFO; break; case LogLevel::DEBUG_NOTIFY : $level = LogLevel::DEBUG; // Report 'debug', handle like 'preflight' @@ -102,6 +112,7 @@ public function log($level, $message, array $context = array()) { return TRUE; } $type_msg = sprintf("[%s]", $level); + $level = LogLevel::DEBUG; break; case LogLevel::BOOTSTRAP : case LogLevel::DEBUG : @@ -111,6 +122,7 @@ public function log($level, $message, array $context = array()) { return TRUE; } $type_msg = sprintf("[%s]", $level); + $level = LogLevel::DEBUG; break; } @@ -129,18 +141,27 @@ public function log($level, $message, array $context = array()) { $entry['message'] = $entry['message'] . ' ' . $timer; } + $message = $entry['message']; +/* + // Drush-styled output + + $message = $this->interpolate( + $message, + $this->getLogOutputStyler()->style($context) + ); + $width[0] = ($columns - 11); $format = sprintf("%%-%ds%%%ds", $width[0], $width[1]); // Place the status message right aligned with the top line of the error message. - $message = wordwrap($entry['message'], $width[0]); + $message = wordwrap($message, $width[0]); $lines = explode("\n", $message); $lines[0] = sprintf($format, $lines[0], $type_msg); $message = implode("\n", $lines); - drush_print($message, 0, STDERR); - + $this->getErrorStreamWrapper()->writeln($message); +*/ + // Robo-styled output + parent::log($level, $message, $context); } - - } diff --git a/lib/Drush/Sql/SqlBase.php b/lib/Drush/Sql/SqlBase.php index d05f504aa9..7b42074c4b 100644 --- a/lib/Drush/Sql/SqlBase.php +++ b/lib/Drush/Sql/SqlBase.php @@ -176,7 +176,7 @@ public function query($query, $input_file = NULL, $result_file = '') { // but the sql query itself is stored in a temp file and not displayed. // We show the query when --debug is used and this function created the temp file. if ((drush_get_context('DRUSH_DEBUG') || drush_get_context('DRUSH_SIMULATE')) && empty($input_file_original)) { - drush_log('sql-query: ' . $query, LogLevel::NOTICE); + drush_log('sql-query: ' . $query, LogLevel::INFO); } $success = drush_shell_exec($exec); diff --git a/lib/Drush/UpdateService/Project.php b/lib/Drush/UpdateService/Project.php index d933922ae7..a4fb8c8c98 100644 --- a/lib/Drush/UpdateService/Project.php +++ b/lib/Drush/UpdateService/Project.php @@ -603,7 +603,7 @@ function getReleaseNotes($version = NULL, $print_status = TRUE, $tmpfile = NULL) $filename = drush_download_file($release_link, drush_tempnam($project_name)); @$dom = \DOMDocument::loadHTMLFile($filename); if ($dom) { - drush_log(dt("Successfully parsed and loaded the HTML contained in the release notes' page for !project (!version) project.", array('!project' => $project_name, '!version' => $version)), LogLevel::NOTICE); + drush_log(dt("Successfully parsed and loaded the HTML contained in the release notes' page for !project (!version) project.", array('!project' => $project_name, '!version' => $version)), LogLevel::INFO); } else { drush_log(dt("Error while requesting the release notes page for !project project.", array('!project' => $project_name)), LogLevel::ERROR); diff --git a/tests/Unish/CommandUnishTestCase.php b/tests/Unish/CommandUnishTestCase.php index 83251d128e..2fea791f13 100644 --- a/tests/Unish/CommandUnishTestCase.php +++ b/tests/Unish/CommandUnishTestCase.php @@ -386,7 +386,8 @@ function parse_backend_output($string) { function assertLogHasMessage($log, $message, $logType = FALSE) { foreach ($log as $entry) { if (!$logType || ($entry['type'] == $logType)) { - if (strpos($entry['message'], $message) !== FALSE) { + $logMessage = $this->getLogMessage($entry); + if (strpos($logMessage, $message) !== FALSE) { return TRUE; } } @@ -394,6 +395,23 @@ function assertLogHasMessage($log, $message, $logType = FALSE) { $this->fail("Could not find expected message in log: " . $message); } + protected function getLogMessage($entry) { + return $this->interpolate($entry['message'], $entry); + } + + protected function interpolate($message, array $context) + { + // build a replacement array with braces around the context keys + $replace = array(); + foreach ($context as $key => $val) { + if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) { + $replace[sprintf('{%s}', $key)] = $val; + } + } + // interpolate replacement values into the message and return + return strtr($message, $replace); + } + function drush_major_version() { static $major; diff --git a/tests/annotatedCommandTest.php b/tests/annotatedCommandTest.php new file mode 100644 index 0000000000..94ca92bb97 --- /dev/null +++ b/tests/annotatedCommandTest.php @@ -0,0 +1,160 @@ +setUpDrupal(1, TRUE); + $uri = key($sites); + $root = $this->webroot(); + $options = array( + 'root' => $root, + 'uri' => $uri, + 'yes' => NULL, + ); + + // Copy the 'woot' module over to the Drupal site we just set up. + $this->setupModulesForTests($root); + + // Enable out module. This will also clear the commandfile cache. + $this->drush('pm-enable', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); + + // drush woot --help + $this->drush('woot', array(), $options + ['help' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertContains('Woot mightily.', $output); + // TODO: Symfony Console does not print alias info like this + // $this->assertContains('Aliases: wt', $output); + + // drush help woot. TODO: drush help does not find annotated commands yet +// $this->drush('help', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); +// $output = $this->getOutput(); +// $this->assertContains('Woot mightily.', $output); + + // drush woot + $this->drush('woot', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertEquals('Woot!', $output); + + // drush my-cat --help + $this->drush('my-cat', array(), $options + ['help' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + // TODO: the command description does not appear in the help text yet + //$this->assertContains('This is the my-cat command', $output); + $this->assertContains('bet alpha --flip', $output); + $this->assertContains('The first parameter', $output); + $this->assertContains('The other parameter', $output); + $this->assertContains('Whether or not the second parameter', $output); + // TODO: Symfony Console does not print alias info like this + // $this->assertContains('Aliases: c', $output); + + // drush help my-cat + // TODO: help cannot find annotated commands yet + //$this->drush('help', array('my-cat'), $options, NULL, NULL, self::EXIT_SUCCESS); + //$output = $this->getOutput(); + //$this->assertContains('This is the my-cat command', $output); + + // drush my-cat bet alpha --flip + $this->drush('my-cat', array('bet', 'alpha'), $options + ['flip' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertEquals('alphabet', $output); + + // drush woot --help with the 'woot' module ignored + $this->drush('woot', array(), $options + ['help' => NULL, 'ignored-modules' => 'woot'], NULL, NULL, self::EXIT_ERROR); + + // drush my-cat bet alpha --flip + $this->drush('my-cat', array('bet', 'alpha'), $options + ['flip' => NULL, 'ignored-modules' => 'woot'], NULL, NULL, self::EXIT_ERROR); + + $this->drush('try-formatters', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $expected = <<assertEquals($expected, $output); + + $this->drush('try-formatters --format=yaml --fields=III,II', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $expected = <<assertEquals($expected, $output); + + $this->drush('try-formatters', array(), $options + ['backend' => NULL]); + $parsed = $this->parse_backend_output($this->getOutput()); + $data = $parsed['object']; + $expected = <<assertEquals($expected, json_encode($data)); + + // drush try-formatters --help + $this->drush('try-formatters', array(), $options + ['help' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + // TODO: Command description does not appear in help text yet + //$this->assertContains('Demonstrate formatters', $output); + $this->assertContains('try:formatters --fields=first,third', $output); + $this->assertContains('try:formatters --fields=III,II', $output); + // TODO: Help for formats and fields not available yet + //$this->assertContains('--fields=', $output); + //$this->assertContains('Fields to output. All available', $output); + //$this->assertContains('--format=', $output); + //$this->assertContains('Select output format. Available:', $output); + // TODO: Symfony Console does not print alias info like this + // $this->assertContains('Aliases: try-formatters', $output); + + // If we are running Drupal version 8 or later, then also check to + // see if the demo:greet and annotated:greet commands are available. + if (UNISH_DRUPAL_MAJOR_VERSION >= 8) { + $this->drush('demo:greet symfony', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertEquals('Hello symfony', $output); + + $this->drush('annotated:greet symfony', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertEquals('Hello symfony', $output); + } + + // Disable the woot module to avoid cross-contamination of the Drupal + // test site's database. (not necessary?) + if (UNISH_DRUPAL_MAJOR_VERSION >= 8) { + $this->drush('pm-uninstall', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); + } + else { + $this->drush('pm-disable', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); + } + // Also kill the Drush cache so that our 'woot' command is not cached. + $this->drush('cache-clear', array('drush'), $options, NULL, NULL, self::EXIT_SUCCESS); + } + + public function setupModulesForTests($root) { + $wootModule = __DIR__ . '/resources/modules/d' . UNISH_DRUPAL_MAJOR_VERSION . '/woot'; + $modulesDir = "$root/sites/all/modules"; + $this->mkdir($modulesDir); + \symlink($wootModule, "$modulesDir/woot"); + if ((UNISH_DRUPAL_MAJOR_VERSION < 8) && !file_exists("$wootModule/Command/WootCommands.php")) { + $woot8Module = __DIR__ . '/resources/modules/d8/woot'; + \symlink("$woot8Module/src/Command/WootCommands.php", "$wootModule/Command/WootCommands.php"); + } + } +} diff --git a/tests/initCommandTest.php b/tests/initCommandTest.php index b5b913d6fa..ef7bbb3a80 100644 --- a/tests/initCommandTest.php +++ b/tests/initCommandTest.php @@ -15,8 +15,8 @@ function testInitCommand() { $this->drush('core-init', array(), array('backend' => NULL, 'add-path' => TRUE, 'yes' => NULL)); $parsed = $this->parse_backend_output($this->getOutput()); // First test to ensure that the command claimed to have made the expected progress - $this->assertLogHasMessage($parsed['log'], "Copied example Drush configuration file", 'ok'); - $this->assertLogHasMessage($parsed['log'], "Copied example Drush bash configuration file", 'ok'); + $this->assertLogHasMessage($parsed['log'], "Copied Drush bash customizations", 'ok'); + $this->assertLogHasMessage($parsed['log'], "Copied Drush completion", 'ok'); $this->assertLogHasMessage($parsed['log'], "Updated bash configuration file", 'ok'); // Next we will test to see if there is evidence that those // operations worked. diff --git a/tests/resources/modules/d7/woot/Command/.gitignore b/tests/resources/modules/d7/woot/Command/.gitignore new file mode 100644 index 0000000000..772f99a1e4 --- /dev/null +++ b/tests/resources/modules/d7/woot/Command/.gitignore @@ -0,0 +1 @@ +WootCommands.php diff --git a/tests/resources/modules/d7/woot/woot.info b/tests/resources/modules/d7/woot/woot.info new file mode 100644 index 0000000000..4a01a94af5 --- /dev/null +++ b/tests/resources/modules/d7/woot/woot.info @@ -0,0 +1,4 @@ +name = woot +description = Woot Mightily +core = 7.x +files[] = woot.module diff --git a/tests/resources/modules/d7/woot/woot.module b/tests/resources/modules/d7/woot/woot.module new file mode 100644 index 0000000000..f51b34a5be --- /dev/null +++ b/tests/resources/modules/d7/woot/woot.module @@ -0,0 +1,22 @@ + 'Woot', + 'description' => 'Woot mightily.', + 'page callback' => 'woot_page', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + return $items; +} + +function woot_page() { + return array('#markup' => 'Woot!'); +} diff --git a/tests/resources/modules/d8/woot/composer.json b/tests/resources/modules/d8/woot/composer.json new file mode 100644 index 0000000000..72d8757320 --- /dev/null +++ b/tests/resources/modules/d8/woot/composer.json @@ -0,0 +1,14 @@ +{ + "name": "drupal/woot", + "type": "drupal-module", + "description": "Woot Mightily.", + "keywords": ["Drupal"], + "license": "GPL-2.0+", + "homepage": "http://drupal.org/project/woot", + "minimum-stability": "dev", + "support": { + "issues": "http://drupal.org/project/issues/woot", + "source": "http://cgit.drupalcode.org/woot" + }, + "require": { } +} diff --git a/tests/resources/modules/d8/woot/src/Command/AnnotatedGreetCommand.php b/tests/resources/modules/d8/woot/src/Command/AnnotatedGreetCommand.php new file mode 100644 index 0000000000..eeb3752aef --- /dev/null +++ b/tests/resources/modules/d8/woot/src/Command/AnnotatedGreetCommand.php @@ -0,0 +1,41 @@ +getArgument('name'); + if ($name) { + $text = 'Hello '.$name; + } else { + $text = 'Hello'; + } + + if ($input->getOption('yell')) { + $text = strtoupper($text); + } + + $output->writeln($text); + } +} diff --git a/tests/resources/modules/d8/woot/src/Command/GreetCommand.php b/tests/resources/modules/d8/woot/src/Command/GreetCommand.php new file mode 100644 index 0000000000..ac4184c3a5 --- /dev/null +++ b/tests/resources/modules/d8/woot/src/Command/GreetCommand.php @@ -0,0 +1,52 @@ +setName('demo:greet') + ->setDescription('Greet someone') + ->addArgument( + 'name', + InputArgument::OPTIONAL, + 'Who do you want to greet?' + ) + ->addOption( + 'yell', + null, + InputOption::VALUE_NONE, + 'If set, the task will yell in uppercase letters' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $name = $input->getArgument('name'); + if ($name) { + $text = 'Hello '.$name; + } else { + $text = 'Hello'; + } + + if ($input->getOption('yell')) { + $text = strtoupper($text); + } + + $output->writeln($text); + } +} diff --git a/tests/resources/modules/d8/woot/src/Command/WootCommands.php b/tests/resources/modules/d8/woot/src/Command/WootCommands.php new file mode 100644 index 0000000000..0f2cdfe882 --- /dev/null +++ b/tests/resources/modules/d8/woot/src/Command/WootCommands.php @@ -0,0 +1,66 @@ + false]) + { + if ($options['flip']) { + return "{$two}{$one}"; + } + return "{$one}{$two}"; + } + + /** + * Demonstrate formatters. Default format is 'table'. + * + * @field-labels + * first: I + * second: II + * third: III + * @usage try:formatters --format=yaml + * @usage try:formatters --format=csv + * @usage try:formatters --fields=first,third + * @usage try:formatters --fields=III,II + * @return Consolidation\OutputFormatters\StructuredData\RowsOfFields + */ + public function tryFormatters($options = ['format' => 'table', 'fields' => '']) + { + $outputData = [ + 'en' => [ 'first' => 'One', 'second' => 'Two', 'third' => 'Three' ], + 'de' => [ 'first' => 'Eins', 'second' => 'Zwei', 'third' => 'Drei' ], + 'jp' => [ 'first' => 'Ichi', 'second' => 'Ni', 'third' => 'San' ], + 'es' => [ 'first' => 'Uno', 'second' => 'Dos', 'third' => 'Tres' ], + ]; + return new RowsOfFields($outputData); + } +} diff --git a/tests/resources/modules/d8/woot/src/Controller/WootController.php b/tests/resources/modules/d8/woot/src/Controller/WootController.php new file mode 100644 index 0000000000..4f9234d019 --- /dev/null +++ b/tests/resources/modules/d8/woot/src/Controller/WootController.php @@ -0,0 +1,31 @@ + 'markup', + '#markup' => $this->t('Woot!') + ]; + } + +} diff --git a/tests/resources/modules/d8/woot/src/WootManager.php b/tests/resources/modules/d8/woot/src/WootManager.php new file mode 100644 index 0000000000..9802835585 --- /dev/null +++ b/tests/resources/modules/d8/woot/src/WootManager.php @@ -0,0 +1,54 @@ +currentUser = $current_user; + } + + /** + * Woof mightily. Note that we can include commands directly + * inside a service class. + * + * @command woof + * @aliases wf + */ + public function woof() + { + return 'Woof!'; + } +} diff --git a/tests/resources/modules/d8/woot/woot.info.yml b/tests/resources/modules/d8/woot/woot.info.yml new file mode 100644 index 0000000000..cd849fbd5e --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.info.yml @@ -0,0 +1,5 @@ +name: Woot +type: module +description: Woot Mightily. +core: 8.x +package: Other diff --git a/tests/resources/modules/d8/woot/woot.module b/tests/resources/modules/d8/woot/woot.module new file mode 100644 index 0000000000..b1535c4d4a --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.module @@ -0,0 +1,33 @@ +' . t('About') . ''; + $output .= '

' . t('Woot Mightily.') . '

'; + return $output; + + default: + } +} + +/** + * Implements hook_theme(). + */ +function woot_theme() { + $theme = []; + + return $theme; +} diff --git a/tests/resources/modules/d8/woot/woot.routing.yml b/tests/resources/modules/d8/woot/woot.routing.yml new file mode 100644 index 0000000000..a607603b65 --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.routing.yml @@ -0,0 +1,8 @@ + +woot.woot_controller_woot: + path: '/woot' + defaults: + _controller: '\Drupal\woot\Controller\WootController::woot' + _title: 'Woot' + requirements: + _permission: 'access content' diff --git a/tests/resources/modules/d8/woot/woot.services.yml b/tests/resources/modules/d8/woot/woot.services.yml new file mode 100644 index 0000000000..51666bcc30 --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.services.yml @@ -0,0 +1,18 @@ +services: + woot.manager: + class: Drupal\woot\WootManager + arguments: ['@current_user'] + tags: + - { name: consolidation.commandhandler } + woot.command: + class: Drupal\woot\Command\WootCommands + tags: + - { name: consolidation.commandhandler } + greet.command: + class: Drupal\woot\Command\GreetCommand + tags: + - { name: console.command } + annotated_greet.command: + class: Drupal\woot\Command\AnnotatedGreetCommand + tags: + - { name: console.command }