From 1b305448b103f66ba8df27780c4637718b36078d Mon Sep 17 00:00:00 2001 From: Moshe Weitzman Date: Mon, 12 Dec 2016 17:14:38 -0500 Subject: [PATCH] Port cache commands to annotated (#2498) * Port cache commands to Annotated. * Remove a code comment. * Remove old file. * Misc minot fixes and renames. * Update to new cache clear method * Remove debug code. * Cast topic element to a bool to match old API --- commands/core/cache.drush.inc | 307 ---------------------- commands/core/drupal/cache.inc | 6 +- commands/core/drupal/cache_8.inc | 6 +- commands/core/topic.drush.inc | 2 +- composer.lock | 124 ++++----- includes/annotationcommand_adapter.inc | 6 +- lib/Drush/Commands/core/CacheCommands.php | 269 +++++++++++++++++++ lib/Drush/Commands/core/CoreCommands.php | 18 +- lib/Drush/Commands/core/ViewsCommands.php | 15 +- tests/cacheCommandTest.php | 2 +- 10 files changed, 359 insertions(+), 396 deletions(-) delete mode 100644 commands/core/cache.drush.inc create mode 100644 lib/Drush/Commands/core/CacheCommands.php diff --git a/commands/core/cache.drush.inc b/commands/core/cache.drush.inc deleted file mode 100644 index 1df12cbca2..0000000000 --- a/commands/core/cache.drush.inc +++ /dev/null @@ -1,307 +0,0 @@ - 'Fetch a cached object and display it.', - 'examples' => array( - 'drush cache-get schema' => 'Display the data for the cache id "schema" from the "cache" bin.', - 'drush cache-get update_available_releases update' => 'Display the data for the cache id "update_available_releases" from the "update" bin.', - ), - 'arguments' => array( - 'cid' => 'The id of the object to fetch.', - 'bin' => 'Optional. The cache bin to fetch from.', - ), - 'required-arguments' => 1, - 'callback' => 'drush_cache_command_get', - 'outputformat' => array( - 'default' => 'print-r', - 'pipe-format' => 'var_export', - 'output-data-type' => TRUE, - ), - 'aliases' => array('cg'), - ); - $items['cache-clear'] = array( - 'bootstrap' => DRUSH_BOOTSTRAP_MAX, - 'description' => 'Clear a specific cache, or all drupal caches.', - 'arguments' => array( - 'type' => 'The particular cache to clear. Omit this argument to choose from available caches.', - ), - 'callback' => 'drush_cache_command_clear', - 'aliases' => array('cc'), - ); - $items['cache-set'] = array( - 'description' => 'Cache an object expressed in JSON or var_export() format.', - 'arguments' => array( - 'cid' => 'The id of the object to set.', - 'data' => 'The object to set in the cache. Use \'-\' to read the object from STDIN.', - 'bin' => 'Optional. The cache bin to store the object in.', - 'expire' => 'Optional. CACHE_PERMANENT, CACHE_TEMPORARY, or a Unix timestamp.', - 'tags' => 'An array of cache tags.', - ), - 'required-arguments' => 2, - 'options' => array( - // Note that this is not an outputformat option. - 'format' => 'Format to parse the object. Use "string" for string (default), and "json" for JSON.', - 'cache-get' => 'If the object is the result a previous fetch from the cache, only store the value in the "data" property of the object in the cache.', - ), - 'callback' => 'drush_cache_command_set', - 'aliases' => array('cs'), - ); - $items['cache-rebuild'] = array( - 'description' => 'Rebuild a Drupal 8 site and clear all its caches.', - 'options' => array(), - 'arguments' => array(), - // Bootstrap to DRUSH_BOOTSTAP_DRUPAL_SITE to pick the correct site. - // Further bootstrap is done by the rebuild script. - 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE, - 'core' => array('8+'), - 'aliases' => array('cr', 'rebuild'), - ); - - return $items; -} - -/** - * Command argument complete callback. - * - * @return - * Array of clear types. - */ -function cache_cache_clear_complete() { - // Bootstrap as far as possible so that Views and others can list their caches. - drush_bootstrap_max(); - return array('values' => array_keys(drush_cache_clear_types(TRUE))); -} - -function drush_cache_clear_pre_validate($type = NULL) { - $types = drush_cache_clear_types(drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)); - // Check if the provided type ($type) is a valid cache type. - if ($type && !array_key_exists($type, $types)) { - if ($type === 'all' && drush_drupal_major_version() >= 8) { - return drush_set_error(dt('`cache-clear all` is deprecated for Drupal 8 and later. Please use the `cache-rebuild` command instead.')); - } - // If we haven't done a full bootstrap, provide a more - // specific message with instructions to the user on - // bootstrapping a Drupal site for more options. - if (!drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { - $all_types = drush_cache_clear_types(TRUE); - if (array_key_exists($type, $all_types)) { - return drush_set_error(dt("'!type' cache requires a working Drupal site to operate on. Use the --root and --uri options, or a site @alias, or cd to a directory containing a Drupal settings.php file.", array('!type' => $type))); - } - else { - return drush_set_error(dt("'!type' cache is not a valid cache type. There may be more cache types available if you select a working Drupal site.", array('!type' => $type))); - } - } - return drush_set_error(dt("'!type' cache is not a valid cache type.", array('!type' => $type))); - } -} - -/** - * Command callback for drush cache-clear. - */ -function drush_cache_command_clear($type = NULL) { - if (!drush_get_option('cache-clear', TRUE)) { - drush_log(dt("Skipping cache-clear operation due to --cache-clear=0 option."), LogLevel::OK); - return TRUE; - } - $types = drush_cache_clear_types(drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)); - - if (!isset($type)) { - // Don't offer 'all' unless Drush has bootstrapped the Drupal site - if (!drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { - unset($types['all']); - } - $type = drush_choice($types, 'Enter a number to choose which cache to clear.', '!key'); - if (empty($type)) { - return drush_user_abort(); - } - } - // Do it. - drush_op($types[$type]); - if ($type == 'all' && !drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { - drush_log(dt("No Drupal site found, only 'drush' cache was cleared."), LogLevel::WARNING); - } - else { - drush_log(dt("'!name' cache was cleared.", array('!name' => $type)), LogLevel::SUCCESS); - } -} - -/** - * Print an object returned from the cache. - * - * @param $cid - * The cache ID of the object to fetch. - * @param $bin - * A specific bin to fetch from. If not specified, the default bin is used. - */ -function drush_cache_command_get($cid = NULL, $bin = NULL) { - drush_include_engine('drupal', 'cache'); - $result = drush_op('_drush_cache_command_get', $cid, $bin); - - if (empty($result)) { - return drush_set_error('DRUSH_CACHE_OBJECT_NOT_FOUND', dt('The !cid object in the !bin bin was not found.', array('!cid' => $cid, '!bin' => $bin ? $bin : _drush_cache_bin_default()))); - } - return $result; -} - -/** - * Set an object in the cache. - * - * @param $cid - * The cache ID of the object to fetch. - * @param $data - * The data to save to the cache, or '-' to read from STDIN. - * @param $bin - * A specific bin to fetch from. If not specified, the default bin is used. - * @param $expire - * The expiry timestamp for the cached object. - * @param $tags - * Cache tags for the cached object. - */ -function drush_cache_command_set($cid = NULL, $data = '', $bin = NULL, $expire = NULL, $tags = array()) { - // In addition to prepare, this also validates. Can't easily be in own validate callback as - // reading once from STDIN empties it. - $data = drush_cache_set_prepare_data($data); - if ($data === FALSE && drush_get_error()) { - // An error was logged above. - return; - } - - drush_include_engine('drupal', 'cache'); - return drush_op('_drush_cache_command_set', $cid, $data, $bin, $expire, $tags); -} - -function drush_cache_set_prepare_data($data) { - if ($data == '-') { - $data = file_get_contents("php://stdin"); - } - - // Now, we parse the object. - switch (drush_get_option('format', 'string')) { - case 'json': - $data = drush_json_decode($data); - break; - } - - if (drush_get_option('cache-get')) { - // $data might be an object. - if (is_object($data) && $data->data) { - $data = $data->data; - } - // But $data returned from `drush cache-get --format=json` will be an array. - elseif (is_array($data) && isset($data['data'])) { - $data = $data['data']; - } - else { - // If $data is neither object nor array and cache-get was specified, then - // there is a problem. - return drush_set_error('CACHE_INVALID_FORMAT', dt("'cache-get' was specified as an option, but the data is neither an object or an array.")); - } - } - - return $data; -} - -/** - * All types of caches available for clearing. Contrib commands can alter in their own. - */ -function drush_cache_clear_types($include_bootstrapped_types = FALSE) { - drush_include_engine('drupal', 'cache'); - $types = _drush_cache_clear_types($include_bootstrapped_types); - - // Include the appropriate environment engine, so callbacks can use core - // version specific cache clearing functions directly. - drush_include_engine('drupal', 'environment'); - - // Command files may customize $types as desired. - drush_command_invoke_all_ref('drush_cache_clear', $types, $include_bootstrapped_types); - - return $types; -} - -/** - * Clear caches internal to drush core. - */ -function drush_cache_clear_drush() { - drush_cache_clear_all(NULL, 'default'); // commandfiles, etc. - drush_cache_clear_all(NULL, 'complete'); // completion - // Release XML. We don't clear tarballs since those never change. - $matches = drush_scan_directory(drush_directory_cache('download'), "/^https---updates.drupal.org-release-history/", array('.', '..')); - array_map('unlink', array_keys($matches)); -} - -/** - * Rebuild a Drupal 8 site. - * - * This is a transpose of core/rebuild.php. Additionally - * it also clears drush cache and drupal render cache. - */ -function drush_cache_rebuild() { - if (!drush_get_option('cache-clear', TRUE)) { - drush_log(dt("Skipping cache-clear operation due to --cache-clear=0 option."), LogLevel::OK); - return TRUE; - } - chdir(DRUPAL_ROOT); - - // Clear the APC cache to ensure APC class loader is reset. - if (function_exists('apc_fetch')) { - apc_clear_cache('user'); - } - // Clear user cache for all major platforms. - $user_caches = [ - 'apcu_clear_cache', - 'wincache_ucache_clear', - 'xcache_clear_cache', - ]; - array_map('call_user_func', array_filter($user_caches, 'is_callable')); - - $autoloader = drush_drupal_load_autoloader(DRUPAL_ROOT); - require_once DRUSH_DRUPAL_CORE . '/includes/utility.inc'; - - $request = Request::createFromGlobals(); - // Ensure that the HTTP method is set, which does not happen with Request::createFromGlobals(). - $request->setMethod('GET'); - // Manually resemble early bootstrap of DrupalKernel::boot(). - require_once DRUSH_DRUPAL_CORE . '/includes/bootstrap.inc'; - DrupalKernel::bootEnvironment(); - // Avoid 'Only variables should be passed by reference' - $root = DRUPAL_ROOT; - $site_path = DrupalKernel::findSitePath($request); - Settings::initialize($root, $site_path, $autoloader); - - // Use our error handler since _drupal_log_error() depends on an unavailable theme system (ugh). - set_error_handler('drush_error_handler'); - - // drupal_rebuild() calls drupal_flush_all_caches() itself, so we don't do it manually. - drupal_rebuild($autoloader, $request); - drush_log(dt('Cache rebuild complete.'), LogLevel::OK); - - // As this command replaces `drush cache-clear all` for Drupal 8 users, clear - // the Drush cache as well, for consistency with that behavior. - drush_cache_clear_drush(); -} - diff --git a/commands/core/drupal/cache.inc b/commands/core/drupal/cache.inc index 61b546ccf5..92b221d3ce 100644 --- a/commands/core/drupal/cache.inc +++ b/commands/core/drupal/cache.inc @@ -1,4 +1,6 @@ 'drush_cache_clear_drush', + 'drush' => ['\Drush\Commands\core\CacheCommands', 'cacheDrush'], 'all' => 'drush_cache_clear_both', ); if ($include_bootstrapped_types) { @@ -88,7 +90,7 @@ function drush_cache_clear_block() { * Clear caches internal to Drush core and Drupal. */ function drush_cache_clear_both() { - drush_cache_clear_drush(); + CacheCommands::clearDrush(); if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { drupal_flush_all_caches(); } diff --git a/commands/core/drupal/cache_8.inc b/commands/core/drupal/cache_8.inc index fca98a7167..f70d6c9e4f 100644 --- a/commands/core/drupal/cache_8.inc +++ b/commands/core/drupal/cache_8.inc @@ -27,10 +27,6 @@ function _drush_cache_command_set($cid, $data, $bin, $expire, $tags) { $bin = _drush_cache_bin_default(); } - // Convert the "expire" argument to a valid value for Drupal's cache_set(). - if ($expire == 'CACHE_TEMPORARY') { - $expire = Cache::TEMPORARY; - } if (!isset($expire) || $expire == 'CACHE_PERMANENT') { $expire = Cache::PERMANENT; } @@ -40,7 +36,7 @@ function _drush_cache_command_set($cid, $data, $bin, $expire, $tags) { function _drush_cache_clear_types($include_bootstrapped_types) { $types = array( - 'drush' => 'drush_cache_clear_drush', + 'drush' => ['\Drush\Commands\core\CacheCommands', 'cacheDrush'], ); if ($include_bootstrapped_types) { $types += array( diff --git a/commands/core/topic.drush.inc b/commands/core/topic.drush.inc index 4f87f70301..561e4eb563 100644 --- a/commands/core/topic.drush.inc +++ b/commands/core/topic.drush.inc @@ -62,7 +62,7 @@ function drush_topic_core_topic($topic_name = NULL) { } } if (empty($topics)) { - return drush_set_error('DRUSH_NO_SUCH_TOPIC', dt("No topics on !topic found.", array('!topic' => $topic_name))); + return drush_set_error('DRUSH_NO_SUCH_TOPIC', dt("!topic topic not found.", array('!topic' => $topic_name))); } if (count($topics) > 1) { // Show choice list. diff --git a/composer.lock b/composer.lock index 01fbd3cf5a..a7bdb60fb6 100644 --- a/composer.lock +++ b/composer.lock @@ -9,20 +9,20 @@ "packages": [ { "name": "consolidation/annotated-command", - "version": "2.1.3", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "6dcc442cbdc2c5145bb19e042d6b5f3979003b9f" + "reference": "2066be99905d4001b516e41feab52718614e00c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/6dcc442cbdc2c5145bb19e042d6b5f3979003b9f", - "reference": "6dcc442cbdc2c5145bb19e042d6b5f3979003b9f", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/2066be99905d4001b516e41feab52718614e00c1", + "reference": "2066be99905d4001b516e41feab52718614e00c1", "shasum": "" }, "require": { - "consolidation/output-formatters": "^3.1.3", + "consolidation/output-formatters": "^3.1.5", "php": ">=5.4.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", "psr/log": "~1", @@ -57,7 +57,7 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2016-11-19 01:02:43" + "time": "2016-11-24 00:36:49" }, { "name": "consolidation/log", @@ -108,16 +108,16 @@ }, { "name": "consolidation/output-formatters", - "version": "3.1.4", + "version": "3.1.5", "source": { "type": "git", "url": "https://github.com/consolidation/output-formatters.git", - "reference": "16c2313d755ea7e3dee72127c07f4bdb2ccf16d7" + "reference": "cc821a08b7bd89511038aa081625cb5b573960f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/16c2313d755ea7e3dee72127c07f4bdb2ccf16d7", - "reference": "16c2313d755ea7e3dee72127c07f4bdb2ccf16d7", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/cc821a08b7bd89511038aa081625cb5b573960f6", + "reference": "cc821a08b7bd89511038aa081625cb5b573960f6", "shasum": "" }, "require": { @@ -153,26 +153,26 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2016-11-21 00:56:19" + "time": "2016-11-23 23:10:13" }, { "name": "consolidation/robo", - "version": "1.0.4", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/consolidation/Robo.git", - "reference": "bfe2246358298d7839114612f84bcfdca3c14066" + "reference": "d06450370e8e303ebd1495dfc956f4c6c1b9dd01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/bfe2246358298d7839114612f84bcfdca3c14066", - "reference": "bfe2246358298d7839114612f84bcfdca3c14066", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/d06450370e8e303ebd1495dfc956f4c6c1b9dd01", + "reference": "d06450370e8e303ebd1495dfc956f4c6c1b9dd01", "shasum": "" }, "require": { - "consolidation/annotated-command": "^2.0.1", + "consolidation/annotated-command": "^2.2", "consolidation/log": "~1", - "consolidation/output-formatters": "^2.1.2|~3", + "consolidation/output-formatters": "^3.1.5", "league/container": "^2.2", "php": ">=5.5.0", "symfony/console": "~2.8|~3.0", @@ -230,7 +230,7 @@ } ], "description": "Modern task runner", - "time": "2016-11-15 19:24:36" + "time": "2016-11-24 02:07:48" }, { "name": "container-interop/container-interop", @@ -445,24 +445,24 @@ }, { "name": "nikic/php-parser", - "version": "v2.1.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0" + "reference": "adf44419c0fc014a0f191db6f89d3e55d4211744" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0", - "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/adf44419c0fc014a0f191db6f89d3e55d4211744", + "reference": "adf44419c0fc014a0f191db6f89d3e55d4211744", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.4" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.0|~5.0" }, "bin": [ "bin/php-parse" @@ -470,7 +470,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -492,7 +492,7 @@ "parser", "php" ], - "time": "2016-09-16 12:04:44" + "time": "2016-12-06 11:30:35" }, { "name": "pear/console_table", @@ -647,37 +647,38 @@ }, { "name": "psy/psysh", - "version": "v0.7.2", + "version": "v0.8.0", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280" + "reference": "4a8860e13aa68a4bbf2476c014f8a1f14f1bf991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280", - "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/4a8860e13aa68a4bbf2476c014f8a1f14f1bf991", + "reference": "4a8860e13aa68a4bbf2476c014f8a1f14f1bf991", "shasum": "" }, "require": { "dnoegel/php-xdg-base-dir": "0.1", "jakub-onderka/php-console-highlighter": "0.3.*", - "nikic/php-parser": "^1.2.1|~2.0", + "nikic/php-parser": "~1.3|~2.0|~3.0", "php": ">=5.3.9", "symfony/console": "~2.3.10|^2.4.2|~3.0", "symfony/var-dumper": "~2.7|~3.0" }, "require-dev": { - "fabpot/php-cs-fixer": "~1.5", - "phpunit/phpunit": "~3.7|~4.0|~5.0", - "squizlabs/php_codesniffer": "~2.0", + "friendsofphp/php-cs-fixer": "~1.11", + "hoa/console": "~3.16|~1.14", + "phpunit/phpunit": "~4.4|~5.0", "symfony/finder": "~2.1|~3.0" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", "ext-pdo-sqlite": "The doc command requires SQLite to work.", "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", - "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", + "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." }, "bin": [ "bin/psysh" @@ -715,7 +716,7 @@ "interactive", "shell" ], - "time": "2016-03-09 05:03:14" + "time": "2016-12-07 17:15:07" }, { "name": "sebastian/version", @@ -1347,20 +1348,20 @@ }, { "name": "webmozart/assert", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", "shasum": "" }, "require": { - "php": "^5.3.3|^7.0" + "php": "^5.3.3 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^4.6", @@ -1369,7 +1370,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1393,7 +1394,7 @@ "check", "validate" ], - "time": "2016-08-09 15:02:57" + "time": "2016-11-23 20:04:58" }, { "name": "webmozart/path-util", @@ -1499,16 +1500,16 @@ }, { "name": "phpspec/prophecy", - "version": "v1.6.1", + "version": "v1.6.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", "shasum": "" }, "require": { @@ -1516,10 +1517,11 @@ "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "sebastian/recursion-context": "^1.0|^2.0" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "phpspec/phpspec": "^2.0", + "phpunit/phpunit": "^4.8 || ^5.6.5" }, "type": "library", "extra": { @@ -1557,7 +1559,7 @@ "spy", "stub" ], - "time": "2016-06-07 08:13:47" + "time": "2016-11-21 14:58:47" }, { "name": "phpunit/php-code-coverage", @@ -1623,16 +1625,16 @@ }, { "name": "phpunit/php-file-iterator", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", "shasum": "" }, "require": { @@ -1666,7 +1668,7 @@ "filesystem", "iterator" ], - "time": "2015-06-21 13:08:43" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -1804,16 +1806,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.28", + "version": "4.8.31", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "558a3a0d28b4cb7e4a593a4fbd2220e787076225" + "reference": "98b2b39a520766bec663ff5b7ff1b729db9dbfe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/558a3a0d28b4cb7e4a593a4fbd2220e787076225", - "reference": "558a3a0d28b4cb7e4a593a4fbd2220e787076225", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/98b2b39a520766bec663ff5b7ff1b729db9dbfe3", + "reference": "98b2b39a520766bec663ff5b7ff1b729db9dbfe3", "shasum": "" }, "require": { @@ -1829,7 +1831,7 @@ "phpunit/php-text-template": "~1.2", "phpunit/php-timer": "^1.0.6", "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.1", + "sebastian/comparator": "~1.2.2", "sebastian/diff": "~1.2", "sebastian/environment": "~1.3", "sebastian/exporter": "~1.2", @@ -1872,7 +1874,7 @@ "testing", "xunit" ], - "time": "2016-11-14 06:25:28" + "time": "2016-12-09 02:45:31" }, { "name": "phpunit/phpunit-mock-objects", diff --git a/includes/annotationcommand_adapter.inc b/includes/annotationcommand_adapter.inc index dcc3707a80..ebab9326cc 100644 --- a/includes/annotationcommand_adapter.inc +++ b/includes/annotationcommand_adapter.inc @@ -404,12 +404,12 @@ function annotationcommand_adapter_get_commands_for_commandhandler($commandhandl 'description' => $commandinfo->getDescription(), 'examples' => $commandinfo->getExampleUsages(), 'bootstrap' => $bootstrap, - 'remote_tty' => $commandinfo->hasAnnotation('remote-tty'), + 'remote-tty' => $commandinfo->hasAnnotation('remote-tty'), 'handle-remote-commands' => $commandinfo->hasAnnotation('handle-remote-commands'), - 'strict_option_handling' => $commandinfo->hasAnnotation('strict-option-handling'), + 'strict-option-handling' => $commandinfo->hasAnnotation('strict-option-handling'), 'hidden' => $commandinfo->hasAnnotation('hidden'), 'aliases' => $aliases, - 'topic' => $commandinfo->hasAnnotation('topic'), + 'topic' => (bool) $commandinfo->getTopics(), 'topics' => _convert_csv_to_array($commandinfo->getAnnotation('topics')), 'add-options-to-arguments' => TRUE, 'consolidation-output-formatters' => TRUE, diff --git a/lib/Drush/Commands/core/CacheCommands.php b/lib/Drush/Commands/core/CacheCommands.php new file mode 100644 index 0000000000..21259d2df9 --- /dev/null +++ b/lib/Drush/Commands/core/CacheCommands.php @@ -0,0 +1,269 @@ + 'json']) { + drush_include_engine('drupal', 'cache'); + $result = drush_op('_drush_cache_command_get', $cid, $bin); + + if (empty($result)) { + throw new \Exception(dt('The !cid object in the !bin bin was not found.', array('!cid' => $cid, '!bin' => $bin ? $bin : _drush_cache_bin_default()))); + } + return new PropertyList($result); + } + + /** + * Clear a specific cache, or all Drupal caches. + * + * @command cache-clear + * @param $type The particular cache to clear. Omit this argument to choose from available caches. + * @option cache-clear Set to 0 to suppress normal cache clearing; the caller should then clear if needed. + * @hidden-option cache-clear + * @aliases cc + * @bootstrap DRUSH_BOOTSTRAP_MAX + * @complete \Drush\Commands\core\CacheCommands::complete + */ + public function clear($type = NULL, $options = ['cache-clear' => TRUE]) { + if (!$options['cache-clear']) { + $this->logger()->info(dt("Skipping cache-clear operation due to --cache-clear=0 option.")); + return NULL; + } + + $types = $this->getTypes(drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)); + + if (empty($type)) { + // Don't offer 'all' unless Drush has bootstrapped the Drupal site + if (!drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { + unset($types['all']); + } + $type = drush_choice($types, 'Enter a number to choose which cache to clear.', '!key'); + if (empty($type)) { + return drush_user_abort(); + } + } + + // Do it. + drush_op($types[$type]); + // @todo 'all' only applies to D7. + if ($type == 'all' && !drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { + $this->logger()->warning(dt("No Drupal site found, only 'drush' cache was cleared.")); + } + else { + $this->logger()->success(dt("'!name' cache was cleared.", array('!name' => $type))); + } + } + + /** + * Cache an object expressed in JSON or var_export() format. + * + * @command cache-set + * @param $cid The id of the object to set. + * @param $data The object to set in the cache. Use \'-\' to read the object from STDIN. + * @param $bin The cache bin to store the object in. + * @param $expire CACHE_PERMANENT, CACHE_TEMPORARY, or a Unix timestamp. + * @param $tags A comma delimited list of cache tags. + * @option input-format The format of value. Use 'json' for complex values. + * @option cache-get If the object is the result a previous fetch from the cache, only store the value in the "data" property of the object in the cache. + * @aliases cs + * @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL + */ + public function set($cid, $data, $bin = NULL, $expire = NULL, $tags = NULL, $options = ['input-format' => 'string', 'cache-get' => FALSE]) { + $tags = is_string($tags) ? _convert_csv_to_array($tags) : []; + + // In addition to prepare, this also validates. Can't easily be in own validate callback as + // reading once from STDIN empties it. + $data = $this->setPrepareData($data, $options); + if ($data === FALSE && drush_get_error()) { + // An error was logged above. + return; + } + + drush_include_engine('drupal', 'cache'); + return drush_op('_drush_cache_command_set', $cid, $data, $bin, $expire, $tags); + } + + protected function setPrepareData($data, $options) { + if ($data == '-') { + $data = file_get_contents("php://stdin"); + } + + // Now, we parse the object. + switch ($options['input-format']) { + case 'json': + $data = drush_json_decode($data); + break; + } + + if ($options['cache-get']) { + // $data might be an object. + if (is_object($data) && $data->data) { + $data = $data->data; + } + // But $data returned from `drush cache-get --format=json` will be an array. + elseif (is_array($data) && isset($data['data'])) { + $data = $data['data']; + } + else { + // If $data is neither object nor array and cache-get was specified, then + // there is a problem. + throw new \Exception(dt("'cache-get' was specified as an option, but the data is neither an object or an array.")); + } + } + + return $data; + } + + /** + * Rebuild a Drupal 8 site. + * + * This is a copy of core/rebuild.php. Additionally + * it also clears Drush cache and Drupal's render cache. + + * + * @command cache-rebuild + * @option cache-clear Set to 0 to suppress normal cache clearing; the caller should then clear if needed. + * @hidden-option cache-clear + * @aliases cr,rebuild + * @bootstrap DRUSH_BOOTSTRAP_DRUPAL_SITE + */ + public function rebuild($options = ['cache-clear' => TRUE]) { + if (!drush_get_option('cache-clear', TRUE)) { + drush_log(dt("Skipping cache-clear operation due to --cache-clear=0 option."), LogLevel::OK); + return TRUE; + } + chdir(DRUPAL_ROOT); + + // We no longer clear APC and similar caches as they are useless on CLI. + // See https://github.com/drush-ops/drush/pull/2450 + + $autoloader = drush_drupal_load_autoloader(DRUPAL_ROOT); + require_once DRUSH_DRUPAL_CORE . '/includes/utility.inc'; + + $request = Request::createFromGlobals(); + // Ensure that the HTTP method is set, which does not happen with Request::createFromGlobals(). + $request->setMethod('GET'); + // Manually resemble early bootstrap of DrupalKernel::boot(). + require_once DRUSH_DRUPAL_CORE . '/includes/bootstrap.inc'; + DrupalKernel::bootEnvironment(); + // Avoid 'Only variables should be passed by reference' + $root = DRUPAL_ROOT; + $site_path = DrupalKernel::findSitePath($request); + Settings::initialize($root, $site_path, $autoloader); + + // Use our error handler since _drupal_log_error() depends on an unavailable theme system (ugh). + set_error_handler('drush_error_handler'); + + // drupal_rebuild() calls drupal_flush_all_caches() itself, so we don't do it manually. + drupal_rebuild($autoloader, $request); + $this->logger()->success(dt('Cache rebuild complete.')); + + // As this command replaces `drush cache-clear all` for Drupal 8 users, clear + // the Drush cache as well, for consistency with that behavior. + CacheCommands::clearDrush(); + } + + /** + * A complete callback for cache-clear. + */ + function complete() { + // Bootstrap as far as possible so that Views and others can list their caches. + drush_bootstrap_max(); + return array('values' => array_keys(drush_cache_clear_types(TRUE))); + } + + /** + * @hook validate cache-clear + */ + function validate(CommandData $commandData) { + $types = $this->getTypes(drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)); + $type = $commandData->input()->getArgument('type'); + // Check if the provided type ($type) is a valid cache type. + if ($type && !array_key_exists($type, $types)) { + if ($type === 'all' && drush_drupal_major_version() >= 8) { + throw new \Exception(dt('`cache-clear all` is deprecated for Drupal 8 and later. Please use the `cache-rebuild` command instead.')); + } + // If we haven't done a full bootstrap, provide a more + // specific message with instructions to the user on + // bootstrapping a Drupal site for more options. + if (!drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) { + $all_types = $this->getTypes(TRUE); + if (array_key_exists($type, $all_types)) { + throw new \Exception(dt("'!type' cache requires a working Drupal site to operate on. Use the --root and --uri options, or a site @alias, or cd to a directory containing a Drupal settings.php file.", array('!type' => $type))); + } + else { + throw new \Exception(dt("'!type' cache is not a valid cache type. There may be more cache types available if you select a working Drupal site.", array('!type' => $type))); + } + } + throw new \Exception(dt("'!type' cache is not a valid cache type.", array('!type' => $type))); + } + } + + /** + * Types of caches available for clearing. Contrib commands can hook in their own. + */ + function getTypes($include_bootstrapped_types = FALSE) { + drush_include_engine('drupal', 'cache'); + $types = _drush_cache_clear_types($include_bootstrapped_types); + + // Include the appropriate environment engine, so callbacks can use core + // version specific cache clearing functions directly. + drush_include_engine('drupal', 'environment'); + + // Command files may customize $types as desired. + $handlers = $this->getCustomEventHandlers('cache-clear', $types, $include_bootstrapped_types); + foreach ($handlers as $handler) { + $handler($types, $include_bootstrapped_types); + } + return $types; + } + + /** + * Clear caches internal to Drush core. + */ + static function clearDrush() { + drush_cache_clear_all(NULL, 'default'); // commandfiles, etc. + drush_cache_clear_all(NULL, 'complete'); // completion + // Release XML. We don't clear tarballs since those never change. + $matches = drush_scan_directory(drush_directory_cache('download'), "/^https---updates.drupal.org-release-history/", array('.', '..')); + array_map('unlink', array_keys($matches)); + } +} \ No newline at end of file diff --git a/lib/Drush/Commands/core/CoreCommands.php b/lib/Drush/Commands/core/CoreCommands.php index ee2af2902f..d22a9f23d9 100644 --- a/lib/Drush/Commands/core/CoreCommands.php +++ b/lib/Drush/Commands/core/CoreCommands.php @@ -36,7 +36,7 @@ public function cron() { * @aliases twigc * @bootstrap DRUSH_BOOTSTRAP_DRUPAL_FULL */ - public function twig_compile() { + public function twigCompile() { require_once DRUSH_DRUPAL_CORE . "/themes/engines/twig/twig.engine"; // Scan all enabled modules and themes. // @todo refactor since \Drush\Boot\DrupalBoot::commandfile_searchpaths is similar. @@ -167,10 +167,10 @@ public function renderCell($key, $cellData, FormatterOptions $options) { * @aliases dd * @bootstrap DRUSH_BOOTSTRAP_NONE */ - public function drupal_directory($target = 'root', $options = ['component' => 'path', 'local-only' => FALSE]) { - $path = $this->drush_core_directory($target, $options['component'], $options['local-only']); + public function drupalDirectory($target = 'root', $options = ['component' => 'path', 'local-only' => FALSE]) { + $path = $this->getPath($target, $options['component'], $options['local-only']); - // If _drush_core_directory is working right, it will turn + // If getPath() is working right, it will turn // %blah into the path to the item referred to by the key 'blah'. // If there is no such key, then no replacement is done. In the // case of the dd command, we will consider it an error if @@ -197,7 +197,7 @@ public function drupal_directory($target = 'root', $options = ['component' => 'p * 'root' & 'uri' - the Drupal root and URI of the site from the path * 'path-component' - The ':' and the path */ - protected function drush_core_directory($target = 'root', $component = 'path', $local_only = FALSE) { + protected function getPath($target = 'root', $component = 'path', $local_only = FALSE) { // Normalize to a sitealias in the target. $normalized_target = $target; if (strpos($target, ':') === FALSE) { @@ -234,7 +234,7 @@ protected function drush_core_directory($target = 'root', $component = 'path', $ * description: Description * @default-fields name,description */ - public function global_options($options = ['format' => 'table', 'fields' => '', 'include-field-labels' => FALSE]) { + public function globalOptions($options = ['format' => 'table', 'fields' => '', 'include-field-labels' => FALSE]) { drush_print(dt('These options are applicable to most Drush commands. Most options can be disabled by using --no-option (i.e. --no-debug to disable --debug.)')); drush_print(); $fake = drush_global_options_command(FALSE); @@ -308,14 +308,14 @@ public function execute($options = ['escape' => TRUE]) { if (!empty($site['site-list'])) { $sites = drush_sitealias_resolve_sitelist($site); foreach ($sites as $site_name => $site_spec) { - $result = $this->drush_core_execute_cmd($site_spec, $cmd); + $result = $this->executeCmd($site_spec, $cmd); if (!$result) { break; } } } else { - $result = $this->drush_core_execute_cmd($site, $cmd); + $result = $this->executeCmd($site, $cmd); } } else { @@ -335,7 +335,7 @@ public function execute($options = ['escape' => TRUE]) { /** * Helper function for drush_core_execute: run one shell command */ - protected function drush_core_execute_cmd($site, $cmd) { + protected function executeCmd($site, $cmd) { if (!empty($site['remote-host'])) { // Remote, so execute an ssh command with a bash fragment at the end. $exec = drush_shell_proc_build($site, $cmd, TRUE); diff --git a/lib/Drush/Commands/core/ViewsCommands.php b/lib/Drush/Commands/core/ViewsCommands.php index ed340ee3e9..1f4fc66db8 100644 --- a/lib/Drush/Commands/core/ViewsCommands.php +++ b/lib/Drush/Commands/core/ViewsCommands.php @@ -319,12 +319,13 @@ static function complete() { } /** - * @todo See https://github.com/consolidation/annotated-command/issues/56 - * Implements hook_cache_clear. Adds a cache clear option for views. + * Adds a cache clear option for views. + * + * @hook on-event cache-clear */ -// function views_drush_cache_clear(&$types, $include_bootstrapped_types) { -// if ($include_bootstrapped_types && \Drupal::moduleHandler()->moduleExists('views')) { -// $types['views'] = 'views_invalidate_cache'; -// } -// } + function cacheClear(&$types, $include_bootstrapped_types) { + if ($include_bootstrapped_types && \Drupal::moduleHandler()->moduleExists('views')) { + $types['views'] = 'views_invalidate_cache'; + } + } } diff --git a/tests/cacheCommandTest.php b/tests/cacheCommandTest.php index 9aa2cb22cb..2e60117a8d 100644 --- a/tests/cacheCommandTest.php +++ b/tests/cacheCommandTest.php @@ -45,7 +45,7 @@ function testCacheSet() { $input = array('data'=> $expected); $stdin = json_encode($input); $bin = UNISH_DRUPAL_MAJOR_VERSION >= 8 ? 'default' : 'cache'; - $exec = sprintf('%s cache-set %s %s my_cache_id - %s CACHE_PERMANENT --format=json --cache-get 2>%s', UNISH_DRUSH, "--root=" . self::escapeshellarg($options['root']), '--uri=' . $options['uri'], $bin, $this->bit_bucket()); + $exec = sprintf('%s cache-set %s %s my_cache_id - %s CACHE_PERMANENT --input-format=json --cache-get 2>%s', UNISH_DRUSH, "--root=" . self::escapeshellarg($options['root']), '--uri=' . $options['uri'], $bin, $this->bit_bucket()); $return = $this->execute($exec, self::EXIT_SUCCESS, NULL, [], $stdin); $this->drush('cache-get', array('my_cache_id'), $options + array('format' => 'json')); $data = $this->getOutputFromJSON('data');